Your system architecture says many things about you; often it says you didn’t design it, or that you decided to follow the crowd, in the best cases it says you know what your needs are and have designed accordingly. There are many opinions about what good architecture looks like and depending on your situation there is likely to be an architecture that better suits your needs. When designing from scratch you have the freedom to design the best possible architecture.
Brownfield applications are a little different. Any system that has withstood more than a few years of operation should be celebrated; it has demonstrated its ability to do what it needed to do. Unfortunately, a system that’s been running for several years probably also shows its age and probably doesn’t look exactly as it would if you were to design it today. Some of the decisions might have been bad ones, but mostly they’ll have been the right decision at the time and need re-visiting to bring them up to date.
So how do you re-architect a system? My preferred way is to do it gradually.
As tempting as it is to stop working on features in order to rebuild part of a system, or even to build an entirely new system to replace the one that went wrong, this probably isn’t the best decision. Stopping ‘normal’ work to focus on rebuilding can help kickstart a tech-debt paydown project but it misses the opportunity to teach teams how to make incremental improvements alongside their regular work. Without these skills or discipline the ‘new’ system is likely to end up in the same poorly architected state within a few years.
By gradually reviewing and replacing or removing parts of an old system you can turn a poorly architected system into something that exactly meets you needs. Focusing on the areas that cause the most pain, or are most frequently changed is a great way to start. By gradually removing dependencies, or bringing in new tools or technologies the system will start to improve. For many teams the best end state isn’t a complete re-design for 100% of the system but a more pragmatic approach to deal with the greatest pain points and isolate the infrequently changed areas.
But the work doesn’t stop here, system architecture is a constantly evolving being. Every day that you add or remove code you’re changing your architecture. When you decide to add or remove a dependency you’re changing your architecture. Even the decision not to change something is a decision on how your system architecture should be.
Many teams look to successful companies to decide on the right architecture for them. This may work but it ignores the unique team and problem that you have. Knowing what you value, and knowing where you need to be are essential for designing a great architecture. If you value team autonomy then make sure the system architecture supports this. If you value throughput, or robustness, or ease of learning then take the time to understand exactly how your architecture will support this. Create shared values for the end state to remove the need for day to day decision approval and instead allow everyone to focus their efforts on analysis, education, and progress.
When building new features teams should be working to move the architecture forwards at the same time as meeting their delivery goals. Sometimes that means a small change to a message, sometimes it means building a whole new microservice. Making this work means that every team needs to know exactly what their current architecture looks like, and also needs an opinion on what a better design would be. Regularly gathering around a whiteboard to discuss system design helps normalise design discussions and builds awareness of the pros and cons of every decision.
Make time to build the architecture forwards by building awareness of the current situation and its impact. Help everyone to understand what needs to change and why. When estimating work factor in the time and cost of building it the right way, the way that allows you to get the feature you want AND the architecture you want.
A system that is under active development will never have a textbook perfect architecture for long because it isn’t a static being. Systems needs to evolve to support new decisions and ideas. So whether you have a monolith or services, microservices or mono-repos, the only thing that really determines how good your architecture is is whether you know it well enough to work with it.