Changeability in Software Architectures
Changeability in Software Architectures
One common theme popping up in projects is that change is the only constant. Code changes, architecture changes, technology changes, requirements change and people change. But often, change comes at a high cost. Things were just not prepared for change because doing so would have imposed the costs earlier on. But really the same costs? To reduce costs in the long run, wouldn’t it be beneficial to spend some effort in changeability upfront? Of course, but it is difficult to find the sweet spot between spending enough and too much effort to properly implement changeability.
I have recently stumbled upon a paper by Ernst Fricke and Armin Schulz called “Design for changeability (DfC): Principles to enable changes in systems throughout their entire lifecycle” which distils some great food for thought. The approach distinguishes four aspects of changeability:
- Robustness: the system is insensitive to a change in the surrounding environment.
- Flexibility: the system can easily be changed.
- Agility: the system can rapidly be changed.
- Adaptability: the system adapts itself to changing operating conditions.
When improving changeability, any of the four aspects can be improved. To have a guideline on how much to improve changeability the authors provide a simple chart:
The horizontal axis represents the degree of changeability of a system. A low changeability means a high cost to change the system, but a low cost to implement changeability. On the opposite side, a system with a high degree of changeability has a low cost to change the system, but a high cost to further improve upon its changeability. The interesting part is that the total costs of the system are the sum of the two curves and have a sweet spot somewhere in the middle. Now you might think this is totally obvious, but take a step back from your latest project and have a look at the following examples:
Low-cost changeability
The following non-exhaustive list compiles some low-effort practices and principles that I came across in a lot of projects. In your projects you should be using all of the aspects unless you have a very good reason not to. Paying attention to them will definitely pay off in the future!
- Configuration: Most systems have some sort of configuration options. Even a small script has configuration options. Especially true for small scripts and throw-away prototypes that suddenly grow, the configuration is often hard-coded to a specific environment and changing later is a PITA. Most frameworks provide easy ways to provide configuration options, leverage them!
- Magic numbers and strings: Now seriously, constants can so easily be defined. Just do it. Sooner or later you will have to refactor.
- Facades and interfaces: Hide complexity and restrict the information provided. If you want to extract an interface from a class being used throughout the entire application you will most likely find usages of methods that you did not want to appear in the extracted interface. Defining and using an interface takes just a couple of minutes. Of course, a good interface takes some time, but starting with an interface allows you to properly refactor later.
- Naming and documentation: Just take your time to properly name and document the things you write. It is not a lot of effort while you have all the code in your mind, but dare not to return to your undocumented code months later. And remember, naming is one of the hardest things!
- Dependency management: Every modern programming language has some kind of system to manage dependencies such as required libraries. Learn to leverage those dependency management apps. Don’t start to manually fiddle around.
- Frameworks: Don’t reinvent the wheel. If you write less code by using a framework, you have to change less code in case you need to.
High-cost changeability
When defining a system architecture, you have to make lots of important decisions. There are also some practices and principles you can leverage in your system to obtain a high degree of changeability. However, make sure to thoroughly estimate the return on investment for these decisions!
- Domain-driven design: The art of building huge and complex systems that are easy to change. DDD emphasizes the proper modeling of the actual domain entities and interactions. Changes in the domain can then trickle all the way down to the supporting infrastructure.
- Object-relational mappers: ORM libraries provide a huge level of abstraction over your database. Your schema and your queries can easily change or even be automatically ported to other platforms. However, ORMs also have a number of drawbacks that carefully need to be considered to maximize their potential.
- Messaging: Distributed systems can have various different messaging patterns. While applying a messaging pattern can greatly improve the changeability and robustness of a system, it also opens a whole lot of issues that need to be dealt with, such as consistency, availability and partition-tolerance (CAP theorem).
Conclusion
Changeability is an important aspect of all systems you develop in your day-to-day business. Keeping an eye on changeability does not only save you money and effort in the long run, but also helps you to estimate and meet deadlines and relentlessly adapt to changing market conditions. Do you have additional low- or high-cost principles you consider when designing/implementing systems for changeability?