Architecture Foundations
Architecture Foundations
Core Laws
- Everything in software architecture is a trade-off
- Why is more important than how
- Most decisions exist on a spectrum, not binary choices
– Mark Richards & Neal Ford, Fundamentals of Software Architecture (2020)
Architecture consists of:
- Structure: System components and relationships
- Characteristics: Capabilities the system must deliver
- Components: Behavioral building blocks
- Style: Implementation pattern and topology
- Decisions: Rules and constraints guiding construction
Architectural Thinking
Architecture vs Design
Architecture = Strategic, long-term, hard to change, significant trade-offs Design = Tactical, short-term, easier to change, fewer trade-offs
Ask yourself: How much planning? How many people affected? Long-term vision or short-term action?
Technical Breadth vs Depth
Architects need breadth (knowing a little about many things) over depth (expertise in one area).
Goal: Move things from “unknown unknowns” → “known unknowns” → “knowns” (when needed)
Common Dysfunctions:
- Trying to maintain expertise in too many areas → burnout
- Stale expertise: Outdated knowledge treated as current
- Frozen Caveman antipattern: Reverting to irrational past-trauma concerns instead of objective assessment
Core Skills
Trade-Off Analysis:
“Programmers know the benefits of everything and the trade-offs of nothing. Architects need to understand both.” – Rich Hickey
Everything has trade-offs. The answer is often “it depends” on: environment, business drivers, culture, budgets, timelines, skills.
Business Translation:
Translate business requirements → architecture characteristics (scalability, performance, availability)
Common business justifications: Cost | Time to market | User satisfaction | Strategic positioning |
Hands-On Coding Balance:
Avoid the Bottleneck Trap: Don’t own critical-path code. Delegate framework code; focus on minor features 1-3 iterations ahead.
Stay hands-on via: POCs | Technical debt | Bug fixes | Automation | Code reviews |
Modularity & Coupling
Cohesion (Best → Worst)
- Functional: Everything essential together
- Sequential: Output → Input chain
- Communicational: Shared communication
- Procedural: Specific execution order
- Temporal: Related only by timing
- Logical: Logically but not functionally related
- Coincidental: Unrelated (worst)
Coupling Metrics
Afferent (incoming): Dependencies on this component Efferent (outgoing): This component’s dependencies
Key Metrics:
- Abstractness: Abstract / Concrete ratio
- Instability: Efferent / (Efferent + Afferent)
- Distance from Main Sequence: Balance of abstractness & instability
- Zone of Uselessness: Too abstract
- Zone of Pain: Too concrete
Connascence
Concept introduced by Meilir Page-Jones (1992), popularized in software architecture by Jim Weirich and Kevin Rutherford
Describes coupling types more precisely than simple metrics. Two components are connascent if changing one requires changing the other to maintain correctness.
Static (source-code level):
- Name: Components must agree on entity names (e.g., method names, variable names)
- Example: Renaming a method requires updating all call sites
- Type: Components must agree on data types
- Example: Changing parameter from
int
toString
breaks callers
- Example: Changing parameter from
- Meaning: Components must agree on the meaning of values
- Example: Both must interpret
status = 1
as “active”
- Example: Both must interpret
- Position: Components must agree on parameter order
- Example:
calculateTotal(price, tax)
vscalculateTotal(tax, price)
- Example:
- Algorithm: Components must agree on a particular algorithm
- Example: Both encryption and decryption must use same algorithm
Dynamic (runtime level):
- Execution: Order of execution matters
- Example: Must call
connect()
beforesendData()
- Example: Must call
- Timing: Timing of execution matters (race conditions)
- Example: Two threads accessing shared state without synchronization
- Values: Multiple values must change together
- Example: Updating width requires updating height to maintain aspect ratio
- Identity: Components must reference the same entity
- Example: Multiple services must point to the same user record
Properties (used to evaluate connascence):
- Strength: Ease of refactoring (name < type < meaning < position < algorithm)
- Locality: How close modules are (connascence within a module is less problematic than across services)
- Degree: Size of impact (how many components are affected)
Improvement Strategy:
- Minimize overall connascence in the system
- Minimize connascence across architectural boundaries
- Maximize connascence within boundaries (high cohesion)
Architecture Characteristics
Definition Criteria
Must meet three criteria:
- Specify non-domain consideration
- Influence structural design
- Be critical to success
Categories
Operational: Availability | Continuity | Performance | Recoverability | Reliability | Robustness | Scalability |
Structural: Configurability | Extensibility | Maintainability | Portability | Upgradeability |
Cloud: On-demand scalability | On-demand elasticity | Zone-based availability | Region-based privacy |
Cross-Cutting: Accessibility | Authentication | Authorization | Legal | Privacy | Security | Supportability |
Selection Process
- Start with explicit requirements
- Identify implicit needs
- Focus on trade-offs and priorities
- Limit to 3-7 characteristics (the magic number)
Measuring & Governing
Challenges: Vague definitions, varying interpretations, too composite
Solutions:
- Operational: Performance metrics, response times
- Structural: Cyclomatic complexity (target: <5, acceptable: <10), code metrics
- Process: Test coverage, deployment success rates
- Fitness Functions: Automated integrity assessments
Fitness Functions (evolutionary architecture concept by Neal Ford, Rebecca Parsons, and Patrick Kua):
Objective integrity assessments of architecture characteristics. Like unit tests for architecture.
Examples:
- Performance: Automated tests failing if response time >200ms
- Modularity: Tests failing if cyclomatic complexity >10
- Dependency: Tests failing if service calls forbidden dependencies
- Security: Tests failing if vulnerabilities detected in dependencies
Architecture Quantum
Concept from Mark Richards & Neal Ford’s Fundamentals of Software Architecture (2020)
An independently deployable artifact with high functional cohesion and synchronous connascence. In simpler terms: the smallest useful piece of the system that can be deployed on its own.
Requirements:
- Independent deployment: Can be deployed without deploying other parts
- High functional cohesion: Does something purposeful and complete
- Synchronous connascence: All parts within the quantum that must work together synchronously
Examples:
- Single quantum (monolith): Entire e-commerce application deployed as one unit
- Multiple quanta (microservices): Separate Order Service, Payment Service, Inventory Service each deployable independently
- Hybrid: Modular monolith with separate background job processor (2 quanta)
Why it matters: Determines architectural style, deployment strategy, scalability approach, and team organization. More quanta = more flexibility but more operational complexity.
Partitioning Strategies
Technical Partitioning
Organized by technical capabilities (presentation, business, persistence).
Pros: Clear technical separation, aligns with layered patterns Cons: High global coupling, scattered domain concepts, difficult data migration
Domain Partitioning
Organized by business domains/workflows (DDD approach).
Pros: Models business, easier cross-functional teams, simpler distributed migration Cons: Customization appears in multiple places
Conway’s Law
“Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization’s communication structure.”
– Melvin Conway (1967)
Often paraphrased as: “Organizations design systems that mirror their communication structures.”
Implication: Team structure directly influences architecture. Domain-partitioned architectures work best with cross-functional teams; technical-partitioned architectures often create communication barriers between layers.
Inverse Conway Maneuver: Deliberately structure teams to encourage the desired architecture.
Distributed Computing
Fallacies of Distributed Computing
Originally identified by Peter Deutsch (1994), later expanded by James Gosling and others at Sun Microsystems
False assumptions developers make about distributed systems that lead to problems:
- Network is reliable → Networks fail; use retries, timeouts, circuit breakers
- Latency is zero → Network calls are orders of magnitude slower than local calls; minimize round trips
- Bandwidth is infinite → It’s limited and costly; be mindful of payload sizes
- Network is secure → Secure everything: encrypt in transit, authenticate, authorize
- Topology doesn’t change → Services move, scale, fail; use service discovery
- There is one administrator → Many teams manage different parts; coordinate changes
- Transport cost is zero → Infrastructure, bandwidth, serialization all have costs
- Network is homogeneous → Mix of hardware, OSs, network equipment; handle incompatibilities
Additional modern considerations:
- Versioning is easy → Complex in production; plan for backward compatibility
- Compensating transactions always work → They have limitations; some operations aren’t reversible
- Observability is optional → Critical for debugging distributed systems; invest early
Monolith vs Distributed Decision
Choose Distributed when:
- Different parts need different characteristics
- High scalability/availability required
- Teams need independent deployment
- Domain boundaries are clear
Choose Monolithic when:
- Single characteristic set suffices
- Simpler deployment preferred
- Smaller team/scope
- Cost/complexity must minimize
Team Topologies
Framework by Matthew Skelton and Manuel Pais from “Team Topologies” (2019)
Four fundamental team types for organizing software delivery:
Stream-Aligned Teams: Aligned to a flow of work from a business domain
- Focus on single business domains
- Move quickly delivering discrete value
- Primary team type in most organizations
Enabling Teams: Bridge capability gaps across stream-aligned teams
- Provide research, learning, specialized knowledge
- Help teams overcome obstacles
- Temporary assistance, not permanent dependencies
Complicated-Subsystem Teams: Build and maintain systems requiring specialized knowledge
- Handle highly specialized systems requiring deep expertise
- Reduce cognitive load on stream-aligned teams
- Examples: video processing, mathematical algorithms, real-time trading engines
Platform Teams: Provide internal products that accelerate stream-aligned teams
- Self-service APIs, tools, services as internal product foundation
- Reduce burden on stream-aligned teams
- Treat other teams as customers
Quick Reference
Decision Framework
Question | Monolith | Distributed |
---|---|---|
Different characteristics per part? | No | Yes |
Scalability critical? | Low-Medium | High |
Deployment independence? | No | Yes |
Clear domain boundaries? | No | Yes |
Team size | Small | Multiple teams |
Coupling Reduction Checklist
- Minimize connascence across service boundaries
- Maximize cohesion within components
- Prefer domain partitioning for distributed systems
- Limit architecture characteristics to 3-7
- Measure coupling with afferent/efferent metrics
Key Metrics
Cyclomatic Complexity: Target <5, Acceptable <10 Architecture Characteristics: Limit to 3-7 Connascence: Minimize across boundaries, maximize within
Found this guide helpful? Share it with your team:
Share on LinkedIn