Five Invariants for Resilient Systems
- Neejesh Dhaubhadel

- May 12
- 4 min read
Five Patterns. Five Questions. One Principle.

Whether you're writing code or designing a complex system, these five patterns determine whether your system thrives or collapses when it meets the real world.
Every few years, a new technology promises to solve all our problems. Monolith, Microservices, Serverless, Agentic AI. The tools change, but the underlying challenges remain stubbornly consistent. Systems still need to evolve. Data still needs owners. Dependencies still cause surprises at 2 AM.
What follows are five patterns that show up everywhere, in software architecture, in financial systems or in any complex system.
These aren't new ideas. They're enduring principles that determine whether your system thrives or collapses when it meets the real world.
Pattern 1: Evolvability
The Core Question: Can the system adapt when requirements change?
When the complexity of the environment exceeds the capacity of a system to respond, the environment wins. — W. Ross Ashby, An Introduction to Cybernetics
Any system designed to be rigid will eventually be redesigned, usually under the worst possible conditions. Your system does not exist in a stable and ideal environment. It never did. Regulations change. Markets shift. Vendors deprecate products. The only honest architectural stance is to design for change as a first-class requirement.
The Git Repository
Imagine two development teams:
❌ Team A | ✅ Team B |
Works in a single massive file with 50,000 lines of code. Every change risks breaking everything. Merging is archaeology. | Uses modular branches. Features evolve independently. The main branch stays stable. Modularity is strategy. |
Both contain code. One enables adaptation; the other prevents it.

Pattern 2: Encapsulation
The Core Question: Does each component own and protect its data?
A component that doesn't own its data isn't truly independent, it's an accident waiting to happen. When ownership is unclear, or when everyone can reach in and modify anything, you don't have a modular system. You have a ticking time bomb.
❌ Broken | ✅ Encapsulated |
The Private API: Every service queries the payment database directly. Schema change? Everyone breaks simultaneously. | The Private API: Payment service exposes getPaymentStatus(). Internals are hidden. The payment team can completely restructure their database, no one else notices. |

Pattern 3: Coupling
The Core Question: Is our coupling explicit and managed?
Here's a truth that gets buried under years of "decoupling" advice: you cannot build a useful system from components that have no relationship to each other. Your order service needs to know about inventory. Your accounts payable needs to talk to your bank feed. Coupling isn't the enemy.
Hidden, unmanaged coupling is the enemy. The difference between a resilient architecture and a fragile one isn't the amount of coupling, it's whether that coupling is acknowledged, documented, and versioned.
❌ Unmanaged | ✅ Managed |
The Interface Contract: Order service directly calls Inventory's internal methods. Refactoring breaks everything silently, discovered only in production at 2 AM. | The Interface Contract: Services agree on versioned contracts: reserveInventory(productId, qty). Internal changes don't break consumers. Breaking changes require a new version. |

Pattern 4: Observability
The Core Question: Can we follow one transaction from end to end?
This is the difference between knowing something is broken and being able to fix it. Monitoring tells you that error rates are up. Observability tells you that customer #8821 experienced a failure at the payment step for order #4471 because the inventory service returned an unexpected null at 09:41:04.
The Audit Trail
Every transaction links to approvals, documentation, and source records. When an auditor asks "why was this adjustment made?", you retrieve the answer in seconds. You don't reconstruct it from interviews and fragments three weeks later.
The audit trail is the financial equivalent of the distributed trace, a complete, immutable record of what happened, when, and why.

Pattern 5: Resilience
The Core Question: Do we absorb failures or collapse from them?
A distributed system is one in which the failure of a computer you didn't even know existed can render your own computer unusable. — Leslie Lamport
Failure is not a design flaw. It is a design input. Your cloud provider will have outages. Your vendors will send malformed data. Your network will partition. The question isn't whether failure will happen, it's whether you designed for it.
Fragile systems assume success. Resilient systems assume failure, and build accordingly.
❌ Fragile | ✅ Resilient |
The Exception Handler: Code assumes success. Timeout? Crash. Unknown state. Manual recovery. An on-call engineer gets paged at 2 AM to manually reconcile records. | The Exception Handler: Code assumes failure. Catch exceptions. Queue retries with exponential backoff. Preserve state across restarts. Alert operations with context, not just stack traces. |

The Closing Thought

"The goal was never to build a perfect system. The goal was to build a resilient system that can survive being imperfect in an imperfect world."
These five patterns aren't a checklist to complete once. They're lenses to apply continuously, at the start of a project, during architecture reviews, after incidents, and when evaluating new tools.
The specific technologies will keep changing. Serverless, Kubernetes, Agentic AI, whatever comes next. But the systems that survive, that teams can actually work in, that businesses can actually depend on, that adapt without collapsing, are the ones built on these fundamentals.
About the Author

Neejesh Dhaubhadel
Technical Project Manager & BA
Connect with Neejesh on LinkedIn


