AW Dev Rethought

🕵️ Debugging is like being the detective in a crime movie where you are also the murderer - Filipe Fortes

Architecture Realities: Why Observability Should Influence Architecture Decisions


Introduction:

Observability is almost always treated as an operational concern. After a system is designed and built, monitoring is added, logging is instrumented, and tracing is configured. The architecture is fixed by the time observability tooling is applied to it — and if that architecture makes the system difficult to observe, the tooling works around the constraints rather than eliminating them.

This sequencing is backwards. The decisions that most significantly affect how observable a system is are architectural decisions — how services are decomposed, how data flows between components, how state is managed, and how failures are surfaced. These decisions are made during design, long before any observability tooling is selected or configured. Treating observability as an operational afterthought means accepting architectural constraints that make systems harder to understand, harder to debug, and harder to operate than they need to be.

Observability that influences architecture produces systems that are genuinely understandable in production. Observability that is applied to a finished architecture produces systems that are instrumented but not necessarily observable.


The Difference Between Instrumented and Observable:

A system can be heavily instrumented and still not be observable. Instrumentation — adding metrics, logs, and traces to existing code — tells you what the code was written to report. Observability tells you what is actually happening in the system, including things the code was not explicitly written to report.

The difference emerges from architectural decisions. A system where business logic is distributed across many small functions that are called indirectly through multiple layers of abstraction is difficult to observe even with comprehensive instrumentation — because the instrumentation reports what each layer is doing without making it easy to understand the end-to-end behaviour that those layers collectively produce.

A system designed with observability in mind has clear boundaries where behaviour can be measured, explicit representations of state that can be inspected, and data flows that are structured so that what enters and exits each component can be captured and correlated. These are architectural properties, not instrumentation properties.


Service Decomposition Affects Observability Directly:

How a system is decomposed into services determines how easy it is to identify where a problem originates. A monolithic system where a failure occurs anywhere affects the whole system — but the failure is at least localised to one deployment unit, one process, and one set of logs. A microservices system distributes failures across many services — but if service boundaries are drawn correctly, failures are localised to the service where they originate and do not propagate to others.

Service decomposition that was driven purely by functional separation — splitting services along domain lines without considering how failures propagate or how requests flow — frequently produces systems where a single user-visible failure involves five or ten services and requires correlating logs and traces across all of them to understand.

Service decomposition that considers observability asks how a failure in this service will manifest in the systems around it, what signals will be available to identify the origin of that failure, and whether the service boundary makes the system more or less understandable when something goes wrong. These questions do not always change the decomposition decision but they surface observability implications before they become operational problems.


Synchronous Call Chains Create Observability Dead Zones:

Long chains of synchronous service calls — where service A calls service B which calls service C which calls service D — create observability challenges that are difficult to address with tooling alone. A failure that originates in service D manifests as a timeout in service A. Understanding the root cause requires tracing the call chain from A through B and C to D — which requires distributed tracing infrastructure, consistent trace propagation across every service in the chain, and tooling that can reconstruct the full chain from individual spans.

When any service in the chain does not propagate trace context correctly, the chain breaks and the trace is incomplete. When a service aggregates calls to multiple downstream services without capturing the relationship between them, the trace does not accurately represent the dependency structure. The instrumentation is present but the architectural decision to use deep synchronous call chains makes the instrumentation insufficient for reliable root cause analysis.

Architectural alternatives — asynchronous communication patterns that decouple services, event-driven designs that make data flows explicit, and service designs that limit the depth of synchronous call chains — produce systems where failures are easier to trace not because the instrumentation is better but because the architecture does not create the dead zones that deep call chains introduce.


State Management Choices Affect Debuggability:

Systems that manage state in ways that are difficult to inspect are systems that are difficult to debug. Distributed state that is spread across multiple services without a clear source of truth is difficult to reason about when it becomes inconsistent. In-memory state that is not persisted or surfaced through any observable interface is invisible to debugging tools. State that is encoded in formats that are not human-readable requires additional tooling to inspect.

Architectural decisions about state management — where state lives, how it is structured, how it can be inspected — directly affect how easy it is to understand system behaviour during incidents. A design that centralises important state in a way that can be queried, that represents state in human-readable formats, and that surfaces state transitions through observable events is significantly easier to debug than a design where state is distributed, opaque, and transitions are implicit.

Choosing state management approaches with debuggability as an explicit criterion produces systems where the questions that arise during incidents — what state was the system in when this failure occurred, how did the system get into this state, what changed — have answers that can be found through observability tooling rather than through code archaeology.


Failure Surfaces Should Be Designed, Not Discovered:

In systems where observability was not considered during design, failure surfaces — the points where failures become visible — are discovered during incidents rather than defined in advance. An engineer debugging a production failure must first figure out where in the system the failure is manifesting before they can begin investigating why.

Designing failure surfaces explicitly means deciding in advance where failures should be visible, what signals should be available at those points, and how those signals should be structured to support investigation. An API gateway that captures and reports the outcome of every downstream service call is a designed failure surface. A database layer that reports query performance statistics is a designed failure surface. A message consumer that tracks processing latency and failure rates per message type is a designed failure surface.

These surfaces are architectural decisions that determine which questions observability tooling can answer. Tooling applied to a system without designed failure surfaces can only answer questions the system was incidentally built to support. Tooling applied to a system with designed failure surfaces can answer the questions that matter most during incidents.


Conclusion:

Observability should influence architecture decisions because the most important determinants of system observability are architectural — how services are decomposed, how data flows between components, how state is managed, and where failures are designed to surface. These decisions, made during design, determine what observability tooling can accomplish. Tooling applied to an architecture that was not designed for observability works around constraints that should have been addressed before the first line of code was written.

The engineering teams that operate their systems most effectively are the ones that treat observability as a design constraint alongside performance, reliability, and maintainability — asking during every architectural decision how this choice will affect the system's understandability in production, and choosing the option that makes the system genuinely observable rather than merely instrumented.


If this article helped you, you can support my work on AW Dev Rethought.


Rethought Relay:
Link copied!

Enjoyed this post?

Stay in the loop

New posts + weekly digest, straight to your inbox.

or

Create a free account

  • Save posts to your vault
  • Like posts & build history
  • New-post alerts

Comments

Add Your Comment

Comment Added!