A cure for complexity in software development
- 06 December, 2021 22:45
I recently read Scott Carey’s great InfoWorld article that focuses on application complexity as an agent for reducing developer productivity and livelihood.
The article has some great ideas, including focusing on reining in complexity by using standardised third-party services and other techniques. This is a strategy that I agree has value to many organisations.
However, the article also states that microservice architectures are more complex than the equivalently functional application in a monolithic architecture, and uses this in furthering the cause that “complexity kills.” I disagree with this assessment.
The implied message I take from this point of view is that microservice architectures create complexity that reduces developer efficiency. This is not true. Microservice architectures do create an overall more complex application than an equivalent application built as a monolith -- but this does not mean that the job of the developer or the architect is more complex as a result.
Microservice architecture complexity
Many companies have built large monolithic applications only to find that they get weighed down in complexity. Too many developers working in a single code base makes it difficult to independently add features and fix defects. This limits the number of simultaneous projects that developers can work on in a single application.
Additionally, individual projects make changes that may have a broad impact on the code base -- an impact that becomes more difficult to understand when the application becomes larger and more complex. Together, these issues lead to more defects, lower quality, and increased technical debt as the complexity continues to rise.
When you split an application into separate modules or parts, you are attempting to divide that complexity in order to reduce the number of developers who need to work in a single code base.
Additionally, you reduce the breadth of the impact of your changes. This tends to create more stable code, more supportable code, less technical debt, and higher overall application quality and developer productivity.
Improving application quality and stability and improving developer productivity also lead to an improved developer experience, thus reducing fatigue, burnout, and ultimately turnover among the development team.
There are many ways to modularise an application, some more effective than others. The best model for application modularisation is to use a microservice-based application architecture.
Combining a microservice architecture with a solid model for organising your development teams and their ownership and responsibility, you end up with an organisation where individual developers can focus their attention on a smaller codebase. These developers end up being more efficient and productive, and create higher-quality code with less technical debt. These developers experience higher job satisfaction and less burnout.
The application as a whole may be more complex, but the individual piece that a single developer must focus on is substantially less complex. Thus the microservice model improves the developer’s experience.
Not all microservices are equally micro
However, simply moving to a service- or microservice-based architecture doesn’t give you this advantage automatically. Rather, you have to architect your application rationally and organise your teams appropriately. There are two things you need to watch out for in particular: service sizing and team organisation.
The size of your services has a big impact on the complexity for developers. If you size your services too small, your application ends up with a very large number of interconnected services. This interservice connectivity increases inherent complexity significantly. Your application as a whole becomes more complex. Your developers see this complexity and have to deal with it, defeating the purpose of moving to services in the first place.
If you size your services too large, then you lose the advantages that microservice architectures offer. Your services become mini-monoliths, with all the complexity disadvantages of larger monoliths.
Once again, individual developers have to deal with increased complexity, and you’ve simply moved to multiple complex applications rather than a single complex application. These mini-monoliths may ease the developer’s complexity burden in the short term, but not in the long term.
Only when you size your services appropriately do you achieve the correct balance that effectively decreases your individual developer’s complexity and cognitive load.
Team size, structure, ownership responsibilities, and lines of influence are just as critical in building your application as the code itself. In order to handle a service architecture efficiently, you must organise your development teams around your application architect appropriately. Additionally, your teams must be given the responsibility, authority, ownership, and support needed to provide complete management of their owned services.
Failure to provide this organisation and support will add a different type of complexity that is just as destructive to your organisation. Team organisation -- along with appropriate team assignments and setting responsibilities and ownership -- is critical in reducing the cognitive load of the application for the individual developers.
I recommend the standard STOSA organisational model, which describes a model for creating your organisation and assigning team-level responsibilities in a service-based application architecture. I cover the STOSA model extensively in my O’Reilly Media book, Architecting for Scale.
Tooling to reduce coding complexity
Going back to my colleague’s original article, which focuses on reducing complexity for developers, there are other techniques you can use to accomplish this as well, beyond leveraging microservice architectures and STOSA organisations.
One technological direction that will have huge benefits for reducing developer complexity in the future is software-assisted development. This is the ability to use tools, often assisted by artificial intelligence (AI) and machine learning techniques, to help the developer write code, diagnose problems in code, and manage overall code complexity.
There are many companies focusing on software-assisted development tools for programmers. GitHub’s Copilot AI assistant for Visual Studio Code uses AI to help developers write more reliable code with fewer defects.
Performance monitoring companies such as Datadog and New Relic recently announced tools that provide higher-end support for developers to diagnose problems within their code. Finally, no-code and low-code tools such as OutSystems’ App Development Platform provide higher-level service creation assistance that reduces the cognitive load needed to build and deploy individual services and applications.
Application complexity is an issue that most organisations need to deal with, and how you deal with it will impact the future of your application, the health and stability of your development organisation, and the future of your business. But there are many ways to deal with application complexity.
The approaches Scott Carey discusses, which include building an internal platform and standardising on external services across your organisation, are great strategies.
But also give serious consideration to microservice architectures. While microservices may increase your overall application complexity, they provide value in decreasing the cognitive load and visible complexity to individual developers. This will lead to higher-quality code, greater availability, lower technical debt, and improved developer morale.