Let's have a quick look at some of the mainstream software architectures before we compare them to Polylith later on.
We'll describe our development and production experiences with three mainstream software architectures. But we'll start by defining our terms:
- The high-level structures of a software system
- Fundamental structural choices, which are costly to change once implemented
- A software architecture where the code is stored in a single codebase and deployed as a single artefact
- A software architecture consisting of small and independently deployable services
- Each service runs in a separate process and communicates with the others across a network
- A software architecture based on a cloud-computing execution model
- The cloud provider dynamically manages the allocation of machine resources
The traffic lights are a rough summary of our personal experiences. Please take them as our subjective opinions, not as objective truths.
We split the ratings into "small" and "large", because building larger and more complex systems usually gave us a different experience.
Our subjective development experiences
Monoliths keep all their code in one place, which gives a friction-free development experience for code navigation, refactoring, debugging, code reuse, and testability. However, as Monoliths grow, they trend towards "big balls of mud", which become very difficult to maintain.
Working with a single Microservice is great, as it gives us the same benefits as working with a small Monolith. However, the more Microservices we maintain, the worse our development experience becomes. That's because each new service boundary increases the friction for code navigation, refactoring, debugging, code reuse, and testing.
Serverless architecture is inherently modular and functional, which gives significant advantages for simplicity and testability. However, the distributed nature of its code execution has a negative impact on our code reusability, debugging and testing.
Our subjective production experiences
Monolith's one artefact approach keeps operation costs low and simplifies deployment, but makes horizontal scalability difficult.
Microservices' distributed approach gives excellent scalability and robustness, but makes deployment complex and hosting expensive.
Serverless' "outsourcing" approach gives excellent scalability, reduces our ownership of deployment complexity, and keeps server costs in-line with our usage, but also gives us an air-tight vendor lock-in.
These architectures give us plenty of guidance on how to deploy our systems, but very little guidance on how to structure our code within each system. Over the years, we've tried many different approaches to improve our systems' internal structures (e.g. DCI, DDD, Design Patterns, SOA, SOLID, Hexagon, etc.), but none of them took us all the way to development nirvana.
To get there, we realised we needed to roll up our sleeves and invent a whole new approach.