Quick Navigation
- Start here — What quality attributes are
- The core -ilities
- How -ilities conflict
- Tactics for each
- How to prioritise
- How to specify
- Putting it all together
- Cheat sheet
Before we start — the one thing to hold onto
Functional correctness isn't enough. A system that processes orders correctly but crashes under load, takes 30 seconds to respond, or exposes customer data isn't fit for purpose. I've seen teams build systems that do the right things — but do them slowly, unreliably, or insecurely.
Quality attributes are the non-functional characteristics that determine whether a system is truly fit for purpose — not just whether it works, but how well it works under real conditions.
Architecture is driven by quality attributes more than by functional requirements. Features can be added incrementally. Quality attributes must be designed in from the start.
Keep it in mind.
1. What quality attributes are — The difference between "it works" and "it works well enough"
Teams focus on features. They build systems that do the right things — but do them slowly, unreliably, or insecurely.
Quality attributes describe the "how well" of a system. They're often invisible when present and devastating when absent.
The distinction:
flowchart LR
FUNC["Functional\nRequirements\nWhat it does"] --> WORKS["System Works"]
QA["Quality Attributes\nHow well it works"] --> FIT["System is Fit\nfor Purpose"]
WORKS -.->|"not enough alone"| FIT
Examples: A search system that returns correct results in 10 seconds is functionally correct but not fit for purpose. A payment system that processes transactions correctly but has no redundancy is a business risk. A platform that works today but can't be modified without breaking things is on a path to legacy.
The ISO 25010 standard defines quality attributes in a structured model: Quality in Use — effectiveness, efficiency, satisfaction, freedom from risk, context coverage. Product Quality — functional suitability, performance efficiency, compatibility, usability, reliability, security, maintainability, portability.
Why the terminology matters: "Non-functional requirements" is a misleading term — it sounds like they're unimportant. "Quality attributes" is preferred — it signals these are first-class design concerns. "Quality of service" is used in infrastructure and networking contexts. Architects should use "quality attributes" to signal importance.
Quality attributes = the difference between "it works" and "it works well enough."
Try it yourself — The "it works" test
Think of a system in your organisation. Does it work? Yes. Is it fit for purpose?
| Question | Your answer |
|---|---|
| Does it work functionally? | |
| Is it fast enough? | |
| Is it reliable enough? | |
| Is it secure enough? | |
| Can it be changed without breaking? |
If any answer is "no," you have a quality attribute problem, not a functional problem.
2. The core -ilities — Nine attributes that cover most architecture concerns
There are dozens of -ilities. Which ones matter?
Nine quality attributes cover the concerns most architects face. Each has a clear definition and specific design tactics.
flowchart TD
QA["Quality Attributes"]
QA --> S["Scalability\nHandle growth"]
QA --> R["Reliability\nDo the right thing"]
QA --> A["Availability\nBe there when needed"]
QA --> P["Performance\nRespond fast enough"]
QA --> SEC["Security\nProtect what matters"]
QA --> M["Maintainability\nChange without breaking"]
QA --> I["Interoperability\nWork with others"]
QA --> U["Usability\nBe usable by humans"]
QA --> RES["Resilience\nRecover from failure"]
| Attribute | Definition | Key question |
|---|---|---|
| Scalability | Ability to handle increased load | "Can it handle 10x the current load?" |
| Reliability | System performs correctly over time | "Does it do the right thing consistently?" |
| Availability | System is accessible when needed | "What percentage of time is it up?" |
| Performance | Response time and throughput | "How fast does it respond?" |
| Security | Protection of data and access | "Can unauthorised users access or damage it?" |
| Maintainability | Ease of modification | "How much effort to add a feature?" |
| Interoperability | Ability to work with other systems | "Can it exchange data with partners?" |
| Usability | Ease of use for intended users | "Can users accomplish their goals efficiently?" |
| Resilience | Ability to recover from failure | "How quickly does it recover when things break?" |
Each attribute has specific measurable criteria: Vague: "It should be fast." Measurable: "P95 response time under 200ms." Vague: "It should be reliable." Measurable: "99.99% availability = 52 min downtime/year." Vague: "It should scale." Measurable: "Handle 10,000 concurrent users with <1s response."
Nine core -ilities cover most architecture concerns.
Try it yourself — The measurability check
Take three quality attributes for your system. Are they specified measurably?
| Attribute | Current specification | Measurable? | If not, what's the target? |
|---|---|---|---|
If you can't measure it, you can't design for it — and you can't verify it.
3. How -ilities conflict — You can't maximise all of them
Improving one quality attribute often degrades another. You can't maximise all of them simultaneously.
Quality attributes exist in tension. The architect's job is to choose which tensions to accept.
Common conflicts: Security vs usability — more security steps = harder to use. Performance vs maintainability — optimised code is harder to change. Scalability vs consistency — distributed systems trade consistency for scale. Availability vs cost — higher availability costs more. Flexibility vs simplicity — flexible systems are more complex.
flowchart LR
SEC["Security"] <-.->|"tension"| US["Usability"]
PERF["Performance"] <-.->|"tension"| MAINT["Maintainability"]
SCALE["Scalability"] <-.->|"tension"| CONSIST["Consistency"]
AVAIL["Availability"] <-.->|"tension"| COST["Cost"]
FLEX["Flexibility"] <-.->|"tension"| SIMPLE["Simplicity"]
The CAP theorem as an example of fundamental conflict: Consistency, Availability, Partition Tolerance — you can't have all three. Must choose. This is one instance of a general principle — quality attributes conflict. Understanding conflicts prevents teams from setting contradictory goals. Explicit conflict analysis is better than discovering conflicts during implementation.
-ilities conflict — you can't maximise all of them.
Try it yourself — The conflict check
Which quality attributes are in tension in your system?
| Attribute 1 | Attribute 2 | How does the tension manifest? | How are you resolving it? |
|---|---|---|---|
If you haven't identified the tensions, you're discovering them in production.
4. Tactics for each — Specific design patterns that improve each attribute
Knowing which quality attributes matter isn't enough — you need to know how to achieve them.
Each quality attribute has specific design tactics — architectural patterns and decisions that support it.
| Attribute | Key tactics |
|---|---|
| Scalability | Horizontal scaling, load balancing, caching, database sharding, async processing, CDN |
| Reliability | Redundancy, replication, error handling, data validation, idempotency |
| Availability | Failover, health checks, circuit breakers, multi-region deployment, graceful degradation |
| Performance | Caching, indexing, connection pooling, content compression, lazy loading, query optimisation |
| Security | Encryption, authentication, authorisation, input validation, audit logging, zero trust |
| Maintainability | Modularity, loose coupling, high cohesion, clear APIs, documentation, testing |
| Interoperability | Standard protocols, API contracts, data format standards, adapters, middleware |
| Usability | Consistent UI patterns, progressive disclosure, accessibility, responsive design, clear error messages |
| Resilience | Circuit breakers, retry with backoff, bulkheads, chaos engineering, graceful degradation |
Tactics for availability — detailed example: Detection — health checks, heartbeats, monitoring. Recovery — failover, redundancy, replication. Prevention — circuit breakers, load shedding, rate limiting. Degradation — graceful degradation, feature flags, fallback responses.
Tactics are the building blocks of architecture patterns. Choosing tactics is choosing which quality attributes to support. Multiple tactics can be combined — most production systems use tactics from several attributes.
Each -ility has specific design tactics — patterns that improve it.
Try it yourself — The tactics check
For your top priority quality attribute, which tactics are you using?
| Attribute | Tactics in use | Tactics missing | Gap risk |
|---|---|---|---|
If you're missing key tactics for your top priority, you're not designing for it — you're hoping for it.
5. How to prioritise — Choosing what to optimise for
Not all -ilities matter equally for every system. A banking system prioritises differently from a content website.
The prioritisation exercise forces stakeholders to choose — which quality attributes matter most, and which can be sacrificed?
The prioritisation process: List all relevant quality attributes. Rate each by importance to the business (high / medium / low). Identify conflicts between high-priority attributes. Make explicit trade-offs. Document the priorities and rationale.
flowchart TD
LIST["List all\nquality attributes"] --> RATE["Rate by\nbusiness importance"]
RATE --> CONFLICT["Identify\nconflicts"]
CONFLICT --> TRADE["Make explicit\ntrade-offs"]
TRADE --> DOCUMENT["Document\npriorities and rationale"]
The -ility prioritisation matrix:
| Quality Attribute | Importance (H/M/L) | Conflict with | Trade-off decision |
|---|---|---|---|
| Availability | High | Cost | Accept higher infrastructure cost |
| Security | High | Usability | Accept additional auth steps |
| Performance | Medium | Maintainability | Allow some optimised code |
| Scalability | Medium | Simplicity | Accept distributed complexity |
| Maintainability | High | Performance | Prefer clean code over micro-optimisation |
| Usability | Low | Security | Accept security-first UX |
Different systems, different priorities: Banking System — Security: Critical. Availability: Critical. Consistency: Critical. Usability: Medium. Social Media — Availability: Critical. Performance: Critical. Scalability: Critical. Consistency: Low. Internal Tool — Maintainability: Critical. Usability: Critical. Security: Medium. Scalability: Low.
Prioritisation = choosing what to optimise for — not pretending everything matters equally.
Try it yourself — The prioritisation matrix
Take your system. Prioritise the nine core -ilities:
| Attribute | Importance (H/M/L) | Conflict with | Trade-off decision |
|---|---|---|---|
If everything is "high," you haven't prioritised. You've listed.
6. How to specify — Measurably, not vaguely
"The system should be fast" isn't a requirement. "Fast" means different things to different people. Quality attributes must be specified measurably.
Specification means turning vague quality goals into testable, measurable criteria that teams can design against and verify.
The specification formula: [Quality attribute] + [measurable criterion] + [target value] + [conditions]
Examples: Performance: P95 response time under 200ms for API calls under normal load. Availability: 99.99% uptime measured monthly, excluding planned maintenance. Scalability: Handle 10,000 concurrent users with response time under 1 second.
The quality attribute scenario format (from SEI): Source — who/what triggers the stimulus. User, system, external event. Stimulus — the event that arrives. API request, deployment, failure. Environment — conditions when it occurs. Normal load, peak load, degraded mode. Artifact — what is affected. Service, database, network. Response — what should happen. Response within time, recover, log. Response measure — how to measure success. P95 < 200ms, recovery < 30s, 99.99% uptime.
How to turn vague into specific: Vague: "Fast" → Specific: P95 response time under 200ms. Vague: "Reliable" → Specific: 99.99% availability, zero data loss. Vague: "Secure" → Specific: All data encrypted at rest and in transit, MFA required. Vague: "Scalable" → Specific: Handle 10x current load without performance degradation. Vague: "Maintainable" → Specific: New feature deployable within one sprint without architectural changes.
Quality attribute scenarios are testable — you can verify whether the system meets them. Scenarios force precision — "fast" becomes a specific number with specific conditions. Scenarios enable trade-off analysis — you can compare options against measurable criteria. Scenarios feed into fitness functions — automated tests that verify quality attributes in CI/CD.
If you can't measure it, you can't design for it — and you can't verify it. Specify quality attributes measurably — "fast" isn't a requirement.
Try it yourself — The specification test
Take three vague quality goals. Turn them into specific specifications:
| Vague | Specific |
|---|---|
If you can't turn it into a measurable criterion, it's not a requirement. It's a wish.
Putting it all together
Here's the complete picture in one diagram. This is the mental model worth internalising.
flowchart TD
QA["Quality Attributes\nThe -ilities"]
QA --> CORE["Core 9\nScalability, Reliability, Availability,\nPerformance, Security, Maintainability,\nInteroperability, Usability, Resilience"]
QA --> CONFLICT["They Conflict\nImproving one often\ndegrades another"]
QA --> TACTICS["Each Has Tactics\nDesign patterns that\nsupport each attribute"]
QA --> PRIORITISE["Must Prioritise\nWhich matter most\nfor this system?"]
QA --> SPECIFY["Must Specify\nMeasurably, not vaguely"]
CORE --> ARCH["Drives Architecture\nStructure, patterns, technology choices"]
CONFLICT --> ARCH
TACTICS --> ARCH
PRIORITISE --> ARCH
SPECIFY --> ARCH
The foundation:
"It works" isn't enough — quality attributes determine whether a system is fit for purpose under real conditions. They conflict — improving one often degrades another; prioritisation is unavoidable. Specify measurably — "fast" isn't a requirement; "P95 under 200ms" is a design target. Architecture is driven by which quality attributes matter most — and accepting the trade-offs that come with that prioritisation.
Cheat Sheet — All the key terms
| Attribute | One-Line Memory | Key Design Tactics |
|---|---|---|
| Scalability | Handle growth | Horizontal scaling, caching, sharding |
| Reliability | Do the right thing | Redundancy, replication, idempotency |
| Availability | Be there when needed | Failover, circuit breakers, health checks |
| Performance | Respond fast enough | Caching, indexing, connection pooling |
| Security | Protect what matters | Encryption, auth, zero trust |
| Maintainability | Change without breaking | Modularity, loose coupling, testing |
| Interoperability | Work with others | Standards, contracts, adapters |
| Usability | Be usable by humans | Consistent patterns, accessibility |
| Resilience | Recover from failure | Circuit breakers, retries, bulkheads |
How to know if this landed
You'll know this has landed when someone stops saying "it should be fast" and starts saying "P95 response time under 200ms." Can name and define the nine core quality attributes. Identifies conflicts between quality attributes before design. Prioritises quality attributes for a specific system context. Specifies quality attributes measurably — not vaguely. Selects appropriate design tactics for prioritised attributes. And documents quality attribute decisions with rationale.
What changes when the mental model clicks
I've run this session with an e-commerce platform where performance requirements were stated as "fast" — no measurable criteria. Security and usability in constant tension — every security feature made UX worse. No quality attribute prioritisation — everything was "critical." Teams discovered scalability limits in production during peak sales. The gap at the start is usually not about understanding quality attributes — it's about not specifying them measurably.
What changes after this session:
Teams stop setting vague quality goals and start setting measurable targets. The prioritisation exercise — "which -ilities matter most for this system?" — is always the moment things click. People stop treating quality attributes as afterthoughts and start treating them as first-class design concerns. Their results get better. They stop discovering scalability limits in production when the real problem was that they hadn't specified what "scale" meant.
The specification exercise tends to immediately change how teams write requirements. They start turning "fast" into "P95 under 200ms." Their design clarity goes up. They stop arguing about whether something is "fast enough" when the real problem was that they hadn't agreed on a number.
Book a Workshop
Ready to build quality attribute skills in your teams?
or
1-day workshop includes quality attribute identification and classification exercise, prioritisation matrix creation with stakeholders, conflict analysis workshop for real systems, measurable specification practice, tactics selection for prioritised attributes, and quality attribute reference card for your context.