DEV Community

Cover image for Conceptual Contours
Jim McKeon
Jim McKeon

Posted on

Conceptual Contours

Domain Excavation

Because it requires constant discovery and refinement, building software is much like excavating a buried house. One requirement exposes a section of wall. A bug fix reveals a doorway we hadn’t accounted for. A conversation with a user turns up a hearth or a pottery shard. Gradually, the pieces begin to suggest architectural features yet to be discovered: rooms, connections, and the activities they supported.

Recognizing the architectural whole changes how we understand the pieces. A wall has a purpose in relation to the rooms it separates; a doorway tells us how those rooms connect. Each discovery helps us interpret what we’ve already found and gives us a better idea of where to look next. Of course, none of this happens if we're not looking for the structure to begin with, via a "house-seeking mind".

After several years of daily software development and maintenance, I started getting the sense that there was something there beneath all the switch statements, loops, and if/else branches. A concept, a process, sometimes a physical object that my code was outlining (and often mangling beyond recognition).

More importantly, I suspected that if I could identify that thing and align the code with it, subsequent requirements and fixes would be easier to accommodate. I was certain that each change and fix had a natural "home", a place where it conceptually belonged.

As Eric Evans puts it in the "Conceptual Contours" section of The Big Blue Book, "there is a logical consistency deep in most domains, or else they would not be viable in their own sphere".

Intuiting Contours

Most applications need to store and retrieve data, handle concurrency, and report failures. StubHub, Netflix, Spotify and NASDAQ all have to read and write data across services and databases, validate input, and manage concurrency. However, none of them have to worry about how to split a restaurant's tip pool, calculate the cost of parking when a car leaves the lot, or how many seats to sell beyond a flight's capacity. Very often, the complexities of the business the application models are what make it uniquely challenging. Best practices for EF Core, REST semantics, or tracing a request across physically disparate microservices can be googled. Design guidance for a specific customer's seasonal pricing, handling, and shipping rates can't be.

The “something there” I sensed beneath the loops and branches was the model, the inherent structure of the business, bursting at the seams. DDD helped me bring it into focus—and give subsequent changes somewhere meaningful to belong.

As programmers we're primed to focus first on technical matters. However, when technical concerns dominate the conversation, it’s easy to make progress on the mechanics while leaving the business problem poorly understood. The code can become technically elaborate while the rules it exists to implement remain obscure. As Evans puts it, to skillfully design a solution to a business problem, we must "temper [our] technical thinking by frequently touching base with [our] intuition for the domain".

Aligning code with the contours of the business also makes it easier to think about. So much of the mental effort in development goes into translating between what the business does and how the software represents it. We encounter grouping, sorting, counting, and arithmetic, expressed through inheritance, lambdas, and closures, and have to reconstruct the business meaning before we can even consider whether it’s correct or how to modify it. A promotion like “buy two, get one free” can disappear into those mechanics. When the code explicitly models that promotion and its rules, we can hold it in mind as a recognizable business concept. Less of our attention goes into figuring out what the code means, leaving more available to reason about what it should do.

Recognizing the Contours

Technical refactoring can help us express that understanding, but extracting methods or splitting classes doesn’t necessarily produce it. We can make the code tidier while leaving the business concept just as obscure.

How do we recognize those contours as we uncover them? One guide Evans offers is to ask which distinctions matter to the people the software serves.

In his paint-mixing example, users combine whole paints. They don’t need to manipulate the individual pigments. A model for paint chemists might need those distinctions, but introducing them into the mixing application would add detail without helping express the work its users perform. The domain gives us a basis for deciding what to keep together and what to separate.

Our understanding of those boundaries develops as the software changes. A new requirement may reveal that two rules we grouped together actually vary independently. Another may expose the same business concept implemented in several places. These changes provide evidence about the shape of the model. Evans’s “shearing patterns” give us something to observe: where the design pulls apart as our understanding grows.

That connects back to the excavation. Each discovery can change our interpretation of what we’ve already uncovered. Recognizing a doorway changes our understanding of a wall; recognizing a business policy can change how we organize several apparently unrelated conditions, or better yet, anticipate rules and conditions that have yet to be uncovered.

The “house seeking mind” matters throughout. As requirements, conversations, and bug fixes expose more of the business, we have to keep asking how those discoveries fit together—and let the code reflect what we learn.

Top comments (0)