Engineering · Application Development
Application Development
Most software we are asked to take over works. The problem is that nobody can change it safely, and the person who could has left. [Draft copy]
The problem
The rules got tangled up with the plumbing.
It was built quickly, which was the right call at the time. The business rules ended up inside the database, or the controller, or a stored procedure written by a contractor in 2019. A change to how a discount is calculated now touches the UI, the data layer and two reports.
So estimates inflate, because every change is really an archaeology exercise. Tests exist, but they test the framework rather than the rules, so they pass while the behaviour changes underneath them. And the system cannot move — it is married to a runtime version on a particular server.
What enterprise-grade looks like here
The rules sit in the middle and depend on nothing.
We build on an onion architecture: the domain at the centre, infrastructure at the edges, and every dependency pointing inward. The rules do not know what database they are stored in, what framework serves them, or which cloud they run on. Swap any of those and the rules do not change.
SOLID, KISS and DRY are not a credential to put on a slide. They are the reason a change stays where you put it: one responsibility per unit so a change has one home, the simplest thing that works so the next person can read it, and one definition of each rule so fixing it once fixes it everywhere.
We mostly build this in .NET, because that is where the deepest bench of our experience is and because it is straightforward to hire for in this market. The shape matters more than the stack, and we are not limited to it — if your team is a Java or a TypeScript team, the architecture is the same and we build it there instead.
This framing repeats on every capability page. It is the differentiator, and it reads consistently across all of them (§9 T3).
What we do
Five moves, in this order.
-
Model the domain before writing the application
The rules, written in the language the business already uses. If we cannot describe them without mentioning a table name, they are not understood yet.
-
Put the domain at the centre
Onion architecture: domain, then application services, then infrastructure. Dependencies point inward, always, and that constraint is enforced in the build rather than trusted to discipline.
-
Test the rules, not the framework
The domain is testable without a database or a web server, so the suite is fast enough that people actually run it. Integration tests cover the edges where the plumbing lives.
-
Record the decisions as they are taken
Short architecture decision records, including the option rejected and why. This is what makes the codebase legible to whoever comes next, including your own new starters.
-
Hand it over so you can hire for it
Conventional structure, no in-house cleverness, and documentation written during the build. A competent developer should be productive in it without us.
[Draft copy]
What you end up owning
Documents and configuration, not a dependency.
| Deliverable | Owned by |
|---|---|
| Source code with the domain isolated and testable | Your engineering team |
| Architecture decision records | Your engineering team |
| Test suite covering the business rules | Your engineering team |
| Build and deployment definitions | Platform team |
| Handover documentation and pairing | Your engineering team |
[Draft copy]
Tell us what you are being asked to prove.
Bring the system you are afraid to change, or the one you are about to commission.
Start a conversation