NorfolkDevelopers
AI-assisted summary of The Principles of Clean Architecture by Uncle Bob Martin — original source. Check the original for full context.
Source published:
Key ideas
- Software architecture should scream its business domain rather than its delivery framework or tools, treating the web merely as an I/O delivery mechanism. (10:45)
- Clean Architecture enforces an inward dependency rule where delivery mechanisms and databases act as plugins to core entities and interactors. (33:07)
- Relational databases and SQL were engineering workarounds for spinning disk latency, an architectural constraint that evaporates with modern persistent RAM. (50:42)
- A primary duty of a software architect is to maximize the number of decisions deferred, keeping frameworks and database choices at arm's length. (66:11)
Detailed notes
## Background Published on YouTube by NorfolkDevelopers on December 15, 2015, this presentation features industry veteran Robert C. "Uncle Bob" Martin delivering a lecture titled "The Principles of Clean Architecture." The video description highlights Martin's career dating back to 1970, his role in formulating Agile Software Development and the Software Craftsmanship Movement, and his authorship of foundational software engineering books such as Clean Code and The Clean Coder.
## TL;DR Uncle Bob Martin argues that high-level software architecture must boldly declare an application's business intent rather than advertising the web frameworks or databases used to build it. Drawing on Ivar Jacobson's use-case driven approach, Martin demonstrates how core business rules—modeled as invariant entities and application-specific interactors—should reside at the architectural center, insulated behind strict input and output boundaries. By treating the web, databases, and third-party frameworks as outer plugins whose dependencies point inward toward stable domain logic, engineering teams decouple from external volatility. This clean separation enables sub-second automated test execution, eliminates the fear of refactoring legacy code, and empowers architects to maximize the deferral of technical decisions.
## Atmosphere & style The presentation carries an energetic, theatrical, and irreverent keynote vibe, launching unexpectedly into mathematical ancestry calculations and evolutionary biology before pivoting into software engineering. Uncle Bob speaks with charismatic confidence and sharp comedic timing, peppering his critique of framework trends, disk hardware, and database administrators with expressive vocal shifts and deadpan humor. The atmosphere is provocative and earnest, transitioning from historical storytelling into an impassioned call for engineering craftsmanship, technical courage, and architectural discipline.
## Bulletin - [10:45](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=645s) Software architecture should scream its business domain rather than its delivery framework or tools, treating the web merely as an I/O delivery mechanism. - [33:07](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=1987s) Clean Architecture enforces an inward dependency rule where delivery mechanisms and databases act as plugins to core entities and interactors. - [50:42](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3042s) Relational databases and SQL were engineering workarounds for spinning disk latency, an architectural constraint that evaporates with modern persistent RAM. - [01:06:11](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3971s) A primary duty of a software architect is to maximize the number of decisions deferred, keeping frameworks and database choices at arm's length.
## Key takeaways - [10:45](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=645s) Directory structures should reveal the system's business purpose rather than highlighting frameworks like Ruby on Rails or Spring. - [12:38](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=758s) The web is simply an I/O mechanism that displays output and captures input, not the fundamental foundation of software architecture. - [15:27](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=927s) Use cases originated by Ivar Jacobson describe business processes through input data, main courses, and alternative paths independent of UI or persistence technology. - [20:01](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=1201s) Entities encapsulate enterprise-wide business rules, whereas interactors manage application-specific use cases and coordinate those entities. - [24:17](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=1457s) Decoupling use cases with plain request and response models enables sub-second automated unit testing without running web servers or databases. - [27:14](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=1634s) Trygve Reenskaug originally designed Smalltalk MVC for individual GUI widgets rather than full web pages, leading to modern architectural leakage in web frameworks. - [36:13](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=2173s) Source code dependencies must cross architectural boundaries inward, ensuring stable business rules remain insulated from volatile external delivery plugins. - [37:56](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=2276s) The presenter and view model pattern removes formatting logic from views, making views too simple to require automated testing. - [48:12](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=2892s) Relational databases and B-tree indexes were historically engineered to compensate for the severe mechanical seek times and latency of spinning magnetic disks. - [50:42](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3042s) The transition to large addressable persistent RAM eliminates the need to map data structures into relational rows and tables. - [54:28](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3268s) The Entity Gateway pattern insulates core business logic from databases by providing abstract interfaces, treating persistent storage as an interchangeable plugin. - [56:31](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3391s) Test suites must execute in seconds to serve as a practical safety net, allowing developers to fearlessly refactor legacy code without breaking behavior. - [01:01:16](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3676s) FitNesse operated successfully for months using in-memory mock storage and flat files, demonstrating the advantage of deferring database implementation decisions. - [01:06:11](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3971s) A good software architecture maximizes deferred decisions, delaying commitments to databases, message queues, and UI frameworks until sufficient information is available. - [01:08:19](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=4099s) Applications must maintain an arm's-length relationship with third-party frameworks, as framework authors have no commitment to preserve backward compatibility. - [01:12:22](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=4342s) Domain entities represent synthesized business behaviors across data sources rather than direct 1:1 representations of database tables.
## Detailed walkthrough ### [00:01](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=1s) The Mathematics of Ancestry and Population Collapse
Uncle Bob Martin begins his talk with a seemingly non-technical puzzle directed at the audience: how many biological parents does each person have? Naturally, the answer is two—even in Norfolk. Going back another step, everyone has four grandparents, eight great-grandparents, and sixteen great-great-grandparents, assuming cousins have not lived close together for generations. Programmers readily recognize this progression as simple powers of two. However, extrapolating this binary progression into the past quickly leads to a physical impossibility.
Ten generations back, roughly 200 years, the formula $2^{10}$ yields 1,024 potential ancestors. Jumping back 400 years to 1615 gives roughly one million ancestors. Going back 600 years to 1415 produces one billion possible ancestors, which was roughly the entire population of the planet at the time. Taking another step back to 1215, the year the Magna Carta was signed, the calculation yields one trillion potential ancestors—far exceeding the total number of human beings who have ever lived on Earth, including all the dead. Martin points out that pedigree collapse and intermarriage flatten this geometric curve:
> “So this power of two thing doesn't work it only works in the first couple of generations and then it sort of curves around you can imagine this this growth curve of your possible ancestors and then the real ancestors kind of curve around and then another effect takes place.”
Because every genealogical line has a non-zero probability of eventually dying out, tracing family lines back far enough inevitably prunes away every branch except one. Mathematically, this guarantees that everyone in the room—and eventually everyone on the planet—shares a common ancestral mother and father.
- Generational scaling: 2 parents $\rightarrow$ 4 grandparents $\rightarrow$ 8 great-grandparents $\rightarrow$ 16 great-great-grandparents. - 200 years ago (10 generations): 1,024 theoretical ancestors ($2^{10}$). - 400 years ago (1615): $1,000,000$ theoretical ancestors ($2^{20}$). - 600 years ago (1415): $1,000,000,000$ theoretical ancestors ($2^{30}$). - 800 years ago (1215): $1,000,000,000,000$ theoretical ancestors ($2^{40}$).
---
[04:39](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=279s) Mitochondrial Eve and Maternal Lineage
While most human nuclear DNA undergoes cross-over recombination that blends maternal and paternal genes beyond easy recognition, certain molecules remain relatively undisturbed across generations. Within the cytoplasm of every cell sits the mitochondrion—jokingly clarified as “not the midi-chlorian”—a hot-dog-shaped organelle responsible for cellular respiration, consuming glucose and oxygen to release water, carbon dioxide, and cellular energy. Roughly 1.5 billion years ago, an ancestral single-celled organism swallowed another without digesting it, establishing an endosymbiotic relationship that gave rise to complex eukaryotic life.
Because egg cells contain mitochondria while sperm cells do not, mitochondrial DNA is passed down purely along the maternal line. Except for rare, benign point mutations—such as a cosmic ray flipping a single nucleotide without breaking the degenerate genetic code—a person's mitochondrial DNA is identical to their mother's and maternal grandmother's. By counting the genetic distance between populations, geneticists have mapped human lineage back to Mitochondrial Eve:
> “They didn't know each other probably they probably didn't live within a few hundred miles of each other they very likely did not live within a few thousand years of each other but these two individuals are the mother and father of everyone alive and this is a mathematical certainty.”
Mitochondrial Eve lived roughly 120,000 years ago in East Africa, an origin identified by the region's immense genetic diversity compared to isolated populations like Iceland, where mitochondrial DNA is virtually identical. Following her lifetime, during a warm era before the onset of the last Ice Age, her descendants branched out across the globe: one cohort moved into Western Europe, another journeyed through Eastern Europe and Russia into the steppes, a third skirted the southern coasts into Australia, and a fourth crossed the Bering Strait into North America around 14,000 years ago, reaching the southern tip of South America only 1,000 years later.
```mermaid flowchart TD accTitle: Mitochondrial Eve Dispersal Map accDescr: Flowchart illustrating the geographic spread of human populations originating from Mitochondrial Eve in East Africa.
subgraph Origin["East Africa (c. 120,000 Years Ago)"] Eve["Mitochondrial Eve"] end
subgraph Migrations["Global Migration Cohorts"] WestEur["North to Western Europe"] EastEur["North to Eastern Europe & Russia"] Oceania["Southern Coastal Route to Australia"] Americas["Bering Strait (14k ya) to South America"] end
Eve --> WestEur Eve --> EastEur Eve --> Oceania Eve --> Americas ```
---
[09:30](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=570s) Y-Chromosomal Adam and Human Migration
Just as women pass down mitochondrial DNA, men carry a stretch of DNA strictly along the paternal line: the Y chromosome. Free from maternal recombination, it represents an unbroken chain of paternal inheritance stretching back to Y-chromosomal Adam. He lived approximately 70,000 years ago in East Africa during the peak of the last Ice Age—thousands of years after Mitochondrial Eve lived.
Although their lifetimes were separated by tens of thousands of years, tracking the paternal lineages of his sons reveals migration routes across the continents that closely mirror the maternal dispersal patterns. Martin notes how deeply fascinating it is that the entire history and journey of the human species are physically encoded within the microscopic molecules of the body. With that foundation established, he turns away from evolutionary genetics to address the actual focus of the evening: software architecture.
- **Mitochondrial Eve**: Estimated to have lived ~120,000 years ago in East Africa. - **Y-chromosomal Adam**: Estimated to have lived ~70,000 years ago in East Africa during the height of the last Ice Age. - Paternal line acts as an unmixed, single-inheritance hierarchy passed down father to son.
---
[10:45](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=645s) The Structure of Rails Apps and the Architecture Problem
Martin pivots to software design by recalling an experience from roughly eight years earlier, when his son showed him a newly built Ruby on Rails application. Looking at the project's file tree, Martin instantly saw directories named `app/`, `controllers/`, `models/`, and `views/`. While any Rails developer immediately identifies that layout, the revelation struck Martin as fundamentally flawed. A top-level directory structure should announce the business domain and intent of the application, yet modern frameworks instead foreground themselves and obscure what the system actually does:
> “Why does the high level directory structure of this application tell me the framework that I'm using why doesn't it tell me what the application does?”
Martin asks the audience how many of them build systems with Ruby on Rails or similar web frameworks. He emphasizes that Rails, like any other web framework, is fundamentally a mechanism for delivering user interaction across the web. However, in the grand scheme of software systems, the web is merely an I/O mechanism. Elevating a delivery mechanism to the dominant organizing principle of an application distorts the architecture and buries the true business purpose beneath delivery-mechanism details.
> “Why would the web be considered something so significant that it would overshadow what the application does now?”
[12:38](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=758s) The Fallacy of the Web as Architecture
When the World Wide Web emerged in the late 1990s, it created an overwhelming sensation that the rules of software development had fundamentally shifted. Uncle Bob Martin recalls the headiness of the dot-com boom, where companies believed they could make trillions simply by creating things like a "Save a Pet website"—until the bubble burst, fortunes vanished, and programmers were left literally holding signs asking to code for food. Looking back across the decades, Uncle Bob notes that the industry took almost twenty years to realize a basic truth: the web did not fundamentally change software architecture. At its core, the web is merely an I/O device designed to take user input and project output onto a screen using HTML.
Despite its mundane nature as an I/O channel, web frameworks seized an outsized, architecturally dominant role. Developers began defining their software not by its purpose, but by the tools used to run it. Uncle Bob mocks the habit of calling something a "Rails app" or describing an architecture as "Java, Spring, and Hibernate." As Uncle Bob Martin insists:
> “That’s not an architecture, that’s a bunch of tools.”
If you are writing accounting software, you are building an accounting application—you merely happen to be delivering it through Rails or Spring.
To illustrate what architecture truly represents, Uncle Bob compares software to architectural blueprints. When examining a blueprint of a library, its identity is self-evident: it features bookshelves, desks, computer areas, and study tables. Similarly, a blueprint of a church immediately communicates that it is a church. Architecture is fundamentally about intent, declaring what the system actually does, whereas delivery mechanisms, frameworks, and databases are low-level implementation details that should remain hidden rather than defining the top-level structure.
- Architecture communicates the business intent of the system, not the delivery mechanisms or third-party frameworks. - Frameworks like Ruby on Rails or Spring, as well as libraries like Hibernate, are implementation tools and should not be confused with software architecture. - Describing a project as a "Rails app" obscures the actual domain, such as an accounting system or inventory management system.
---
[15:27](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=927s) Ivar Jacobson and the Lost Simplicity of Use Cases
The realization that architecture is about intent mirrors principles laid out decades earlier by Ivar Jacobson. In 1992, Jacobson published his seminal work, *Object-Oriented Software Engineering: A Use Case Driven Approach* (Uncle Bob quips that Jacobson's employees wrote it while Jacobson took the credit). When the book launched at a conference, developers lined up at the bookstore in droves, recognizing it as an immediate classic.
```mermaid flowchart TD accTitle: Evolution of Use Cases to User Stories accDescr: Diagram showing how simple Jacobson use cases became bloated by consultants before pivoting into Agile user stories.
subgraph JacobsonOrigin["1992: Original Concept"] A["Jacobson Use Cases<br>(Simple, goal-driven)"] end
subgraph ConsultantBloat["The Consultant Era"] B["PostScript / PDF Forms"] C["Actor Overload<br>(Primary, secondary, tertiary)"] D["Exhaustive Pre/Post-conditions"] A --> B --> C --> D end
subgraph AgilePivot["Agile Revolution"] E["Agile User Stories<br>(Identical concept, no bloated forms)"] D -->|"Rejection of bureaucracy"| E end ```
However, the industry's enthusiasm was soon corrupted by what Uncle Bob calls the "invasion of the consultants." To outdo their predecessors, consultants began publishing increasingly rigid, complex forms—originally distributed as PostScript files and PDFs on the nascent web. These templates forced developers into administrative nightmares, requiring explicit listings of primary, secondary, and tertiary actors, along with exhaustive preconditions and postconditions. This bureaucratic bloat alienated software teams to the point of exhaustion. When the Agile movement later arrived advocating "user stories," the industry embraced them enthusiastically, largely failing to recognize that user stories and use cases are fundamentally the exact same thing; user stories simply stripped away the suffocating procedural forms.
- Ivar Jacobson's 1992 book *Object-Oriented Software Engineering: A Use Case Driven Approach* introduced use cases to structure systems around user goals. - Escalating consulting templates introduced administrative bloat (primary, secondary, and tertiary actors, preconditions, postconditions) that made use cases cumbersome. - Agile user stories addressed the exact same conceptual need as use cases while discarding bureaucratic form templates.
---
[17:49](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=1069s) Anatomy of a Use Case
Returning to Jacobson's original formulation, Uncle Bob highlights that a use case is meant to be simple, abstract, and independent of technical mechanisms. Looking at a concrete example—the `Create Order` use case within an order entry system—the specification describes the interaction without binding itself to data schemas, delivery channels, or storage engines:
1. **Input Data**: Captures elements like `Customer ID`, `Shipment Destination`, and `Payment Information` without specifying physical structure, data formats, or whether the payload originated from a web form or another source. 2. **Primary Course**: Describes the normal execution flow through concise processing steps: - The order clerk issues the `Create Order` command with the required data (a manual step triggering the flow). - The system validates all data (deferring specific validation criteria for later). - The system creates the order and determines the order ID (an operation that could involve a database, though the use case does not state this). - The system delivers the order ID back to the clerk (likely on a screen or web page, left uncoupled from the use case itself). 3. **Alternate/Error Courses**: Handles failures and edge conditions, which typically amount to only one or two exceptional paths.
Uncle Bob points out how deliberately agnostic this specification is: it never mentions HTML, HTTP, SQL, or relational tables. It solely outlines the business workflow.
---
[20:01](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=1201s) Objectifying Use Cases: Interactors, Entities, and Boundaries
The central insight of Jacobson's work was translating these procedural use cases directly into object-oriented structures. Because a use case accepts input, manipulates data, and emits an output, it can be modeled directly as an object. Jacobson originally referred to these as "control objects." Uncle Bob chose the term **Interactors** to avoid confusion with the Controller in Model-View-Controller (MVC), though he acknowledges that calling them "use case objects" might have been simpler:
> “The interactor object contains application-specific business rules.”
Uncle Bob differentiates business rules into two distinct categories:
- **Application-Independent Business Rules (Entities)**: Rules that remain invariant across multiple systems within an enterprise (often called "business objects"). For instance, the calculation of an order's total price applies across order entry, fulfillment, and billing. Jacobson called these *Entities*. An interactor coordinates several entities to achieve a goal, such as an `Order`, a `Line Item`, and a `Customer`. - **Application-Specific Business Rules (Interactors)**: Rules that belong strictly to a single application and define its specific use cases. Creating an order belongs uniquely to the order entry system; other systems cannot invoke that specific workflow.
```mermaid flowchart LR accTitle: Interactor, Entities, and Boundaries Flow accDescr: Structural diagram showing how delivery mechanisms communicate with interactors and entities across boundary interfaces.
subgraph Delivery["Delivery Mechanism"] User(["User"]) --> UI["Delivery Component<br>(Web / Console / SOA)"] end
subgraph CleanCore["Application Core"] direction TB InBound["«interface»<br>Input Boundary"] OutBound["«interface»<br>Output Boundary"]
Interactor["Interactor<br>(Application-Specific Rules)"]
subgraph EnterpriseRules["Domain Entities"] Order["Order"] Customer["Customer"] LineItem["Line Item"] end
InBound <|.. Interactor Interactor..|> OutBound Interactor --> Order Interactor --> Customer Interactor --> LineItem end
UI -->|"calls"| InBound OutBound -->|"notifies / passes data"| UI ```
To isolate the Interactor from external concerns, Jacobson introduced **Boundary Objects** (originally called *Interface Objects*), which Uncle Bob models as abstract interfaces:
- **Input Boundary**: An interface implemented by the Interactor through which input data enters. - **Output Boundary**: An interface implemented by an external component (such as a presenter or UI component) through which outgoing results leave the Interactor. - **Delivery Mechanism**: The outermost layer (console, thick client, web application, or service-oriented endpoint) that interacts with external users and systems, remaining entirely decoupled from the core business rules.
[24:17](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=1457s) Boundaries, Interactors, and Testability
Uncle Bob outlines the end-to-end data flow across an architectural boundary. When a user interacts with the system—such as filling out a web form and clicking the submit button—the delivery mechanism takes whatever data was generated in that moment and packages it into a data structure called a request model. He emphasizes that while this might look superficially like an HTTP request to developers accustomed to web work, it must remain strictly untainted by web concepts:
> “I don't want the words HTTP in there at all I don't want any I don't want it to derive from some Base Class which is tied to the web I don't want any field in it that have any webbish kind of knowledge to it in fact what I want this data structure to be is a plain old Java object or a plain old.NET object or whatever language you're using with a bunch of Primitives in it and no dependencies at all on any framework...”
This framework-agnostic request model passes directly into the input boundary. Because the interactor derives from or implements this input boundary, it accepts the request model, decodes it (for example, recognizing a "create order" request), extracts the primitive data, and uses that data to “control the dance of the entities.” The interactor instructs the entities to create an order, attach line items, and associate the customer. Once those tasks finish, the interactor orchestrates the entities in reverse, gathering up the computed results into another decoupled data structure: the result model (or response model). Finally, the result model passes back out through the output boundary to the delivery mechanism, which renders or sends the response to the user.
```mermaid flowchart LR accTitle: Request and Response Flow Through Clean Architecture Boundaries accDescr: Data flows from the delivery mechanism into an input boundary, is processed by an interactor and entities, and returns via an output boundary.
subgraph Delivery["Delivery Mechanism (Web)"] UI["User Form / Submit"] Req["Request Model (POJO)"] Res["Result Model (POJO)"] OutPresenter["Delivery / Presenter"] end
subgraph Application["Application Business Rules"] IBound["Input Boundary"] Interactor["Interactor / Use Case"] OBound["Output Boundary"] end
subgraph Enterprise["Enterprise Business Rules"] Entities["Entities"] end
UI --> Req Req --> IBound IBound --> Interactor Interactor <-->|"orchestrates dance"| Entities Interactor --> Res Res --> OBound OBound --> OutPresenter ```
Uncle Bob stresses that this structure unlocks pure, effortless testability. An interactor can be tested in complete isolation simply by handing it a request model and asserting on the resulting response model. There is no need for a web server, an application server, or even a database to be running. He argues that this isolation is an absolute prerequisite for testing business rules:
> “...when you're writing tests especially tests of your use cases you do not want to have the whole system running especially any part of the system that is slow or any part of the system that makes it difficult to communicate with the business rules like a web server does you don't want to have any of that stuff running you'd like to just talk right to the business rules...”
---
[27:14](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=1634s) Meeting Trygve Reenskaug and the Origins of Smalltalk MVC
Anticipating an audience objection—asking how this boundary-driven model relates to Model-View-Controller (MVC), the standard paradigm for web applications—Uncle Bob takes a detour into history. He introduces Trygve Reenskaug, whom he credits with inventing MVC in the 1970s for Smalltalk, remarking that MVC might be the earliest named design pattern before the term "design pattern" was even coined.
He shares a humorous personal anecdote about meeting Reenskaug in the speaker lounge at a conference in Norway. Uncle Bob was on the floor searching for an outlet to plug in his laptop when an older gentleman silently reached over and handed him a power strip. True to programmer form, Uncle Bob took it without looking up:
> “...programmers don't make eye contact right so I I took the power strip from and then I looked up and oh it's Trygve Reenskaug and as I took it you know our fingers just barely touched I haven't washed that hand...”
Martin then breaks down what Reenskaug’s original MVC actually was: - **Model**: Encapsulates a very small, specific business rule. The model is strictly forbidden from knowing what input devices control it or where its data originates. - **Controller**: Captures hardware gestures from input devices (keyboard, mouse) and translates those raw gestures into method calls against the model. - **View**: Observes the model. Uncle Bob draws attention to an observer relationship where the view registers with the model, and the model notifies the view whenever its internal state changes so the view can re-render the data to the user.
Crucially, Uncle Bob explains that in Smalltalk, MVC was applied *in the small*. You had a distinct triad for an individual button, another for a single text box, and another for a radio button group. It was never intended to represent an entire web page.
---
[30:25](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=1825s) The Corruption of Web MVC and the Discipline Deficit
Uncle Bob explains how the software industry routinely corrupts good ideas: developers recognize that a concept is sound, conclude that their own new idea is also sound, assume both ideas must be the same thing, and slap the original label onto their new construct. This is how the web inherited a distorted version of MVC applied to entire pages:
```mermaid flowchart TD accTitle: Typical Web MVC Flaws accDescr: In typical Web MVC, controllers invoke business models, which hand off to views, but code bleeds across missing boundaries.
subgraph WebBoundary["Delivery (Web / HTTP)"] Req["HTTP GET/POST / URL"] C["Controller"] V["View"] end
subgraph ModelArea["Model Area"] BO["Business Objects"] end
Req --> C C -->|"unpacks parameters & calls"| BO C -->|"passes control"| V V -->|"queries data from"| BO
BO -.->|"leaks controller logic into"| BO BO -.->|"leaks business logic into"| V ```
In typical web MVC, an incoming HTTP GET or POST URL triggers a controller. The controller unpacks string parameters and invokes business objects located in the "model." Afterward, control passes to the view, which queries those same business objects and outputs HTML.
The fatal flaw with this setup is the complete absence of firm architectural boundaries: - Controller logic bleeds directly into the business objects when programmers under deadline pressure scramble to make things work. - Business logic leaks into views, a pattern anyone working in web applications has seen repeatedly.
Uncle Bob connects this structural degradation directly to a lack of professional discipline across the software industry:
> “...one of the problems we have as an industry is that we're not very good at keeping discipline I mean hell half of us don't write tests and that's unbelievable right can you imagine telling your users you know I don't write tests I just write the code and sometimes it even works and I ship it to you and if bugs well you're going to tell me aren't you that's our attitude...”
---
[33:07](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=1987s) The Double Black Line and the Web as a Plugin
Turning back to Ivar Jacobson’s architecture, Uncle Bob highlights the "double black line." He clarifies that he is not speaking of an individual boundary class or boundary object, but a hard, dividing architectural line separating enterprise business rules from external delivery mechanisms like the web.
Across this boundary, all dependencies point inwards toward the business rules:
> “This is the fundamental architecture of a plugin this the web is a plugin to the business rules...”
To demonstrate the structural power dynamics of plugin architectures, Uncle Bob surveys the audience on the programming languages they use: - **Java** and **.NET** - **Python** (“dynamically typed, lots of cool things”) - **APL** (Uncle Bob reacts with disbelief: “Really? People still use APL? Wow. Do you have like special keyboards with a million keys?”) - **PHP** (“accidental language, was never supposed to be a language, but it became one”) - **Tcl/Tk** (“graphics language”) - **JavaScript**
He then uses a concrete software tool pair to illustrate plugin dynamics: Microsoft’s Visual Studio and JetBrains’ ReSharper (a plugin that Martin quips “makes it almost usable”). He asks the audience to consider the relationship between the Visual Studio team at Microsoft and the ReSharper team at JetBrains: which of those teams holds absolute power, and which team is completely powerless? While Microsoft could leverage its financial dominance to harm anyone, Uncle Bob points out that purely at the architectural level of the plugin boundary, Microsoft does not need money to put JetBrains out of business—the author of the boundary controls the contract.
[36:13](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=2173s) Plugins, Compile-Time Immunity, and UI Architecture
Uncle Bob explains how dependency direction establishes power and immunity within software systems. When one system acts as a host and another connects as a plugin, the host holds all the leverage. For instance, a platform vendor could drive an extension developer out of business simply by altering their public interface daily, repeatedly invalidating the plugin just as it prepares to deploy. A plugin is intrinsically vulnerable to the system it plugs into, whereas the core system remains completely immune at compile time to anything occurring within the plugin.
Software architects should intentionally leverage this asymmetry. In any production system, the core business rules must remain immune to the erratic, frequent shifts of the user interface. Because the user interface changes far more frequently than core business logic, it belongs on the vulnerable, outer side of the boundary:
> “If something changes a lot it should be a plug-in if something doesn't change very often it should be plugged into this is the signature of a plug-in plugins always have source code dependencies that point One Direction.”
```mermaid flowchart LR accTitle: Plugin Dependency Flow accDescr: Demonstrates that the UI depends on Business Rules, leaving Business Rules immune to UI changes. subgraph UIModule["UI (Volatile Plugin)"] UI["User Interface"] end subgraph CoreModule["Core (Stable Host)"] BR["Business Rules"] end UI -->|"depends on (source code)"| BR ```
[37:56](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=2276s) Presenters, Response Models, and the "Stupid" View
Tracing the flow of data back out toward the user, the interactor completes the usecase execution—the "dance of the entities"—and packages the output into a response model data structure. It hands this response model across the output boundary to a presenter. The presenter’s sole responsibility is translating the raw domain data in the response model into a view model tailored for display.
While the response model contains raw, non-presentable structures such as `Date` instances or currency `Money` objects, the view model consists almost entirely of plain strings and simple primitives. The presenter applies the formatting—invoking date formatters, applying currency symbols, setting decimal precision, and wrapping negative amounts in parentheses. If a monetary value is negative and needs to appear in red, the presenter evaluates that condition and sets a boolean flag on the view model. The view model also stores display-level UI state: button label strings, booleans indicating whether buttons or menu items should be grayed out or disabled, and lists governing menu element ordering.
By moving all formatting, logic, and conditional state evaluation into the presenter, the view itself is stripped of decision-making logic:
> “The goal behind that is to make the view so stupid you don't have to test it.”
Because the view merely extracts values from the view model and writes them directly to the screen, developers only need to verify it visually. The presenter, by contrast, is fully unit-testable without launching any UI harness, verifying every string format, toggle, and conditional display flag in complete isolation.
- **Response Model:** Holds business-level results produced by the interactor (raw `Date` objects, currency/numeric types, domain structures). - **Presenter:** Formats raw data into strings, evaluates layout flags, and controls widget state (e.g., active, disabled, text color). - **View Model:** A dumb data holder consisting purely of formatted strings and booleans for the view to render directly. - **View:** Completely devoid of business or formatting logic; acts as an untyped renderer that reads the view model.
[41:28](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=2488s) Enforcing Boundaries for Independent Deployment
Every dependency across the architectural boundary must point strictly inward toward the higher-level policies. Uncle Bob emphasizes that this is an absolute rule with zero tolerance for leaks: every import, include, and source code reference must strictly align in that single direction.
This strict adherence is what enables true independent deployment. The UI layer can be packaged into its own JAR, DLL, Ruby gem, or shared library, completely separated from the core business logic component. When modifications are made to the GUI, developers recompile and redeploy only the presentation artifact. The core business rules binary remains entirely untouched, uncompiled, and undeployed, proving that the presentation layer is behaving as a genuine plugin.
```mermaid flowchart TD accTitle: Clean Architecture Output Boundary Flow accDescr: Flow from Interactor through Output Boundary and Presenter to View Model and View. subgraph CoreEngine["Core Business Logic"] UC["Interactor"] OB["Output Boundary (Interface)"] RM["Response Model"] end subgraph PresentationPlugin["Presentation (Plugin)"] P["Presenter"] VM["View Model"] V["View (Dumb)"] end
UC -->|"creates"| RM UC -->|"calls"| OB P -.->|"implements"| OB P -->|"reads"| RM P -->|"populates"| VM V -->|"reads"| VM ```
[42:46](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=2566s) The Myth of the Central Database and the Rise of DBAs
Uncle Bob shifts to the database, addressing the pervasive architectural belief that the database resides at the center of the universe while all surrounding applications exist merely to serve it. He mockingly asks whether the database calls to developers in their sleep like an idol surrounded by worshiping minions. This mental model directly benefits database administrators (DBAs), elevating them to "high priests" who guard the system from atop their perches.
He recounts the historical emergence of DBAs during the 1970s, tracing the title back to aggressive enterprise marketing campaigns led by companies like Oracle. Back when relational database vendors had to fight for market share, their sales forces approached corporate executives with a manufactured concern:
> “They went to CEOs and they said to the CEOs are you protecting your data assets what a beautiful word that is a data asset no one had ever thought of this word data and asset together a data could be an asset are you protecting your data assets CEO goes I didn't know I had data assets oh yes you do and you'd better be protecting them and we have the system that will protect them ah but in order to use our system you have to change your organization you need people to preside over the control of your data assets”
This narrative spurred enterprises to hire dedicated database administrators holding exclusive keys to data stores. Uncle Bob views this elevation as a profound architectural mistake. A database is not an architectural centerpiece; it is merely an I/O device—a mechanical repository for storing bits that happens to offer indexing, searching, and reporting tools. Treating the database as the core architectural focus repeats the architectural error found in frameworks like Ruby on Rails, which places both the web and the database at the center of the application.
- **Role of the Programmer:** Managing details by rigorously separating concrete mechanisms from overarching abstract business rules. - **True Nature of Databases:** An auxiliary I/O device and persistence mechanism, not an architectural foundation.
[46:15](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=2775s) Relational Databases, SQL, and Disk Mechanics
Uncle Bob challenges the modern developer's uncritical acceptance of relational table structures. Persistent storage existed long before relational databases—Unix file system directory hierarchies and hierarchical database engines operated successfully for years. Despite this, the industry spent three decades cramming object-oriented and relational pointers into flat tables, linking them through relationship tables, and querying them through SQL.
He characterizes SQL as a fundamentally flawed access language that introduced widespread security vulnerabilities worldwide:
> “And we have to have this this actually truly horrible language called SQL SQL to access all of this data which by the way has led to tremendous security problems all over the place because somebody had the great idea that our data access language should be textual and then interpreted inside the code so that some guy out in Nigeria could type select star inside the date field”
These elaborate relational engines and frameworks were never invented because tabular layouts represent pure data theory; they were created because physical disks are difficult to manage. Uncle Bob asks the audience if anyone has ever written a disk driver, explaining that rotating magnetic platters—historically stacked 14 or 15 high—forced software designers to invent complex access layers simply to navigate physical read/write heads across magnetic tracks. Relational database engines are, at their foundation, historical workarounds for hardware constraints.
[48:12](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=2892s) The Physical Mechanics and Pain of Spinning Discs
Robert C. Martin ("Uncle Bob") takes the audience back to the mechanical realities of early computer storage to explain why databases took the shape they did. In the early days, disk drives featured magnetic platters spinning on a central spindle at speeds like 3,600 RPM (spinning roughly 50 to 60 times a second), which later accelerated to 7,200 RPM as drives shrank. A physical read/write head had to swing mechanically in and out across the surface, writing microscopic magnetic dots arranged in concentric circles called tracks. With tracks spaced perhaps half a millimeter apart, a platter held 200, 500, or 1,000 such rings; because platters were stacked vertically on the spindle, the vertical cylinder formed by all tracks sharing the same radius was termed a cylinder.
Writing or reading a single byte was a tortuous physical process. A developer or controller had to issue a directive telling the drive head to seek to a specific cylinder (such as cylinder 72). In the earliest hardware, programmers even had to account for physical momentum, manually commanding acceleration and deceleration. A typical seek time in the 1960s, 1970s, and into the mid-1980s was roughly 100 milliseconds. After that delay, the controller had to wait out the rotational latency for the target section of the spinning platter to arrive beneath the head. Furthermore, drives could not read a single byte directly; they had to retrieve an entire 4-kilobyte sector. Only after bringing all 4 KB into memory could software extract the solitary byte it actually needed.
Uncle Bob emphasizes that the entire enterprise of relational databases and early data frameworks was created to mitigate this physical friction: “The job of the database was to get rid of that pain to to make it efficient to get data in and off this horrible spinning magnetic surface.” To overcome disk geometry, computer scientists devised B-tree indexes, structured relational tables, and specialized retrieval frameworks solely to maximize mechanical efficiency.
- Disk platters spun at 3,600 RPM up to 7,200 RPM (50–60 revolutions per second). - Seek times routinely took about 100 ms just to physically position the arm over a cylinder. - Data could only be read in whole sector chunks (typically 4 KB) after rotational latency elapsed. - Relational tables and indexing were technological workarounds invented to conquer physical disk mechanics.
[50:42](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3042s) The Death of the Disk and the Illusion of Persistent Tables
Turning to the audience, Uncle Bob asks how many developers in the room have a spinning hard drive inside their laptop. Not a single hand goes up. He reflects that five years earlier, most of the room would have had spinning platters, while the two or three pioneers with solid-state drives would have been smugly sitting there while everyone else hated them; ten years earlier, nobody would have been disk-free. Now, mechanical disks are disappearing completely, not just from personal machines but from enterprise server farms as well. In their place is massive, linear, addressable RAM.
Uncle Bob challenges the fundamental premise of continuing to store business state in relational rows and columns when disks are gone. If developers possess a massive 32-bit or 64-bit address space of persistent RAM, the rationale behind relational mapping evaporates. In traditional enterprise development, programmers issue SQL queries, pull relational row sets into ADO structures, and then immediately execute an expensive object-relational mapping step: they unpack tabular data into linked lists, hash tables, and binary trees because those are the programmatic structures software engineers actually want to work with. Programmers want pointers, not joins and foreign keys.
Uncle Bob argues that the entire relational database industry faces obsolescence: “If I were Oracle I would be pretty scared because the reason for my existence is evaporating out from underneath me.” While acknowledging the deep cultural momentum behind SQL and the mathematical elegance of relational algebra, he notes that developers increasingly have access to virtually unlimited persistent memory where data can remain in native tree, hash, and list formats. He views the rise of the NoSQL movement not as an isolated trend, but as natural fallout from disks dying: “The NoSQL movement is born out of this notion that we don't need the discs anymore we don't need the databases anymore.” Binding an entire system tightly to a relational database today risks trapping that codebase in obsolete paradigms ten years down the road while the industry moves to far cleaner memory-native techniques.
[54:28](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3268s) Decoupling via the Entity Gateway Pattern
To insulate core business logic from storage mechanisms, Uncle Bob insists on placing a firm architectural boundary between them, representing it on his diagram with a prominent double line. Under this architecture, the database becomes a mere plug-in to the business rules, rather than the foundation of the system. He strongly condemns placing business logic into SQL stored procedures. While stored procedures have legitimate uses for maintaining data integrity or tracking back-pointers, using them to execute domain behavior is disastrous—he recalls with horror seeing a system where an entire mail-merge operation was implemented inside a SQL stored procedure.
To achieve clean separation, the use-case interactors interact with storage exclusively through an abstract interface called an **Entity Gateway**. The Entity Gateway contains pure domain-level query and command methods (for example, `getOrdersSince(date)`), completely free of database syntax. The business rules live on one side of the boundary, oblivious to whether data is stored in Postgres, Oracle, flat files, or an in-memory hash table. On the other side of the boundary, a gateway implementation maps those method calls into concrete SQL queries, communicates with the database API, and feeds plain domain objects back across the line.
```mermaid flowchart TD accTitle: Database Boundary and the Entity Gateway accDescr: Interactors depend on an Entity Gateway interface, making the database implementation a plug-in.
subgraph Core["Core Business Rules (Application)"] direction TB Interactor["Use Case Interactor"] IGateway["«interface»<br/>Entity Gateway<br/>+getOrdersSince(date)"] Interactor --> IGateway end
Boundary(("Boundary Double Line"))
subgraph DBPlugin["Database Plug-in (Infrastructure)"] direction TB GatewayImpl["Entity Gateway Implementation<br/>(SQL / ORM Mapping)"] Database[("Relational Database / Storage")] GatewayImpl --> Database end
IGateway -.-> Boundary Boundary -.-> GatewayImpl GatewayImpl --"implements"--> IGateway ```
Because dependencies point inward toward the business rules, the database is architecturally subordinate. Uncle Bob summarizes the relationship: “The database should plug into the business rules business rules should not be written anybody write their business rules of stored procedures in the database this is a bad idea we don't want to have SQL as our business rules.”
[56:31](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3391s) Fast Test Suites, Instant Feedback, and the Courage to Clean Code
A primary practical benefit of decoupling business logic from the database through an Entity Gateway is test suite execution speed. Real database access makes integration suites notoriously sluggish. By decoupling through an interface, developers can swap out the database entirely during automated testing, replacing slow database calls with lightweight in-memory stubs or fakes that return canned answers instantly. When stubs replace database transactions, thousands of unit tests can execute in microseconds rather than dragging out over minutes or hours.
Uncle Bob underscores that speed is a hard architectural requirement for a test suite: “One of the design imperatives for a test Suite is that it execute quickly and the reason for that is very simple if it doesn't execute quickly you're not going to execute it you're going to put it in some thing that is executed at night.” If tests take longer than two or three minutes, engineers stop running them locally during their inner development loop, deferring execution to nightly continuous integration runs or weekend builds. When tests run in seconds, they give developers instantaneous feedback.
This fast feedback loop changes the entire software delivery culture:
1. **Deploying on Green:** If a comprehensive test suite passes and developers truly trust its coverage, passing is not an ambiguous signal; it means the software is production-ready. The test suite effectively becomes the QA department: “One of the goals is to get the test suite to be the QA process test pass shipping and I mean literally if the test pass you deploy.” 2. **Fearless Refactoring:** Trust in a rapid test suite gives developers the safety net needed to continuously clean dirty code. When an engineer encounters messy code, they can refactor a small piece, press a key, see the green light within seconds, clean further, and immediately catch and fix any regressions. Uncle Bob sets up the psychological contrast: without an airtight, microsecond-fast test suite, developers look at ugly code and back away out of fear of breaking it.
- Any test suite taking more than a couple of minutes gets avoided and relegated to nightly CI runs. - Replacing the database boundary with fast stubs reduces test runtimes to microseconds. - A trusted, fast-running test suite is the single prerequisite that empowers engineers to clean legacy code without fear.
[01:00:12](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3612s) The Fear of Touching Code and the Power of Fast Tests
Uncle Bob reflects on the natural human reaction developers experience when looking at fragile legacy code: the immediate thought is "I'm not touching it," because touching it risks breaking it, and breaking it makes you the owner of that mess. He warns that once developers adopt this defensive posture, software inevitably rots. New features will be added and bugs will be fixed, but every single intervention will make the codebase worse over time because no one dares to clean it up.
The only antidote to this decay is having a suite of automated tests that you truly trust. With reliable tests, cleaning code becomes easy and costs nothing, because developers know instantly if anything breaks. Uncle Bob emphasizes that by decoupling business rules from heavy external dependencies like the database, test suites run blazingly fast—executing all core business rules in mere seconds, or at most a minute.
> “The only way to make it better is to have a sweet of tests that you trust and then it's easy then you make it better all you want and it cost you nothing” — Uncle Bob Martin
[01:01:16](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3676s) The Story of FitNesse: Deferring the Database Decision
Around 2002, Uncle Bob and his son started building FitNesse, a wiki tool designed to run acceptance tests written in HTML tables based on a framework Ward Cunningham had created in 1999. In the beginning, they assumed they needed a place to store wiki pages, which meant they needed a database. At the time, MySQL was essentially the only open-source relational database available. They prepared to install MySQL and design a schema, but realized they did not need it yet because their immediate problem was simply parsing wiki markup into HTML.
To keep moving without a real data store, they created a simple mock called `MockWikiPage` derived from the `WikiPage` base class. The `save()` method was mocked out to do nothing, allowing them to focus entirely on the `toHtml()` method for three months. Later, when test-driven development demanded fetching multiple pages, the team again considered MySQL. Instead, they opted to store pages in an in-memory hash table while keeping the same query and save interfaces intact. For an entire year, they developed the bulk of FitNesse without persisting anything to disk; tests passed, features grew, and life was good.
```mermaid flowchart TD accTitle: Evolution of Storage in FitNesse accDescr: Step-by-step postponement of persistence mechanisms across the development cycle of FitNesse.
subgraph Iterations ["Phases of Persistence"] direction TB P1["MockWikiPage<br/>(save mocked out, focus on HTML rendering)"] P2["In-Memory Hash Table<br/>(same query/save API, runs for ~1 year)"] P3["File-System Storage<br/>(implemented in 1 day by Michael Feathers)"] P4["MySQL Plug-in<br/>(client implemented in 1 day, eventually abandoned)"] end
P1 --> P2 P2 --> P3 P3 --> P4 ```
Eventually, testing the bootup sequence required actual persistence to load pages from disk. Michael Feathers suggested dumping the hash table into a rudimentary file-system structure rather than pulling in MySQL. He implemented it in a single day. Three months later, while using and demonstrating the tool on real projects, the team realized the file-system solution was more than good enough and abandoned the database altogether.
- FitNesse integrated Ward Cunningham's 1999 test framework, turning HTML tables green upon passing. - Storing pages in simple files offered an unexpected benefit: wiki pages could be checked directly into source control. - When an enterprise client insisted a year later that artifacts were "data assets" requiring a database, FitNesse's interface allowed the client to implement a MySQL adapter in a single day; the plugin was bundled with FitNesse, but nobody used it and it was eventually dropped.
[01:06:11](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3971s) The Core Role of an Architect: Deferring Decisions
Uncle Bob uses the FitNesse experience to illustrate a central tenet of software architecture: good architecture does not rush to make big decisions; it creates the structural freedom to defer them as long as possible. Deferring decisions allows software to be built in the absence of premature commitments, giving teams the chance to make those calls later when they have the maximum amount of real-world information.
While some fundamental choices (such as the programming language) must be made early, decisions regarding databases, message queues, and user interfaces can almost always be delayed. Even if an organization has spent millions on a vendor database license, developers should still architect the business rules as though the database is completely unknown. Similarly, starting a web application by typing `rails new` locks developers into a framework before the core business behavior is even defined.
> “The job of an architect is not to make decisions the job of an architect is to defer decisions as long as possible to allow the program to be built in the ab absence of decisions so that decisions can be made later with the most possible information” — Uncle Bob Martin
> “A good architecture maximizes the number of decisions not made and you achieve that by using a plug-in model” — Uncle Bob Martin
[01:08:19](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=4099s) The Plugin Model and Keeping Frameworks at Arm's Length
In a clean architecture, business use cases sit at the center, while user interfaces, databases, and third-party frameworks are treated as plugins that point inward. The inner business rules remain completely oblivious to external mechanisms.
```mermaid flowchart TD accTitle: Plugin Architecture Boundary accDescr: The core use cases and entities remain unaware of the peripheral plugin components.
subgraph Plugins ["Peripheral Plugins"] UI["User Interface"] DB["Database"] FW["DI & Web Frameworks"] end
subgraph Core ["Core Application"] UC["Business Rules & Use Cases"] end
UI -->|"depends on"| UC DB -->|"depends on"| UC FW -->|"depends on"| UC ```
Uncle Bob addresses the overuse of dependency injection (DI) frameworks, warning against letting annotations like `@Autowired` or large XML configuration files bleed deep into domain logic. When DI is scattered everywhere, debugging startup crashes or runtime binding errors becomes a nightmare. Instead, teams should only inject a small number of top-level factories or strategies—perhaps a dozen or two at most—and keep the injection logic confined to an outer plugin layer that feeds plain objects inward.
He cautions that developers must maintain strict boundaries around all third-party frameworks because framework authors have incentives that do not align with application developers. When you build your core logic around a framework, you make an enormous, irreversible commitment to it, while the framework author makes zero commitment to you and can break APIs whenever they see fit.
- Injection frameworks should inject factories and strategies, not raw domain entities or fine-grained business logic. - The use case core should never import or reference dependency injection annotations or framework libraries. - Framework authors are not evil, but they design tools for their own priorities, leaving developers vulnerable to breaking changes and vendor lock-in.
> “You don't want your use case code to know much about any framework why because framework authors are out to screw you” — Uncle Bob Martin
> “You make a tremendous commitment to that framework the author makes no commitment to you at all and the author will change the framework anytime the author feels” — Uncle Bob Martin
[01:10:51](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=4251s) Keeping Frameworks at Arm's Length
Robert Martin warns developers about the hidden risks of blindly committing to third-party frameworks. Mimicking a callous framework creator, he jokes about the vendor lock-in that ensues when updates occur: “Tough tough beans guys, I changed the framework and you are bound to me.” A skilled software developer must evaluate frameworks cautiously, understanding that the immense power they deliver comes with substantial costs. To avoid becoming captive to those costs, teams must keep frameworks at arm's length rather than letting them dictate the core structure of an application.
```mermaid flowchart LR accTitle: Keeping Frameworks at Arm's Length accDescr: Diagram illustrating clean boundaries between the application core and external frameworks. subgraph Core["Core Application"] Entities["Entities & Use Cases"] end subgraph Delivery["External Frameworks"] WebFW["Web Framework (e.g., Rails)"] end Delivery -->|"calls boundary interfaces"| Core ```
The cardinal mistake, Uncle Bob emphasizes, is mimicking the tutorials and quick-start guides written by the creators of those tools. Uncle Bob explains: “The most important thing about that is you do not want to follow the examples that the framework author wrote for you, because the framework author is perfectly comfortable coupling to his framework, but you should not.” Citing Ruby on Rails, he asks how a team could ever break away if they weld their business code tightly to the framework. A clean architecture ensures that if a tool like Rails ever turns into a bottleneck or organizational liability, the system can detach from it without requiring a full rewrite: “You should architect your system so that if Rails becomes a liability, it is not impossible to break away from it.” He then winds down the lecture, glancing at his contact slide and humorously announcing that it is late and he is ready for a beer before opening the floor to questions.
- Frameworks offer power and speed, but tight coupling transfers control of your release cycle and architecture to external maintainers. - Example code written by framework authors demonstrates framework features, not sensible boundary architecture for enterprise business logic. - An application's architectural independence guarantees that replacing an underlying web or persistence framework remains feasible throughout the system's life.
---
[01:12:22](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=4342s) Q&A: Stored Procedures, Entities, and Database Decoupling
An audience member asks about database boundary practices, noting that stored procedures are frequently employed below the repository layer to completely shield the underlying database from application programmers. Under this setup, developers are denied direct table access and forbidden from issuing arbitrary SQL queries. The attendee remarks that developers appreciate having clean calls, while DBAs appreciate being able to protect and control their relational domain.
Uncle Bob agrees with the premise and uses the question to clarify an architectural distinction regarding entity design. He points out that domain entities should never be thought of as one-to-one mirror images of database rows or relational tables. As Uncle Bob remarks: “One of the things I didn't talk about there was that the entities are not instances of database tables; they're usually constructions from many database tables and maybe some operations as well.” Because domain entities bundle behavioral operations and synthesize data across many relational sources, abstracting persistence mechanisms—whether through stored procedures, mapping layers, or repository interfaces—protects the business core from schema churn. With the question answered, Uncle Bob decides not to dive deeper into database mechanics, wraps up the talk with a cheerful exclamation of “Beer!”, and thanks the audience.
- Stored procedures can act as an access barrier, allowing DBAs to optimize relational schemas while preventing application code from executing direct SQL queries against underlying tables. - Entities in clean architecture encapsulate core business rules and behaviors; they represent synthesized domain concepts rather than 1:1 representations of relational database records. - Decoupling database storage mechanisms from entities ensures business rules remain unaffected by table-level schema refactorings.
## Notable quotes > [01:06:11](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=3971s) A good architecture maximizes the number of decisions not made and you achieve that by using a plug-in model — Uncle Bob Martin
> [01:10:51](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=4251s) You should architect your system so that if Rails becomes a liability, it is not impossible to break away from it. — Uncle Bob Martin
> [01:10:51](https://www.youtube.com/watch?v=o_TH-Y78tt4&t=4251s) you do not want to follow the examples that the framework author wrote for you, because the framework author is perfectly comfortable coupling to his framework, but you should not. — Uncle Bob Martin
## Mentioned Robert C. Martin, Mitochondrial Eve, Y-chromosomal Adam, Ruby on Rails, Spring, Hibernate, Ivar Jacobson, Object-Oriented Software Engineering: A Use Case Driven Approach, Trygve Reenskaug, Smalltalk, Microsoft, Visual Studio, JetBrains, ReSharper, Python, APL, PHP, Tcl/Tk, JavaScript, Oracle, SQL, FitNesse, Ward Cunningham, Michael Feathers, MySQL, Postgres
## Video description The Principles of Clean Architecture by Uncle Bob Martin (@unclebobmartin)
Robert C. Martin, aka, Uncle Bob has been a software professional since 1970 and an international software consultant since 1990. In the last 40 years, he has worked in various capacities on literally hundreds of software projects. In 2001, he initiated the meeting of the group that created Agile Software Development from Extreme Programming techniques and served as the first chairman of the Agile Alliance. He is also a leading member of the Worldwide Software Craftsmanship Movement - Clean Code.
He has authored "landmark" books on Agile Programming, Extreme Programming, UML, Object-Oriented Programming, C++ Programming and most recently Clean Code and Clean Coder. He has published dozens of articles in various trade journals.He has written, directed and produced numerous "Code Casts" videos for software professionals.Bob is a regular speaker at international conferences and trade shows.Mr. Martin is the founder, CEO, and president of Uncle Bob Consulting, LLC and Object Mentor Incorporated.
Uncle Bob has published dozens of articles in various trade journals, and is a regular speaker at international conferences and trade shows.
Mr. Martin has authored and edited many books including:
• The Clean Coder
• Clean Code
• Agile Software Development: Principles, Patterns, and Practices.
• Designing Object Oriented C++ Applications using the Booch Method
• Agile Principles Patterns and Practices in C#
• Patterns Languages of Program Design 3
• More C++ Gems
• Extreme Programming in Practice
• UML for Java Programmers
http://www.meetup.com/Norfolk-Developers-NorDev/events/223533655/
[Source](https://www.youtube.com/watch?v=o_TH-Y78tt4)