Remi on software architecture: Build today what will still work tomorrow.
Software architecture is the structural blueprint of an application: how components are organized, how they communicate with each other, and how the system handles growth. A well-thought-out architecture ensures that your software will still be flexible and adaptable five years from now.
What is software architecture?
The first question we ask ourselves when starting a new project is never: “Which framework should we use?” We always start by asking: “What should this system look like in five years?” That is exactly what software architecture is all about.
Definition and scope.
Software architecture refers to the set of fundamental decisions regarding the structure of a software system: what components are included, how are they organized, how do they communicate with each other, and how does the system handle scalability, security, and maintainability?
You make those choices early on in the process. And that’s exactly why they’re so valuable: they set the direction for everything that follows.
The difference from software design.
Architecture and design operate on different levels. Architecture focuses on the big picture: how the system is structured, what layers it consists of, and how subsystems communicate. Design focuses on the details of those components: classes, interfaces, and patterns within a module. We see it this way: good architecture lays the foundation on which good design can thrive. When that foundation is solid, developers have the freedom to do truly excellent work.
Why architectural decisions matter early on.
Poor architectural choices accumulate as technical debt: the hidden debt that arises when earlier decisions later result in greater complexity than anticipated. You rarely pay off that debt all at once. The costs are reflected in the time a developer needs to build a new feature without breaking existing code. In the reluctance to touch certain parts of the codebase. In releases that are nerve-wracking rather than routine.
The great thing is: once you recognize those patterns, you can start addressing them in a targeted way. It starts with mapping out the architecture.
When architecture demands attention.
Does this sound familiar?
New features take a disproportionate amount of time
Bug fixes create new bugs
Onboarding time for new developers is increasing
Every release feels like a major event
Then there’s a good chance it’s an architectural issue. And that’s a solvable problem.
Three levels of architectural choices.
Architectural choices aren’t just a simple list of patterns from which you pick one. They follow three logical levels, which you go through in that order: first you design the landscape, then the application itself, and only then the underlying infrastructure. If you reverse that order, you’re building on a foundation you don’t yet know.
Level 1: Landscape design.
The first question is the most important one: what does the entire system look like? How many applications are there, how do they relate to one another, and how do they scale?
Monolithic architecture: the power of simplicity.
A monolith is an application in which all functionality is contained within a single codebase and deployed as a single unit. It has an undeservedly bad reputation. A monolith is easy to understand, easy to debug, and easy to deploy. For small teams and products in the early stages, it is almost always the right choice. Less overhead, more speed, less coordination.
We are strong advocates of starting with a monolithic architecture. Not out of laziness, but because you only need the complexity of microservices once your system is large enough to actually benefit from them.
SOA and the modular monolith: the intermediate step that is often skipped.
Between the monolith and microservices lies an important intermediate step that is often overlooked: the modular monolith. SOA (Service-Oriented Architecture) is a related but broader approach, in which services communicate over a network and run independently of one another. A modular monolith is a single deployable unit that is internally divided into modules. The distinction lies in deployment: with SOA, services are already separate; with a modular monolith, they are not yet.
The principle: a single codebase, but internally divided into logical, self-contained modules with clear boundaries. Each module has its own responsibilities and communicates with other modules via a defined interface, rather than through direct dependencies across the codebase.
That distinction is valuable. As the system grows and the need for independent scalability or deployment increases, individual modules can be separated and deployed as standalone services. This makes the transition to microservices a controlled step, rather than a complete rewrite.
Microservices: scalability versus complexity.
In a microservices architecture, the application is divided into small, independent services, each of which has a single responsibility. They communicate via APIs or a message bus—a system that delivers messages between services, such as RabbitMQ or Kafka.
The main advantage: services can be scaled, deployed, and replaced independently. The downside: operational complexity increases significantly. Microservices are the right choice if you have large teams that want to deploy independently of one another, or if different components have vastly different scaling requirements.
Martin Fowler, an authority on software architecture, refactoring, and microservices, puts it this way in his article *MonolithFirst*: don’t start a new project with microservices, even if you expect the system to grow large enough to ever benefit from them. Almost every successful microservices system started out as a monolith. We fully endorse this wisdom.
Level 2: the application's design.
Once the architecture is in place, we’ll examine how the application itself works internally. How do components interact with one another? How does information flow through the system?
Event-driven architectuur.
In an event-driven system, components respond to events rather than direct calls. Imagine this: a placed order triggers an event. The inventory module, the email service, and the billing component each respond to that event independently of one another.
Strength: loose coupling between components. This makes the system flexible and easily scalable. The challenge lies in determining the state of the system at any given moment. Event-driven architecture is well-suited for systems with high throughput, asynchronous processing, and multiple independent consumers of the same data.
Level 3: the infrastructure.
Only after the landscape and the application are in place do we consider how and where to run them. Infrastructure choices stem from earlier architectural choices, not the other way around.
Hosting: shared or dedicated environment.
The most straightforward infrastructure choice is often also the most practical: should the platform run on a shared server or on its own VPS (Virtual Private Server)? A shared environment is cheaper and easier to manage. A dedicated VPS offers more control, better isolation, and more predictable performance under load.
At Cube, we adhere to strict environment isolation as standard practice. Exactly what this isolation entails varies by platform: sometimes logical isolation within a shared server is sufficient, while other times physical isolation is necessary. We make this determination based on the system’s security and availability requirements.
Serverless en cloud-native.
Serverless doesn’t mean there are no servers, but rather that you don’t manage your own servers. Functionality is deployed as individual functions that scale based on usage. Cloud-native is a broader term for architectures that make optimal use of cloud infrastructure: containers such as Docker, orchestration such as Kubernetes, and managed services.
Both approaches offer interesting possibilities, especially for systems with highly variable workloads. Which option is best depends on the choices already made in levels one and two. You can read more about how we set up hosting and infrastructure on our hosting & infrastructure page.
How do you choose the right pattern?
There is no single best architectural approach. Certain choices are appropriate for specific contexts. We always make those choices based on four factors.
Team size: Small teams work more efficiently with a monolith. Larger teams benefit from the independence of microservices, but also pay the coordination cost.
Expected scale: Do you already know that your system needs to handle hundreds of thousands of concurrent users? Then a cloud-native or microservices approach has advantages. Don’t know yet? Then anticipating scaling issues that may never arise is a waste of your budget.
Speed to market: a monolith is faster to build. If time-to-market is critical, that’s a major consideration.
Budget: microservices and serverless require more infrastructure expertise and DevOps effort. That always translates to costs.
The role of the software architect in a project.
A software architect isn’t someone who just draws up plans and then steps back. At Cube, the architect is actively involved in development: reviewing code, brainstorming with the team, and making adjustments where necessary. What we do as architects: ensure the consistency of technical choices across the entire system, translate functional requirements into technical architecture, anticipate scalability issues before they become apparent, and monitor the limits of the technical debt the system carries.
What we deliberately avoid doing: dictating every implementation detail. Good architecture creates a framework within which developers can do their best work. Not a straitjacket, but a solid foundation.
How we make architectural decisions at Cube.
We don’t follow architectural trends. We choose what works best for the problem, the team, and the timeline. What we always do: document the architecture. This ensures that every future team member understands why certain choices were made—not just what the system does, but why it was designed that way. This saves months of onboarding and prevents valuable context from being lost.
We also conduct code reviews and technical architecture assessments for existing systems where the architecture has become a barrier to growth. Sometimes the conclusion is that repairs are needed. Sometimes that it needs to be rebuilt. Always honest, always with a concrete plan.
Curious to know how your architecture is doing?
Curious about the state of your architecture? Remi would be happy to help. No sales pitch—just a good conversation about your situation.
Worth reading next...
What is a middleware solution and how are APIs and webhooks used for this?
How can an organization utilise AI without losing control of its data?
How AI can increase software quality in the hands of experts.
Questions? No problem.
Software architecture is the structural blueprint of an application: the decisions about how components are divided, how they communicate, and how the system handles growth and maintainability. These are the early, fundamental choices that guide everything that follows.
A software architect translates functional and non-functional requirements into a technical structure, ensures consistency of decisions across the entire system, and anticipates scaling challenges before they arise. At Cube, the architect is actively involved in development, not just in the design phase.
As soon as your system is large enough that a single developer can no longer maintain a complete overview, and at the start of any new system where early decisions are costly to change later. That point comes sooner than most teams expect.
A modular monolith is an application in a single codebase, but internally divided into logical, self-contained modules with clear boundaries. It combines the simplicity of a monolith with the structure that enables growth towards microservices without a full rewrite.
A monolith is a single codebase that functions and is deployed as one unit. Microservices are small, independent services each with a single responsibility. A monolith is simpler and faster to build; microservices offer more independence when scaling but require more operational expertise. A modular monolith is often a good intermediate step.