Welcome to another Sunday article where we discuss System Design.
This is the first article in the series where I recommend the reader to read the previous article — Template for System Design Using ‘The Method’.
Here are the rules we've already summarized. I keep repeating: we will learn the rules, follow the rules, and once we are good at it, only then will we bend the rules.
- Avoid functional decomposition (what we were doing in universities), and remember: a good system design speaks — through how components interact.
- The client should not be the core business. Let the client be the client — not the system.
- Decompose based on volatility — list the areas of volatility.
- There is rarely a one-to-one mapping between a volatility area and a component.
- List the requirements, then identify the volatilities using both axes: — What can change for existing customers over time? — Keeping time constant, what differs across customers? (Remember: these axes are independent.)
- Verify whether a solution/component is masquerading as a requirement. Verify it is not variability. A volatility is not something that can be handled with if-else; that’s variability.
-
Use the layered approach and proper naming convention:
- Names should be descriptive and avoid atomic business verbs.
- Use
<NounOfVolatility>Manager
,<Gerund>Engine
,<NounOfResource>Access
. - Atomic verbs should only be used for operation names, not service names.
Now we will discuss some more aspects of the template and update the rules.
Four Questions
The layers given in the template should correspond to four questions:
- Client: Who interacts with the system
- Managers: What is required of the system
- Engines: How the system performs the business logic
- ResourceAccess: How the system accesses the resources
- Resource: Where the system state is stored
These questions can be asked both before initiating the design and while validating the design.
At the beginning, asking “what” helps list potential candidates for Managers. But remember, components need not be perfect.
Once done with the design, ask the questions again for validation:
Are all your Clients “who,” with no trace of “what”?
Are all the Managers “what,” without a smidgen of “who” or “where”?
Again, the mapping of questions to layers will not be perfect. Some overlap may occur. However, if you're confident that the encapsulation of volatility is justified, there's no need to doubt that choice. If you're not convinced, the questions may indicate a red flag — a signal to revisit your decomposition.
The Golden Ratio
In the book Righting Software by Juval Löwy, he shares observations from years of experience as a successful architect. I follow the same ratios as a source of truth for validations:
- 1 Manager → 0 or 1 Engine
- 2 Managers → 1 Engine
- 3 Managers → 2 Engines
- 5 Managers → 3 Engines
- 8 Managers → A lot! You've likely failed to decompose volatility. Redesign.
Volatility Decreases Top-Down, Reuse Increases
Clients are more volatile than Managers. Engines are less volatile than Managers, and so on. A design in which volatility decreases down the layers is extremely valuable. Components in the lower layers often have more dependencies. If the components you depend on the most are also the most volatile, your system will implode.
Reuse of services increases from top to bottom. Clients are hardly reusable. Managers are somewhat reusable — e.g., via both phone and web clients. Engines are even more reusable, as different use cases might share core logic.
Services and Subsystems
Group services by use case and divide them into slices. A slice is a subsystem. You'll get a deeper understanding in the next article, where I'll walk through an example.
Make sure you don't have more than 3 Managers in a subsystem.
Developing a system like this can be done one slice/subsystem at a time.
Design iteratively, build incrementally.
A component inside a subsystem cannot be released independently — it won't cover a complete use case. So release one subsystem at a time during development.
Extensibility
By extending the system, we do not mean reopening components and developing them again. If you have designed correctly for extensibility, you can mostly leave existing parts untouched and extend the system holistically — by simply adding more slices or subsystems.
What Are Microservices Here?
Do not assume each slice is a microservice. Creating a service per slice can result in an unnecessary number of microservices, leading to excessive HTTP/TCP communications, unreliability, and complexity.
Internal services like Engines and ResourceAccess should rely on fast, reliable, high-performance communication channels — such as TCP/IP, named pipes, IPC, domain sockets, Service Fabric remoting, custom in-memory interception chains, message queues, etc.
A microservice can be a group of slices if you have many of them.
Updated rules
Let’s update the rules of the framework:
- Avoid functional decomposition (what we were doing in universities), and remember: a good system design speaks — through how components interact.
- The client should not be the core business. Let the client be the client — not the system.
- Decompose based on volatility — list the areas of volatility.
- There is rarely a one-to-one mapping between a volatility area and a component.
- List the requirements, then identify the volatilities using both axes: — What can change for existing customers over time? — Keeping time constant, what differs across customers? What are different use cases? (Remember: Almost always, these axes are independent.)
- Verify whether a solution/component is masquerading as a requirement. Verify it is not variability. A volatility is not something that can be handled with if-else; that’s variability.
-
Use the layered approach and proper naming convention:
- Names should be descriptive and avoid atomic business verbs.
- Use
<NounOfVolatility>Manager
,<Gerund>Engine
,<NounOfResource>Access
. - Atomic verbs should only be used for operation names, not service names.
-
layers given in the template should correspond to 4 question:
- Client : Who interacts withe system
Managers : What is required of the system
Engines : How system performs the business logic
ResourceAccess : How system access the resources
Resource : Where is the system state
Validate if your design follows the golden ratio (Manager:Engine). Some valid ratios: 1:(0/1), 2:1, 3:2, 5:3.
More than 5 Managers? You’re likely going wrong.Volatility decreases from top to bottom, while reusability increases from top to bottom.
Slices are subsystems. No more than 3 Managers in a subsystem.
Design iteratively, build incrementally.
Conclusion
In the next article, I will make the given framework more solid with some don'ts and do's. Once we catch those, we then start delving into design examples.
See you next Sunday!
Stay Tuned!
Here are links to previous articles in case you missed them:
- Why Functional Decomposition Leads to Bad System Design
- System Design Basics: Why The Right Method Matters
- The Anti-Design Thinking in System Design
- Volatility-Based Decomposition: A System Design Example
- Principles of Volatility-Based Decomposition in System Design
- Template for System Design Using ‘The Method’
Top comments (0)