Architecture and design
I split systems for operational reasons, not for fashion. Every boundary has to be justifiable by something that actually happens in production.
- Extend the tool the business already runs on rather than standing up a parallel system. Almost everything I have built in recent years is exactly that: a module, a channel or a service that plugs into an existing platform through its public contracts, without asking the team to switch tools.
- Services with independent build contexts, when there is a concrete availability reason: redeploying the UI must not restart the event ingester, which has to keep receiving.
- Event-driven over a message broker: queue, audit log, dead-letter queue, and domain routing kept separate from ingestion.
- Ports and adapters where it matters. In the payments prototype, swapping the mocked gateway for the real one touches a single file — neither the domain nor the UI notices.
- Contract first: the envelope, the enums and the result codes defined before the code that uses them.
- Control plane separated from data plane, cache-aside, BFF and facade — applied where they solve something, not as a catalogue.