Overview

9 Durable by design

Durable software is software designed to keep working, evolving, and earning trust over time. The chapter presents durability as the foundation that supports all other qualities of good code: it must adapt to changing requirements, survive operational pressure, remain verifiable through testing, and protect users through stable public interfaces. Because change is inevitable, durability is not about freezing a system in place but about shaping it so that change can happen safely and with minimal disruption.

The first layer of durability is thoughtful design. Systems become easier to evolve when they follow separation of concerns, keeping responsibilities clear and avoiding unnecessary entanglement. This means aiming for high cohesion within components and low coupling between them. SOLID principles and design patterns help achieve this, but the chapter stresses that they should not be applied blindly. Good engineers start from the actual problem: where change is likely, which dependencies are risky, and which abstractions genuinely simplify the design. Durability also extends to resilience: systems must handle failures, traffic spikes, slow dependencies, and overload through techniques such as retries, circuit breakers, rate limiting, bulkheads, time limits, caching, health checks, and graceful degradation.

Testing is presented as the discipline that preserves behavior as software changes. Good tests challenge assumptions, reduce the cost of defects, protect reputation, and act as living documentation. They should be clear, focused, meaningful, and cover both normal and failure paths. Finally, durable software must preserve trust at its public boundaries. APIs, libraries, and data formats are contracts, so their exposed surface should be small, clear, well documented, and protected from internal implementation details. When change becomes necessary, teams should communicate clearly, use deprecation policies and semantic versioning, maintain backward compatibility when possible, and give users time to migrate. Durability, however, must remain balanced with simplicity, because overdesigning for every possible future can make a system harder to understand and maintain.

Layers of durability.
High coupling and low cohesion.
High cohesion and low coupling.

Summary

  • The design trend has evolved from tightly entangled code (spaghetti) to structured layers (lasagna), then to modular units with clear boundaries (ravioli), and finally to architectures that isolate core logic behind concentric boundaries (hexagonal, clean architecture, or onion).
  • Designing for change begins with the separation of concerns: each layer or module should address a specific concern or responsibility.
  • Coupling should be low between modules, and cohesion within a module should be high. High cohesion keeps related logic together; loose coupling minimizes the ripple effect of change.
  • SOLID principles help write durable code that adapts to change without breaking.
  • Automated tests and continuous integration help preserve durability by ensuring behavior remains consistent as the system evolves.
  • Once others depend on your software, durability becomes a matter of trust. Public APIs and libraries form contracts that must remain stable over time.
  • Design public interfaces that expose only what’s necessary, hide implementation details, and use clear response models instead of internal entities.
  • When change is unavoidable for a public interface, communicate clearly through documentation, deprecation notices, and semantic versioning to help users adapt.
  • Preserve backward compatibility of public interfaces for as long as possible.

FAQ

What does “durable by design” mean in software development?

“Durable by design” means building software that can withstand change, pressure, and time. Durable software is easy to evolve when requirements shift, resilient when failures or traffic spikes occur, protected by tests, and trustworthy through stable public interfaces.

Why is separation of concerns important for durability?

Separation of concerns keeps different responsibilities, such as business logic, data access, and user interface code, in distinct parts of the system. This reduces entanglement, makes the code easier to understand, and limits the impact of change. A system with well-separated concerns is less likely to collapse under technical debt as it grows.

What is the difference between cohesion and coupling?

Coupling describes how strongly components depend on each other. Low coupling is preferred because fewer dependencies mean fewer ripple effects when code changes. Cohesion describes how closely related the responsibilities inside a component are. High cohesion is preferred because each module, class, or layer has a clear purpose. Durable design aims for low coupling and high cohesion.

How do the SOLID principles support durable code?

SOLID principles help developers create object-oriented designs that are easier to change and maintain. They encourage single responsibilities, extension without modification, reliable substitution, focused interfaces, and reduced dependency on volatile implementations. However, the chapter emphasizes that SOLID should be applied with judgment, not followed blindly in ways that create needless complexity.

Are design patterns recipes that should always be followed?

No. Design patterns are reusable solutions to common design problems, but they are starting points rather than rigid recipes. Patterns such as Strategy, Builder, Factory, Decorator, Observer, and Circuit Breaker can help implement durable designs, but they should be adapted to the problem at hand. Applying patterns mechanically can lead to over-engineering.

What is resilience in durable software?

Resilience is a system’s ability to remain controlled under disruption and recover gracefully from unexpected failures or pressure. It includes handling failed dependencies through retries, circuit breakers, and fallbacks, as well as staying stable under load using patterns such as rate limiting, backpressure, bulkheads, time limiters, caching, watchdogs, and graceful degradation.

What are some common resilience patterns mentioned in the chapter?

The chapter mentions several resilience patterns: Rate Limiter to control request volume, Backpressure to slow producers when consumers are overwhelmed, Bulkhead to isolate resources and contain failures, Time Limiter to stop long-running operations, Cache to reduce load on dependencies, Watchdog or Heartbeat to monitor health, and Graceful Degradation to preserve essential features under stress.

Why is testing described as “the discipline of doubt”?

Testing requires developers to challenge their own assumptions and look for evidence that their code might fail. This helps counter confirmation bias, where we notice only what proves us right. Good tests expose weak spots before users do, preserve behavior during change, and build confidence that the system still works as intended.

What makes a unit test well written?

A well-written unit test verifies one behavior at a time, has a clear name that describes the expected behavior, and is short and structured. It should cover success cases, edge cases, and failure paths. Good tests reduce duplication, remain simple and expressive, and act as living documentation for the intended behavior of the code.

How can public interfaces be evolved without breaking user trust?

Public interfaces should be treated as contracts. To evolve them safely, communicate changes clearly, update documentation, use deprecation policies, and preserve backward compatibility for as long as necessary. Strategies include method extension, compatibility adapters, and versioning. Semantic versioning helps signal whether a release contains breaking changes, backward-compatible additions, or bug fixes.

pro $24.99 per month

  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose one free eBook per month to keep
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime

lite $19.99 per month

  • access to all Manning books, including MEAPs!

team

5, 10 or 20 seats+ for your team - learn more


choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • The Art of Code ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • The Art of Code ebook for free
choose your plan

team

monthly
annual
$49.99
$499.99
only $41.67 per month
  • five seats for your team
  • access to all Manning books, MEAPs, liveVideos, liveProjects, and audiobooks!
  • choose another free product every time you renew
  • choose twelve free products per year
  • exclusive 50% discount on all purchases
  • renews monthly, pause or cancel renewal anytime
  • renews annually, pause or cancel renewal anytime
  • The Art of Code ebook for free