Why Polylith?

Last updated 2 months ago

Polylith is our attempt at getting closer to development nirvana.

Why a new architecture?

Polylith was born out of our frustration with the high levels of incidental complexity and development friction that we experienced with existing software architectures.

We wanted an architecture that gave our codebase an understandable, maintainable, reusable, and testable structure. We wanted a first-class development experience for navigating and refactoring of all our code, and fast feedback when we made changes. We wanted to build scalable systems, but avoid unnecessary complexity from "premature distribution".

We wanted to make it simple, fast and fun to build systems of any size.

In short, we were looking for development nirvana.

Can current architectures be improved?

We'll describe our development and production experiences with three mainstream software architectures. But we'll start by defining our terms:

Software architecture:

  • The high level structures of a software system

  • Fundamental structural choices, which are costly to change once implemented

Monolith:

  • A software architecture where the code is stored in a single codebase and deployed as a single artefact

Microservices:

  • 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

Serverless:

  • A software architecture based on a cloud-computing execution model

  • The cloud provider dynamically manages the allocation of machine resources

Development experience

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.

Production experience

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.

So what's missing?

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, 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.