Evolutionary Architecture in Practice: Conway's Law, Team Topologies & Fitness Functions
This article details practical implementation of evolutionary architecture, covering Conway's Law alignment, cross-functional team organization, culture and experimentation, budget considerations, fitness functions as experimental tools, enterprise governance with bounded contexts, adoption strategies, and when to avoid evolutionary architecture.
1. Don't Fight Conway's Law
Melvin Conway's 1968 paper "How Do Committees Invent?" states: "Organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations." The way a group decomposes a problem influences the design choices available later. When technicians break problems into smaller pieces for assignment, coordination problems arise. Many organizations use formal communication structures or rigid hierarchies to solve coordination, often leading to rigid solutions. For example, in layered architectures where teams are split by technical function (frontend, backend, database), solving cross-cutting concerns increases coordination overhead.
Conway reminds architects to watch how work is assigned, dispatched, and coordinated across teams. Functional silos optimize for their immediate tasks rather than strategic business goals, delivering "components" instead of end-to-end features. As Conway noted, each assignment narrows the design alternatives that can be explored: "If she wants to change something owned by someone else, she has a hard time changing it."
Companies building microservices often organize teams around service boundaries rather than technical silos — a pattern called the Inverse Conway Maneuver (ThoughtWorks Technology Radar). This aligns team structure with desired architecture, making the architecture easier to achieve. Let teams look like your target architecture, and implementing that architecture becomes easier.
2. How to Organize Teams
Domain-centric teams offer several advantages for evolutionary architecture:
Default cross-functional. Teams contain every role needed to design, implement, and deploy their service, including traditionally separate roles like operations. Roles must adapt:
Architecture: Design to eliminate inappropriate coupling that makes incremental change complex. A well-designed modular monolith can exhibit the same incremental change capability as microservices.
Business Analysts: Sit with the team, provide rapid feedback on proposed changes.
Data: DBAs, analysts, scientists handle new granularity, transactions, and system-of-record issues.
Developers: Need to be more T-shaped or "full-stack," doing work they might avoid in silos (e.g., backend developers doing some mobile/web).
Design: Collaborate closely on user-facing features but spend more time aligning with designers on other cross-functional teams for UI consistency.
Operations: Automating machine provisioning, deployment, and other DevOps tasks is critical. Component modularity and operational modularity are not the same thing.
Product Managers: Prioritize customer needs and business outcomes for their domain. No longer need to coordinate across many technical teams.
Testing: Must handle cross-domain integration testing challenges: standing up integration environments, creating and maintaining contracts.
Eliminate coordination friction. In traditional silos, developers wait for DBAs or operations. Colocating roles removes incidental friction from cross-silo coordination.
Small cross-functional teams suit human nature. Amazon's "two-pizza teams" mimic small primate groups (~10 people). High accountability emerges from innate social behavior: if your code breaks at 3 AM and a teammate fixes it, you face their tired eyes next morning — motivating better ownership.
Cross-functional teams prevent blame-shifting between silos, fostering ownership and encouraging members to do their best.
Organize around business capabilities. Implicitly organizes around business capabilities . Traditional layered architectures optimize for replacing technology layers, not for handling domain entities like Customer. With open source and self-provisioned environments, focus can shift from technical architecture to domain-centric design, matching the common closure unit of most software projects.
Balance business capabilities with cognitive load. Manuel Pais and Matthew Skelton's Team Topologies defines four team types:
Stream-aligned teams: Aligned to a business domain work stream.
Enabling teams: Help stream-aligned teams overcome obstacles, learn new skills/technologies.
Complicated-subsystem teams: Own parts requiring deep math, computation, or technical expertise.
Platform teams: Aggregate other team types, provide compelling internal products to accelerate stream-aligned delivery.
Teams must consider cognitive load . A team handling five payment schemes may exceed cognitive capacity even without extra technical complexity. Solution: multiple stream-aligned teams or a complicated-subsystem team for a specific payment scheme.
Treat "projects" as "products." Projects end; products live forever. Cross-functional teams (often via Inverse Conway Maneuver) stay bound to their product long-term. Each product has an owner advocating for its use, managing requirements. All required roles (PM, BA, design, dev, QA, DBA, ops) are represented. Goal: long-term organizational alignment — developers own quality metrics and defects, gaining long-term vision.
Avoid oversized teams. J. Richard Hackman: "The problem isn't the number of people, it's the number of connections they have to maintain." Connections = n(n−1)/2. 14 people = 91 connections; 50 people = 1,225 connections. Small teams cut communication connections. They must be cross-functional to eliminate artificial friction from cross-silo coordination (which inadvertently inflates collaborator count). Teams needn't know what others do unless integration points exist; even then, fitness functions should guard integration integrity. Keep connection counts between dev teams low.
Team coupling characteristics. How a company organizes and governs structure significantly impacts how software is built and architected. Most architects don't consider how team structure affects architectural coupling characteristics, but the impact is huge.
3. Culture, Experiments & Budget
Culture. Architects should care how engineers build systems, noting what behaviors the organization rewards . Activities and decision processes used when choosing tools and designing systems greatly influence how long software withstands evolution. Effective architects take leadership roles, creating technical culture, designing how developers build systems, teaching and encouraging skills needed for evolutionary architecture.
Questions to understand engineering culture:
Does everyone know what a fitness function is? When selecting new tools/products, do they consider impact on "future ability to write new fitness functions"?
Does the team measure how well the system meets its defined fitness functions?
Do engineers understand cohesion and coupling? What about connascence?
Does the team discuss which domain and technical concepts should go together?
Does the team choose solutions based on ease of change rather than what they want to learn ?
How does the team handle business change? Do they struggle to absorb small changes or spend too much time on them?
Adjusting team behavior often requires adjusting surrounding processes , because people respond to "what others require them to do."
If teams aren't used to change, architects can introduce practices that make change a priority. Example: when considering a new library/framework, require a small experiment to explicitly evaluate : how much extra coupling does it bring? Can engineers easily write/test code outside it? Does it require extra runtime config slowing the dev loop? Code reviews are also natural places to consider "how much does this new code support future changes?" Guard against over-engineering — adding complexity and abstraction too early for change. As Refactoring says: "The first time you do something, you just do it. The second time… you wince at the duplication but do it anyway. The third time, you refactor."
Most teams are driven and rewarded by delivering new features ; code quality and evolvability are considered only when the team prioritizes them. Architects caring about evolutionary architecture must watch whether team behavior makes room for "design decisions that aid evolvability" or find ways to encourage it.
Experimental culture. Successful evolution requires experimentation , but some companies skip experiments due to delivery pressure. Successful experiments rely on frequent small activities to try new ideas (technical and product) and integrate successful experiments into existing systems.
Ways to encourage experimentation:
Bring in outside ideas: Send employees to conferences, hire external consultants.
Encourage explicit improvement: Toyota's kaizen (continuous improvement) — everyone continuously seeks improvement, especially those closest to the problem with authority to solve it.
Implement spikes and stabilize: XP practice — build a throwaway solution to quickly understand a thorny technical problem, explore unfamiliar territory, or increase estimation confidence. Spikes trade software quality for learning speed; never put spikes directly into production.
Create innovation time: Google's 20% time ; hackathons; Atlassian's ShipIt days (24-hour events).
Follow set-based development: Explore multiple alternatives simultaneously . Though seemingly expensive, exploring several options in a short time (e.g., under a few days) yields better problem understanding and reveals real tool/method constraints. More robust solutions often emerge.
Expose engineers to end users: Experiments succeed only when teams understand their work's impact. A/B testing; send teams to observe users interacting with software — builds empathy, returns with better understanding of user needs and new ideas to satisfy them.
CFO & Budget. Traditional enterprise architecture functions like budgeting must reflect changed priorities in evolutionary architecture. Budgets used to be based on "predicting long-term trends in software development ecology," but the nature of dynamic equilibrium destroys predictability.
There's an interesting relationship between architectural quantum count and architectural cost : as quantum count rises, cost per quantum falls until a sweet spot.
Reasons: smaller parts → more discrete, explicit separation of concerns; physical quantum count rise forces operational automation (manual handling becomes impractical beyond a point). But quanta can become so small that sheer quantity becomes more expensive. In microservices, services can be as granular as "one field on a form." At that level, coordination cost between small parts dominates other factors. Evolutionary architects must find the sweet spot between appropriate quantum granularity and corresponding cost. Every company differs: companies in fierce markets may need faster cycles → smaller quanta (new generation speed ∝ cycle time; smaller quanta often have shorter cycle times). Others may find a monolith more pragmatic for simplicity.
Facing an ecology that resists planning, the best architecture-cost fit depends on many factors. This reflects an observation: the architect's role has expanded — architectural choices have greater impact than ever before. Modern architects cannot cling to decades-old "enterprise architecture best practices" dogma; they must understand benefits of evolvable systems and their inherent uncertainty.
4. Fitness Functions as Experimental Media
All the technical detail above is meta-work in non-technical eyes unless you can prove business value. Architects must argue that evolutionary architecture boosts confidence in change and automated governance . More direct benefit: the capabilities it enables .
When selling to business stakeholders, use language they understand: talk about A/B testing , learning from customers . Underneath, evolutionary architecture mechanisms and structures support these, including hypothesis-driven and data-driven development .
Hypothesis-driven & data-driven development. GitHub's Scientist framework exemplifies data-driven development — letting data drive changes, focusing effort on technical changes. A similar approach bringing business concerns in: hypothesis-driven development .
Case: Facebook (Dec 2013–Jan 2014). Photos uploaded that week exceeded all of Flickr; >1M flagged offensive. Users flag photos; human reviewers judge objectively. Volume surge caused insufficient reviewers . Facebook had modern DevOps and ability to experiment on users. Asked "probability a regular user participates in an experiment," an engineer said: "100% — we usually run 20+ experiments simultaneously." Engineers used this to ask users why they flagged photos, discovering human quirks: people won't admit their own photos look bad but will say the photographer did a bad job. By experimenting with different phrasings, they got real users to reveal flagging reasons. In short time, Facebook reduced false positives enough to make offensive photos manageable again — by building a platform that allows experimentation .
Lean Enterprise describes modern hypothesis-driven flow: instead of gathering formal requirements and investing time/resources building features, teams use the scientific method . Once a Minimum Viable Product (MVP) exists (new product or maintenance on existing app), teams build hypotheses for new feature ideas, not requirements. Hypotheses must be explicit: what to test, what experiment decides outcome, what validation means for future development.
Example: Don't enlarge promotional images just because a BA thinks it's a good idea. Write hypothesis: "If we enlarge these promotional images, we hypothesize sales of those items will increase by 5%." After hypothesis stands, run A/B test — one group sees large images, one doesn't — measure results.
Even agile projects with deep business involvement can incrementally build themselves into a corner. Individual BA decisions may seem reasonable in isolation but combined with other features, damage overall experience. mobile.de case: they accumulated features along a logical path, eventually sales dropped partly because UI became too complex — common in mature products. Alternatives: add listings, better sorting, better grouping. To decide, they built three UI versions and let users choose .
The engine driving agile methods is nested feedback loops : tests, CI, iterations. But the loop incorporating end users of the application has always been out of reach. Hypothesis-driven development lets us include users like never before, learning from behavior to build what users truly value .
Hypothesis-driven development needs many pieces working together: evolutionary architecture, modern DevOps, transformed requirements gathering, and ability to run multiple versions simultaneously . Service-based architectures (e.g., microservices) typically achieve parallel versions via intelligent service routing : one user executes with a specific service combination, another request uses a different set of instances of the same services. If most services already have many running instances (e.g., for scalability), routing a subset of users to slightly different, enhanced instances becomes trivial.
Experiments should run long enough for statistically significant results. Prefer measurable ways to judge outcomes over annoying pop-up surveys. Example: does a hypothesized workflow let users complete tasks with fewer keystrokes/clicks? Quietly include users in development and design feedback loops to build far more powerful software.
Fitness functions themselves are experimental media. A common architect use of fitness functions is to answer hypotheses . Many architectural decisions have no precedent anywhere; architects make educated guesses about architectural concerns. Once a solution lands, fitness functions can validate hypotheses . Real project examples follow.
Case: UDP Communication
PenultimateWidgets' ecosystem has many ETL (extract, transform, load) jobs and batch processing. Team built a custom monitoring tool to ensure execution of tasks like Send Reports, Consolidate Information.
Architect designed system with UDP protocol between ETL jobs and monitoring service. Completion messages sometimes lost, causing false "job not completed" alerts, dispatching people to handle false alarms. Architect built a fitness function to answer: "What percentage of messages are not covered by the custom monitoring tool?" If >10%, switch to a more standard implementation.
To verify hypothesis "custom tool isn't as reliable as author thought," team built fitness function: in controlled env (PreProd/UAT) calculate estimated message count and frequency for all apps; build a mock service to simulate that request volume; use mock service to read processed messages from monitoring service DB, yielding two metrics: "lost message percentage" and "max messages app can handle without crashing"; store in JSON; process JSON with Pandas for results.
Result: up to 40% message loss under high load , custom solution's reliability questioned, team decided to change implementation.
Case: Security Dependencies
PenultimateWidgets had a scary security vulnerability in a library dependency, leading to a lengthy manual process to verify software supply chain on every application change. This slowed team speed vs market demands. To shorten security check feedback time, team added a stage in CI pipeline: scan library dependency manifest, compare each version against real-time updated blacklist, alert if any project uses affected library.
This fitness function showed how teams can do holistic governance of important ecosystem aspects. Security is a critical fast-feedback need; automated security checks provide fastest feedback. Automation doesn't replace humans from the feedback loop — it frees people from regression testing and other automatable tasks to do creative work only humans can imagine.
Case: Concurrency Fitness Function
PenultimateWidgets used Strangler Fig pattern — replacing functionality one discrete behavior at a time. Built a new microservice for a specific domain. New service running in production with dual-write strategy , but source of truth remained legacy database . Team hadn't built this type of service before; architect estimated scaling factor should be 120 req/sec based on preliminary data. But service crashed frequently, despite tests showing it could handle 300 req/sec. Increase auto-scaling factor or another cause? Problem:
Team built a fitness function to measure real performance in production: calculate incoming call count in production to verify max requests service must support and "auto-scaling factor needed to guarantee horizontal scaling availability"; build New Relic query to get production calls/sec; use new req/sec for new load and concurrency tests; monitor memory and CPU, define stress points ; put this fitness function in pipeline to guarantee long-term availability and performance.
Result: average call count was 1,200 requests/sec , far exceeding estimates. They updated scaling factor to match reality.
Case: Fidelity Fitness Function
Same team using Strangler Fig hit a common problem: "How to be confident the new system replicates old system behavior?" They built a fidelity fitness function , letting teams selectively replace functionality one piece at a time. Most such functions are inspired by "run two versions of code in parallel (with thresholds) to ensure new replicates old."
Initial intent was consistency guarantee, but they discovered a byproduct : identified data from undocumented sources , gaining better overall understanding of data dependencies in that (poorly documented) legacy system.
5. Enterprise Fitness Functions & Bounded Contexts
In evolutionary architecture, the enterprise architect role revolves around guidance and enterprise-level fitness functions. Microservices reflect this role shift: each service is operationally decoupled, so shared resources are no longer a concern. Instead, architects provide guidance on purposeful coupling points (e.g., service templates) and platform choices . Enterprise architecture typically owns shared infrastructure and constrains platform choices to those consistently supported enterprise-wide.
Case: Zero-Day Security Vulnerability
When a zero-day is found in a framework/library your company uses, what do you do? Many scanning tools look at network packet layer for known vulnerabilities but lack proper hooks to test the right things in time. Painful example: Equifax breach (Sep 7, 2017). Root cause: exploit of Apache Struts (CVE-2017-5638). Foundation disclosed vulnerability Mar 7, 2017, released patch; DHS warned Equifax Mar 8; they scanned Mar 15, found most affected systems — not all. Critical patch not applied to many legacy systems until Jul 29, 2017 — when Equifax security experts identified the hack causing the breach.
In a world with automated governance , every project runs a deployment pipeline; security team has a "slot" in each team's pipeline to deploy fitness functions. Usually these are routine safeguard checks (e.g., prevent developers storing passwords in DB). But when zero-day appears, because every project has the same mechanism, security team can drop a test checking specific framework and version into every project: if dangerous version found, fail build and notify security team. Teams increasingly worry about software supply chain issues — especially provenance of open-source libraries/frameworks. Tools like snyk and GitHub's Dependabot help track and automate software supply chain governance.
Teams configure deployment pipelines to wake up for any change in the ecosystem : code, DB schema, deployment config, fitness functions. Dependency changes let security team monitor potential vulnerabilities, getting the right hooks for the right information at the right time.
If every project uses deployment pipelines to apply fitness functions in builds, enterprise architects can inject their own fitness functions. This lets every project continuously verify cross-cutting concerns — scalability, security, other enterprise-wide concerns — catching defects early. Just as microservice projects share service templates to unify parts of technical architecture, enterprise architects can use deployment pipelines to drive consistent tests across projects . Such mechanisms let enterprises broadly automate important governance tasks. With the vast number of components in modern software, automation must provide the guarantees .
Carving Bounded Contexts in Existing Integration Architectures
Architects want reuse without creating brittleness. A typical scenario: reconciling "enterprise reuse" with "isolation via bounded contexts and architectural quanta," usually at the data layer.
Common pattern: layered architecture, architects partition components by technical capability — presentation, persistence, etc. Goal: separation of concerns , (hopefully) higher reuse. Technical partitioning = building architecture by technical capability, most common style for years.
After DDD emerged, architects designed DDD-inspired architectures, especially bounded contexts . The two most common new topologies — modular monolith and microservices — both heavily based on DDD. But these two patterns are fundamentally incompatible with layered architecture: layered architecture advocates separation of concerns for reuse across contexts, which is a claimed benefit. But as shown, this cross-cutting reuse is simultaneously negated by connascence's locality principle and the principles behind bounded contexts.
How to reconcile? Support separation of concerns, but don't allow destructive side effects from cross-cutting reuse. Another example of "architectural principles need governance," so use fitness functions to reinforce structure. Consider an architecture:
Architect partitioned architecture by technical capability (specific layers don't matter). In a DDD exercise, team identified parts of application that should be isolated as bounded contexts (shaded areas in diagram).
After identifying bounded contexts in technical layers: continuing to split domain parts by technical characteristics does no harm , but team must also prevent applications from coupling to their own implementation details . So team builds fitness functions to prevent cross-bounded-context communication .
Team builds fitness functions at every appropriate place to prevent accidental coupling. Can't prescribe exact function shapes — depends on what assets team wants to protect. But overall goal is clear: by guarding connascence's locality principle, prevent violations of bounded contexts.
6. Where to Start
Many architects face existing architectures like a big ball of mud , unsure where to begin adding evolvability. Appropriate coupling and modularization are the first steps, but sometimes other priorities exist. E.g., if data schema is hopelessly coupled, figuring out how DBA implements modularization might be step one. Common strategies and rationales:
Low-hanging fruit. If organization needs an early win to prove the approach, architects may pick the easiest problem that highlights evolutionary architecture practices. Generally, this is a system part already decoupled to a large degree , preferably not on any dependency's critical path. Improving modularity, lowering coupling lets teams demonstrate other aspects — fitness functions and incremental change. Better isolation enables more focused tests and makes fitness function creation possible; better isolated deployable units ease pipeline construction and provide a platform for more robust tests. If treating as proof-of-concept, developers should collect appropriate before/after metrics . Concrete data is the best way for developers to validate the approach — remember: demo beats discussion . This "easy first" path minimizes risk at cost of potential value loss , unless team gets lucky and "easy" overlaps with "high value." Good for skeptical companies wanting to dip a toe.
Highest value first. Alternative to "easy first" is " highest value first ": find system's most critical part, establish evolutionary behavior around it first. Reasons: (1) If architect is already convinced, starting with highest value signals commitment . (2) For companies still evaluating, doing highest value part first demonstrates evolutionary architecture's long-term value proposition . (3) If architect doubts applicability to their app, testing with most valuable part yields actionable data to decide whether to continue.
Testing. Many companies lament lack of tests. If developers find themselves in a test-poor or test-less codebase, they may decide to add critical tests before more ambitious evolutionary architecture changes. A "just add tests" project is often unwelcome; management views it skeptically, especially if new features are delayed. So architects should combine improving modularity with high-level functional tests . Unit tests around functions provide better scaffolding for TDD, but retrofitting is time-consuming. Better: before refactoring code, add coarse-grained functional tests around some behaviors to verify refactoring doesn't change overall system behavior. Testing is a key component of incremental change in evolutionary architecture, and fitness functions aggressively leverage tests. So at least some degree of testing is a prerequisite; strong correlation exists between test completeness and ease of implementing evolutionary architecture .
Infrastructure. Some companies get new capabilities slowly; ops teams often suffer from lack of innovation. For companies with dysfunctional infrastructure, fixing those issues first may be a prerequisite to building evolutionary architecture . Infrastructure dysfunction takes many forms: outsourcing all ops to another company (losing control of critical piece — cross-company coordination overhead raises DevOps difficulty orders of magnitude); impenetrable firewall between dev and ops (devs don't know how code actually runs — common in companies with cross-department politics and siloed ownership); architects/developers ignoring good practices, accumulating massive technical debt in infrastructure; some companies don't even know what runs where or understand basic architecture-infrastructure interactions. Ultimately, all advice points to the annoying but accurate consultant answer: It depends! Only architects, developers, DBAs, DevOps, test, security, and other contributors can determine the best path to evolutionary architecture.
Case: PenultimateWidgets Enterprise Architecture
PenultimateWidgets considering overhauling large part of legacy platform. Enterprise architect team made a spreadsheet listing all attributes new platform should have: security, performance metrics, scalability, deployability, and many others. Each category 5–20 cells, each with specific criteria. Example: one uptime metric required each service to provide five nines (99.999%) availability. They identified 62 discrete items .
But they realized problems: (1) Would they verify these 62 attributes on projects? Policy can be set, but who continuously verifies policy? Even spot-checking manually is a challenge. (2) Does blanket strict availability requirement on every system part make sense? Admin UI also needs five nines? Blanket rules often lead to severe over-engineering .
To solve, enterprise architects defined their standards as fitness functions and built a deployment pipeline template for every project to start with. In pipeline, architects designed automated fitness functions checking critical characteristics like security, leaving specific functions like availability for each team to add.
7. Whether to Do It & The Future
Future of evolutionary architecture: as teams grow familiar with ideas and practices, they'll be absorbed into daily work , teams will use them to build new capabilities like data-driven development.
Harder fitness functions still need much work, but progress is happening — organizations solving problems and freely publishing solutions. Early agile days, people lamented some problems too hard to automate; fearless developers chipped away, now entire data centers succumb to automation. Netflix innovated heavily conceptualizing and building tools like Simian Army , supporting overall continuous fitness functions (though they didn't call them that). Two promising areas:
AI for fitness functions. Large open-source AI frameworks becoming accessible to ordinary projects. As developers learn to use these tools to support software development, we envision AI-based fitness functions to find anomalous behavior . Credit card companies already use heuristics (e.g., flag transactions at opposite corners of world almost simultaneously); architects can build exploratory tools to discover architectural anomalies.
Generative testing. Practice common in functional programming, gaining wider acceptance. Traditional unit tests contain assertions for correct results per test case; generative testing runs large numbers of tests, captures results, uses statistical analysis to find anomalies. Example: boundary checking — traditional tests check known failure points (negative numbers, overflow), but are immune to unexpected edge cases; generative testing checks every possible value, reports crashing edge cases.
Whether to do it? No silver bullets in architecture either. We don't recommend every project bear extra cost and effort of evolvability unless it truly benefits .
Why companies should build evolutionary architecture? Many enterprises find pace of change accelerated, as Forbes observed: every company must become competent in software development and delivery. Reasons:
Predictable vs. evolvable: Many companies value long-term planning, obviously value predictability. But due to software development ecology's dynamic equilibrium , predictability has expired . Enterprise architects may still plan, but plans can become invalid anytime. Even dull mature industries shouldn't ignore danger of non-evolvable systems — taxi industry lasted centuries across borders, yet disrupted by ride-sharing companies that understood ecology change implications and reacted. Innovator's Dilemma foretells: mature market companies likely fail because nimbler startups handle changing ecology better. Building evolvable architecture takes more time/effort, but payoff: company can respond to substantive market changes without major rewrites . Predictability won't return to mainframe/dedicated ops center nostalgia; development world's highly volatile nature pushes more orgs toward incremental change.
Scalability: Best practice used to be transactional systems backed by relational DBs, using DB features for coordination. Problem: scaling — backend DBs hard to scale. Byzantine technologies emerged to mitigate, but they're band-aids for root scaling problem: coupling . Any coupling point eventually prevents scaling; relying on DB-level coordination eventually hits a wall. Amazon hit this: original site was monolithic frontend connected to monolithic backend modeled around DB; as traffic grew, team could only scale DB up, hit DB scaling limit, site performance degraded — every page loaded slower. Amazon realized coupling everything to one thing (whether RDB, ESB, or other) ultimately limits scalability. Redesigning architecture to microservice style eliminating inappropriate coupling made entire ecosystem scalable. A byproduct of this decoupling: stronger evolvability — inappropriate coupling is evolution's biggest challenge, and a scalable system often corresponds to an evolvable system.
Advanced business capabilities: Many companies envy Facebook, Netflix for sophisticated features. Incremental change enables famous practices like hypothesis-driven and data-driven development. Many companies want multi-variate testing to include users in feedback loops. Key building block for many advanced DevOps practices is an architecture that can evolve. E.g., A/B testing is hard when components are highly coupled; isolating concerns is more arduous. Generally, evolutionary architecture gives companies better technical responsiveness to inevitable, unpredictable change.
Cycle time as business metric: Continuous delivery vs. continuous deployment difference: former has at least one manual gate in pipeline; latter auto-promotes after every successful stage. Building continuous deployment requires high engineering maturity — why push that far? Because cycle time has become a business differentiator in some markets. Large conservative orgs view software as cost, minimize it; innovative companies view software as competitive advantage. E.g., AcmeWidgets achieves 3-hour cycle time vs PenultimateWidgets' 6 weeks — AcmeWidgets has exploitable advantage. Many companies treat cycle time as a first-class business metric , mostly because they're in highly competitive markets. All markets eventually become this competitive — e.g., early 1990s, some large companies more aggressive in using software to automate manual workflows, gained huge advantage until all recognized it as necessity.
Isolating architectural characteristics at quantum level: Treating traditional non-functional requirements as fitness functions and building well-encapsulated architectural quanta lets architects support different characteristics per quantum — a microservice benefit. Because each quantum's technical architecture is decoupled from others, architects can choose different architectures for different use cases. E.g., one small service's developers might choose microkernel architecture to support a small core with incremental additions; another team might choose event-driven for scalability. If both services were in same monolith, architect would have to trade off to satisfy both. Isolating technical architecture at small quantum level lets architects freely focus on each quantum's primary characteristic without analyzing trade-offs between competing priorities.
Adaptation vs. evolution: Many orgs fall into trap — technical debt accumulates, resist necessary refactoring, systems and integration points become increasingly brittle. Companies try to paper over this fragility with connection tools like service buses, alleviating some technical headaches but not solving deeper logical cohesion problems in business processes. Using a service bus is actually adapting an existing system to another scenario . But as emphasized, adaptation's side effect is increased technical debt : when you "adapt" something, you keep original behavior, layer new behavior beside it; more adaptation cycles → more parallel behaviors → higher complexity (hopefully strategic). Feature toggles exemplify adaptation benefits: developers use toggles in hypothesis-driven development to try alternatives, test with users which resonates — toggle's technical debt is purposeful and desirable . Engineering best practice: remove toggles ASAP once decision is made. Evolution means fundamental change : building evolvable architecture means changing architecture in place , protected by fitness functions. Result: a system that can continuously evolve in useful ways, without accumulating increasingly obsolete solutions internally.
Why companies might choose NOT to build evolutionary architecture? We don't think it's a panacea. Valid reasons to skip:
Big ball of mud can't evolve: Most overlooked "-ility" is feasibility — should this project be done? If architecture is a hopelessly coupled big ball of mud, making it evolve cleanly takes enormous work, likely more than a rewrite . Companies hate throwing away anything that looks valuable, but rework often costs more than rewrite. How to judge? First step to convert existing architecture to evolvable is modularization : developers' first task is to find any existing modularization in current system and refactor architecture around those discoveries. Once architecture is less tangled, architects can better see underlying structure and make reasonable judgment on refactoring effort.
Other architectural characteristics dominate: Evolvability is just one of many characteristics architects weigh when choosing styles. No architecture can fully support mutually exclusive core goals — e.g., high performance and high scalability in same architecture is hard. Sometimes other factors outweigh evolutionary change. Usually architects choose architecture for a broad set of requirements (e.g., high availability, security, scalability) pointing to general patterns like monolith, microservices, event-driven. But there are domain-specific architectures built to maximize one specific characteristic . Since built for a specific purpose, evolving it to accommodate other concerns is difficult (unless developer gets extremely lucky and architectural concerns happen to overlap). So most domain-specific architectures don't care about evolution because their specific purpose overrides other concerns.
Sacrificial architecture: Martin Fowler defines sacrificial architecture as designed to be thrown away. Many companies need a simple version first to research market or prove feasibility; once proven, build real architecture to support emerged characteristics. Many do this strategically , often when creating MVP to test market, expecting to replace with more robust architecture after market validation. Building sacrificial architecture means architect doesn't intend to evolve it , but replace it with something more permanent at the right time. Cloud products make this option attractive for companies experimenting with new markets/products.
Planning to shut down soon: Evolutionary architecture helps enterprises adapt to changing ecological forces. If a company doesn't plan to be in business next year, no reason to build evolvability into architecture.
Closing. Building evolutionary architecture isn't a silver-bullet tool architects can download and run, but a holistic architectural governance approach based on accumulated software engineering experience. Real software engineering relies simultaneously on automation and incremental change — both hallmarks of evolutionary architecture. Remember, your ecology often has no off-the-shelf tools . Key question: "Is the information I need available somewhere?" If yes, a simple manual script can gather and aggregate that scattered data to provide architectural value.
Architects needn't implement elaborate fitness functions. Like using unit tests for domain testing, architects should focus on high-value fitness functions worth creating and maintaining. Evolution in architecture has no absolute end state , only varying degrees of value added through these practices. To evolve a software system, architects must have confidence that structural design and engineering practices work together — and controlling coupling with automated verification are the keys to building a well-governed architecture that can evolve through domain changes, technical changes, or both.
This concludes the series: mechanisms make architecture evolvable, structure determines whether it can evolve, and impact explains how to make it actually happen in a real organization. The three are inseparable; evolutionary architecture is not a toolset, but a shift in governance approach. 1. Building Evolutionary Architectures 2nd Chapter 9 ↩︎
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
