A software architect who doesn’t care about what his system is supposed to do isn’t worth his salt. For the term “software architect” to hold any meaning at all, it must be to describe someone who understands what the customer needs and designs a system that is fit for this purpose.
Sometimes, however, people talk about “technical architects”. I have myself been guilty of falling into this category once or twice myself. The fallacy of the “technical software architect” is that there is a large number of solutions that will work independent of what problem the customer have.
This is ludicrous. The very meaning of architecture is to apply technology to a context. Leave out the context, and you have no basis to choose a technology.
This is not to say that you don’t need experts within technologies and design strategies used in the solution. If the customer wants to connect a number of old and new systems into a shared portal, an Enterprise Service Bus (or a Data Warehouse!) may be a good solution. And then you will need people who are experts on the technology in question.
However, I would not call such an expert an architect. If you’re really good in some technology, I have no problem calling you a freaking good developer. Heck, you can even put that on your business card. Just don’t think you’re an architect.
If you want to release your code frequently, you have to automate the release process. If your software interacts with shared components or other applications, the release script may have to update shared configuration files. In this blog post, I recall when I solved this with a
If you want to release frequently, a problem you may encounter is that some features, even though functionally complete, don’t stand well on their own, but require other features to be valuable to the user. If you want to release the system in this state, you need a way to hide features. A Feature-on/off-switch is a simple idea for dealing with this.
A feature-on/off-switch is some mechanism to hide features from a system. A feature-on/off-switch must be able to remove menu items concerning the feature and also to prevent adventuresome users from accessing the feature. It may be as crude as commenting out code (not recommended!), to enabling the feature based on a complex set of conditions (also not recommended).
I’ve encountered features switches triggered by the following mechanisms:
- A configuration file or configuration database table tells the system whether to turn the feature on or off.
- The feature is turned on for users that have a specific role (typically something like BETA_TESTER)
- The feature is turned on when the system is deployed as /foo-preview, but not when the system is deployed as /foo
- The feature is turned on after a specific date. This may seem weird, but was a potential solution when we were waiting for a release of another system and operations-freeze during summer was in effect.
There are probably many more conditions you may use to trigger a feature-on/off-switch. Maybe some of my readers have good examples?
As a general observation, it seems that when software architects try to solve general problems, they come up with horrible designs; when they solve specific problems, they come up with good designs.
Designs made without reference to a problem often become complex and not very fit for purpose when we’re solving specific problems. As a general rule, avoid generalizations.
- An Enterprise Service Bus may create a big project and maintainable needs for something that turns out to be only a few simple integration points.
- Splitting a system into generic reusable services may make it harder to understand and maintain
- A generalized security role model may make be hard to understand while the only thing the system needed was an “is_admin?” toggle.
- A complex role based (“can create payment”) security model may hide control of authorization from the developers, making it harder to implement the usually more important data based (“can access account number 5″) security model
- A general model for workflow transition may make it harder to implement the specific workflow you need for a particular process. And it leads to endless discussions about the relationship between a workflow, a process and a process step.
- Generalized test strategies are often vague and require a large number of test environments. In the end, it doesn’t contribute to increased quality.
In “No Silver Bullet”, Fred Brooks introduces the concepts of “essential complexity” and “accidental complexity.” The complexity from generalization is always “accidental” (that is: not inherently necessary). When you focus on solving the essential complexity (that is: the users’ problem) as efficiently as possible, you may found the complexity of your problem shrink by half or more.
Have you ever found yourself thinking, “what specific problem was I trying to solve again”? Then you’ve probably been down the dark road of generic thinking.
When developing a system that people use in their day to day work, I often meet the following requirement: “A user should be able to see all tasks from each functional area on a single screen.” This requirement requires integration with all parts of the system, making it architecturally costly. Luckily, the requirement might often not be needed at all!
Everyone will tell you: The most powerful technique for dealing with a large problem is breaking it up in smaller problems. But we often end up breaking the problem in such a way that the parts will have to talk with each other. And in software development, integration is expensive and bug ridden. So I want to avoid it.
There are some areas that tempt me to integrate the parts more tightly:
- I might want to share information about customers. This is usually a fairly benign integration point, as it’s read only.
- I might want to reuse a service that looks similar to what I need. In a larger ecosystem, this often creates more noise, as other users of the service may be affected by any changes I need to make.
- And there might be places where a user may want to see information from several systems. The most common one is the “unified task list”. This often result in each system having to let go of the life-cycle of it’s own processes, which may increase complexity a lot.
Of these, “unified task list” is the one that’s at the same time most costly and most related to real requirements. While rejecting list can potentially make the project a bit more expensive, rejecting a unified task list means you’re not delivering what the user asked for.
Or did the user really ask for a unified task list? On my last project, we ended up having separate task lists for separate types of tasks. The users were indifferent about unifying these. As a matter of fact, we got the following responses from our user panel:
- In one user’s organization, they only process forestry subsidies every few months, because there are so few and we want to see the total subsidy expenditure
- In another user’s organization, the process the same tasks every month, because there’s a lot more activity.
- In almost all the organizations, the person dealing with forestry subsidies is another person than the person dealing with road subsidies. They have their expertize in different areas, know the external parties for their separate fields and want their separate tasks lists for their jobs
Do you have a requirement for a “unified task list” in your project? Are you really sure the users really need it?