The Road to Clean Software Architecture
What is the secret to good software architecture?
To answer this question, let’s ask another one: What purpose does software serve?
Software exists to solve problems for the people who use it—the users. In a business context, these problems might be such actions as
- View their current orders
- Edit their personal details
- Delete an old credit card payment method
- Pay for their shopping cart
- Create a secondary user profile
A software system that performs these actions well for its users could be considered successful.
These actions are WHAT users want a system to do—the Business Requirements. Implemented in code Business Requirements become Business Logic.
For example, consider the case of a customer paying for their shopping cart.
WHAT must happen
- The shopping cart must have something in it,
- Apply customer discount (if any),
- Add taxes to the shopping cart total (if any), and
- The customer pays the shopping cart total.
Notice how we could use this generic workflow in multiple situations and systems:
- In an e-commerce site,
- At a supermarket checkout,
- In a mobile payment app
The workflow even works outside of a computerised system. And for a good reason—computerised business processes are business processes we have performed for thousands of years outside of computers! The process of paying for a basket of goods has been with us since the emergence of trade. The mechanics of an economic transaction are the same whatever the context – a buyer and seller transact goods or services for money or barter.
Aside from WHAT a system does, there is also HOW it does it. The HOW represents the concrete details of our system.
OK, let’s look at an example.
The system in which our customer will pay for their shopping cart will be an online store:
- Native iOS Mobile app
- ASP.NET WebApi 2
- Database: MongoDB
- Payment Gateway: Braintree
Which is more critical—WHAT our system does or HOW it does it?
WHAT the system does (here: pay for goods and services) is more stable and critical than HOW it does it (here: iOS / WebApi2 / MongoDB / Braintree).
The HOW is more volatile – at some point, the business might want to support Android too for their mobile app. Therefore we might decide to rewrite it in a hybrid framework like React Native. Or it’s conceivable that a web application is required. Or we find that MongoDB does not scale as well as we had thought, and we want to replace it with a highly scalable database technology like Cassandra. Or swap the payment provider from Braintree to Stripe.
OK, but what does this have to do with architecture?
We saw that Business Logic is more stable than the rest—the detail or mechanisms. Business Logic belongs at the epicentre of a useful systems architecture since it is the critical part.
All the other parts, the HOW parts, are replaceable with other technology. Developers wanting to replace one implementation of, say, the payment gateway with another, should be able to do this with ease. So, a desirable property of our architecture will be Pluggability. The pluggability ports, or plugs, should belong to the Business Logic – the implementation details are plugging into them.
For example, a SQL Server implementation of the database plugs into the Business Logic, not the other way round. Why? Because the Business Logic should remain ignorant of particular implementation specifics as otherwise pluggability would be lost. In other words, if the Business Logic has to be aware it’s connecting to SQL Server, then how are we meant to plug in MongoDB at a later point in time? It could be done by an enterprising developer, but it would be weird – using MongoDB by maintaining SQL Server models and SDK references. Best avoided. Keep ‘plugs’, or interfaces neutral and independent of any implementation specifics.
Furthermore, in an ideal architecture, the Business Logic could be hosted in different deployment media (web service, web app, desktop application, timed service, etc.) and packaged up and deployed from a simple single process ‘monolith’ to highly scalable microservice deployment model.
A great architecture acknowledges Business Logic’s central position. Business Logic is WHAT makes a system useful – its purpose. How a system expresses the business requirements may differ—maybe it’s a web app or a mobile one, perhaps it uses one database technology or another. Unlike the central Business Logic, these implementation details, being more likely to change, should be pluggable. Pluggability provides options for architects and developers – they can change their minds later on.