Any organization that designs a system (defined more broadly here than just information systems) will inevitably produce a design whose structure is a copy of the organization's communication structure.
Originally published here June 2019, with discussions on Hackernews and Reddit.
Melvin Conway is credited with that quote back in 1967.
In simple terms, Conway is saying:
when we build software, we need to know the different groups/teams/roles it serves, and divide the app up into separate parts, similar to how those groups normally communicate in real life
That's the essence of the single responsibility principle.
Here are some reasons why it's incredibly relevant to a large number of topics on this blog.
With respect to domain knowledge
In this article about Domain Knowledge and the Single Responsibility principle, we agreed that without having knowledge of the domain, it's incredibly hard to determine just how much responsibility a class and a module should have.
Based on what Conway said back in 1967, if we're working on a system that's going to be used by groups of individuals in real life, like:
Interviewersin a recruitment platform or
Employeesin a generic enterprise application
...then failure to understand which requirement maps to which group will make it difficult for us to identify when our classes or modules are responsible for too much (something that spills into multiple groups).
With respect to subdomains and boundaries
In any large-scale application, the entire problem domain is the whole company.
If we were to create Wal-Mart's online systems tomorrow, the entire problem domain is huge.
One of the first few things we learn in software development is decomposition, breaking things to smaller modules. So we decompose the entire domain (Wal-Mart as a company) into subdomains.
But how do we identify the subdomains?
We split up the subdomains based on the organizational structure. So we need:
inventorysubdomain so that people on the floor can keep track of everything that we currently have
time trackingsubdomain for employees
accountingsubdomain system for the accountants
HR / hiringsubdomain system for HR and recruiters
ecommercesubdomain to sell things online
With respect updating future use cases
From "Head First Design Patterns", one of my favourite quotes is:
"change is the only constant in software development
Where does change originate from?
Is it from within the code? Not really, unless we identify a memory leak or something.
Is it from how we organized the code? It could be, if we didn't organize our code well and suddenly it's hard to figure out where things are.
Changes (feature requests) all originate from one place: the users using the software.
If we've organized our code by
use case, it makes the task of finding where to change code non-existent.
billing/ └ useCases/ └ getCustomerById/ getAllCustomers/ chargeCustomer/ getCharges/ refundCustomer/ trading/ └ useCases/ └ approveOffer/ getAllOffers/ makeOffer/ rejectOffer/ catalog/ └ useCases/ └ addVinyl/ getVinylById/ getAllVinyl/ updateVinyl/ removeVinyl/ search/ users/ └ useCases/ └ createAccount/ deleteAccount/ login/ logout/
If our logical boundaries between subdomains are healthy and dependencies to classes common between subdomains are carefully managed, changing a use case in one subdomain shouldnt't affect a use case in another subdomain.
Enjoying so far? Join 15000+ Software Essentialists getting my posts delivered straight to your inbox each week. I won't spam ya. 🖖
Commenting has been disabled for now. To ask questions and discuss this post, join the community.
I see your subdomain => UseCase very anemic, like forced to services, do you not?
I disagree. Here's why.
What makes code anemic?
When the behavior of your domain lives outside of the domain layer. When business logic fails to be placed closest to the entities and domain services (rich model), but instead ends up in services (anemic model).
Why do we use Use Cases?
The biggest benefit out of organizing your system based on actors and use cases is readability. It's really easy to find where features are in order to change them.
The question becomes, what's the responsibility of a use case?
What is the responsibility of a Use Case?
A use case is just an agnostic (application layer) container that is able to execute a feature in a subdomain.
However, the use case itself should contain no business logic.
The entire role of the use case is (in the case of a COMMAND with respect to CQS) to retrieve the entities from persistence, then mediate the ability for the entities and domain services to run execution of the business' rules.
The Use Case is merely an application layer interactor.
Here's a good reference.
“A use case describes application-specific business rules as opposed to the Critical Business Rules within the Entities.”
Excerpt From: Robert C. Martin. “Clean Architecture: A Craftsman's Guide to Software Structure and Design (Robert C. Martin Series).”