Lesson 3 of 111

Foundations - The Architect's Mindset

Quality Attributes - The Ilities

A few years ago, I reviewed a system that did exactly what the product spec asked for. Every user story was implemented. Every acceptance test passed. And it was a disaster in production: it couldn't handle more than 50 concurrent users, a single server crash took down the entire platform, and deploying a one-line fix required a full system redeployment.

The team had built all the functional requirements and none of the non-functional ones. They'd built what the system should do but ignored how well it should do it.

Functional vs. Non-Functional Requirements

Functional requirements describe what a system does: "Users can place orders." "The system sends email notifications." These are the features on your backlog.

Non-functional requirements: also called quality attributes: describe how the system behaves under stress, at scale, over time, and in failure. They're the "-ilities": scalability, reliability, availability, maintainability, security, observability.

Here's the uncomfortable truth: quality attributes are what make or break a system in production. Features get you to launch. Quality attributes determine whether you survive the first year.

The Core Quality Attributes

Before diving in, here is each attribute in one sentence:

AttributeIn one sentence
ScalabilityHandles more load without proportional cost increases
ReliabilityProduces correct results, every time, even under unexpected conditions
AvailabilityIs operational and accessible when users need it
MaintainabilityIs easy to change, extend, and operate over time
SecurityProtects data and functionality from unauthorized access
ObservabilityLets you understand what is happening inside by examining its outputs

Scalability

The ability to handle increased load: more users, more data, more transactions: without proportionally increasing cost or degrading performance. Scalability is not about being "fast." It's about staying fast as things grow.

Reliability

The system does what it's supposed to do, correctly, every time. A reliable system produces correct results even under unexpected conditions. If your e-commerce platform occasionally charges the wrong amount, you have a reliability problem that no amount of uptime can fix.

Availability

The system is operational and accessible when users need it. Often measured as a percentage: 99.9% availability means roughly 8.7 hours of downtime per year. Availability and reliability are related but distinct: a system can be available (it responds) but unreliable (it responds with wrong data).

Maintainability

How easy it is to modify, extend, debug, and operate the system over time. Maintainability is where most technical debt lives. In Software Architecture in Practice, Bass, Clements, and Kazman argue that maintainability is often the most economically important quality attribute because systems spend most of their lifetime being maintained, not built.

Security

The system protects data and functionality from unauthorized access, modification, and disclosure. Security is not a feature you bolt on at the end: it's a quality attribute that shapes your architecture from day one.

Observability

The ability to understand what's happening inside the system by examining its outputs: logs, metrics, traces. You can't fix what you can't see. In my experience, observability is the most underinvested quality attribute and the one teams regret ignoring the most.

The Conflict Matrix

Here's the critical insight that Richards and Ford emphasize in Fundamentals of Software Architecture: quality attributes frequently conflict with each other. Optimizing for one often degrades another.

ScalabilityReliabilityAvailabilityMaintainabilitySecurityPerformance
Scalability:NeutralSupportsConflictsNeutralConflicts
ReliabilityNeutral:SupportsSupportsSupportsConflicts
AvailabilitySupportsSupports:NeutralConflictsConflicts
MaintainabilityConflictsSupportsNeutral:NeutralNeutral
SecurityNeutralSupportsConflictsNeutral:Conflicts
PerformanceConflictsConflictsConflictsNeutralConflicts:

Conflicts means improving one tends to hurt the other. Supports means they naturally reinforce each other. Neutral means they're largely independent.

Notice how performance conflicts with almost everything. Adding encryption (security) adds latency. Adding redundancy (availability) adds coordination overhead. Adding abstraction layers (maintainability) adds indirection. This is why "make it fast" is never as simple as it sounds.

flowchart diagram 1

Prioritizing Quality Attributes

You cannot maximize all quality attributes simultaneously. You must choose which ones matter most for your specific system and accept trade-offs on the others.

A real-time trading platform prioritizes performance and reliability above all else. A content management system prioritizes maintainability and availability. A healthcare records system prioritizes security and reliability.

The process for prioritization:

  1. Identify your top 3: Which quality attributes would cause the most damage if neglected?
  2. Define measurable targets: "High availability" is meaningless. "99.95% uptime measured monthly" is actionable.
  3. Accept the consequences: If you prioritize availability, acknowledge that you may sacrifice some consistency.
  4. Revisit regularly: As your system matures, priorities shift. A startup's quality priorities at 100 users are different from its priorities at 10 million.

Making Quality Attributes Concrete

Abstract quality attributes become real through quality attribute scenarios. Bass, Clements, and Kazman formalize this as:

  • Source: Who or what causes the event? (A user, a failed server, an attacker)
  • Stimulus: What happens? (A request arrives, a node crashes, a SQL injection attempt)
  • Environment: Under what conditions? (Normal load, peak load, partial failure)
  • Response: What should the system do? (Process the request, failover, block the attempt)
  • Response measure: How do you know it worked? (Latency < 200ms, failover < 30 seconds, zero data exposure)

"The system should be scalable" is a wish. "The system should handle 10x current traffic with p99 latency under 500ms and no more than 2x increase in infrastructure cost" is a design constraint you can actually build toward.

The Architect's Checklist

For every system you design, ask yourself:

  • What happens when traffic increases 10x? (Scalability)
  • What happens when a component produces wrong results? (Reliability)
  • What happens when a server goes down? (Availability)
  • How long does it take a new engineer to ship a change? (Maintainability)
  • What happens if an attacker gains access to the network? (Security)
  • Can you diagnose a production issue at 3 AM? (Observability)

If you can't answer these questions, you don't yet have an architecture: you have a hope.


Key insight: Quality attributes are the non-functional requirements that determine whether a system survives production: and they inherently conflict with each other, forcing you to prioritize deliberately rather than trying to optimize everything.