Week 14

Architecture Patterns

Communication Patterns

Background Processing

Architectural Trade-offs

Messaging

Hands-on: RabbitMQ

Practice

Assignment

Backend Track

Introduction

For thirteen weeks you have been building backends the same way: one Spring Boot application, one codebase, one PostgreSQL database. This week we zoom out and ask a bigger question: how should a whole system be organised? That is what system architecture means — how a system is split into parts, and how those parts work together.

There is no single "best" architecture, only trade-offs. This chapter introduces the three shapes you will hear about in every backend team: the monolith, the modular monolith, and microservices.

Watch: Microservices explained - the What, Why and How?

<aside> 💭

Watch the first 9:24 minutes of following video. Stop at the at end of the “Downsides of Microservices” chapter, just when mentioning Kubernetes.

</aside>

https://www.youtube.com/watch?v=rv4LlmLmVWk

The monolith

A monolith is an application built as one deployable unit: one codebase, one build, one running process, and usually one database.

flowchart LR
    Browser ==> App["Spring Boot application<br/>controllers + services + repositories"]
    App ==> DB[(PostgreSQL)]
    style App fill:#eaf8ed,stroke:#2f9e44,stroke-width:1.5px,color:#123
Advantages Disadvantages
One thing to build, test, run, debug and deploy The codebase grows large and harder to navigate
Calling other code is just a method call — fast and reliable You must scale the whole application, even if only one feature is busy
One database — simple, consistent transactions Many teams working in one codebase step on each other
Easy to run locally One serious bug can bring everything down; every deploy redeploys everything

<aside> 💡

The monolith is the right default. Most successful products started as monoliths, and some very large ones (Shopify, Stack Overflow) still are.

</aside>

💬 Is the REST API you built in this track a monolith?

The modular monolith

A modular monolith is still one deployable unit, but the code inside is organised into clear modules with small public interfaces between them — in Java, typically one package per business area (users, orders, billing) where other modules only call a few public classes.

<aside> 💡

Good package boundaries cost nothing today and buy you an option for later: if one module ever needs to become a separate service, the seam already exists.

</aside>

Microservices

Microservices split a system into several independently deployable services. Each service owns its own database and the services communicate over the network.

flowchart LR
    Browser ==> Users["users-service"]
    Browser ==> Orders["orders-service"]
    Orders -- HTTP --> Users
    Users ==> UDB[(users db)]
    Orders ==> ODB[(orders db)]
    style Users fill:#e8f3ff,stroke:#2f80ed,color:#123
    style Orders fill:#f3edff,stroke:#7950f2,color:#123

Teams consider microservices when: many teams need to deploy independently without waiting for each other, different parts of the system have very different scaling needs, or parts need different technology.

Why not to start with them: every arrow in the diagram is now a network call that can fail or be slow; debugging spans several machines and logs; data is spread over several databases, so keeping it consistent is genuinely hard; and you now operate, deploy and monitor N applications instead of one.

<aside> ⚠️

A distributed system is not "a monolith, but better". It trades code complexity for operational complexity. Teams that split too early pay all the costs before seeing any of the benefits.

</aside>

Choosing: the trade-offs

The progression most systems follow: monolith → modular monolith → (maybe) microservices — splitting only when there is a concrete reason.

Monolith Microservices
Deployment One unit Many independent units
Data One database, easy consistency Database per service, consistency is hard
Failure One process fails → everything is down One service can fail alone, but partial failures are confusing
Debugging One log, one stack trace A request crosses several services and logs
Fits best Small teams, most products Many teams, very large scale

<aside> 💡

"Monolith or microservices?" is a favourite junior interview question. A strong answer: "I would start with a well-structured monolith and split out services only when there is a concrete reason, like team size or scaling. Microservices trade code complexity for operational complexity." That answer sounds more senior than any list of buzzwords.

</aside>

Summary

Architecture is about how a system is split and how the parts talk. The monolith is the right default; the modular monolith keeps it tidy as it grows; microservices solve problems of scale — of teams as much as of traffic — at a real operational cost. In the next chapter you will look at how the parts of a system communicate with each other.

Bonus video: “Microservices”

The following video is a classic. It shows in a humorous way how complex a microservice architecture can be in larger companies. Due to the complexity, simple features can take a very long time to be built.

https://www.youtube.com/watch?v=y8OnoxKotPQ

Extra resources


The HackYourFuture curriculum is licensed under CC BY-NC-SA 4.0 *https://hackyourfuture.net/*

CC BY-NC-SA 4.0 Icons

Built with ❤️ by the HackYourFuture community · Thank you, contributors

Found a mistake or have a suggestion? Let us know in the feedback form.