Chapter 14

Notes 20 January 2004
Domain Driven Design (VIII)
Guest Author: Eric Evans

Russ: Let's start with Strategic Design (Part IV) -- what do we need it for? How about considering the ways to get in trouble on the extremes. How do you look at a system and understand whether we're doing what Eric's doing, or one of the bad alternatives he discussed. (p. 328, halfway down). The more systems I see, the more surprised I am by the range of systems I see. Some of it's really good, some of it's kind of scary. This was a good way of describing a large class of the problems, so I thought it was a good way of introducing tonight's topic.

(Russ referred to text in second half of second paragraph p. 328, "monolithic" vs. "ad-hoc", avoiding extremes).

Dave: Systems glued together out of lots of pieces are also often full of contradictions, an unresolved argument about the system.

John B: Like Unix command-line tools, having varying views of the world?

Russ: Is it ad-hoc components, or ad-hoc interfaces?

Mike: the alternative being an enterprise-wide bus, a common interface for things to plug into, that tries to be everything to everybody. It's hard to get systematic designs through, because you have many sponsors and many forces.

John B: And you have to actually establish the protocols, how to get things to communicate.

Mike: My company has tried for the system-wide bus, and it seems to address the needs of only a small number of the people who want software.

Russ: The author is talking about more than just the technical breakdown of the system, but about the model, the vision of the system.

Eric: Dave said an interesting thing about small pieces composed together being sort of a dialogue or debate about world views of the system. That is very much about what Chapter 14 is about.

Phil: A middle approach to bridging the extremes is to compose the pieces, then to look at what you have, and refactor the composition into the thing it needs to become.

John B: I see on p. 389, there's a discussion about refactoring to Shared Kernel from Separate Ways,

Eric: Refactoring is the *means* by which you change strategies, rather than the strategy you use.

Phil: Refactoring as using the code to change your ideas, you don't see that as well as refactoring as a mechanism?

John B: Eric has listed all the ways to evolve and change the implementation of the model that he can think of, rather than the actual change of the model as ideas.

Eric: All the ones I wanted to recommend.

Tracy: If I understand, Phil, you're talking about refactoring as a process of understanding.

Phil: Yes, learning, and eventually you get to a global view, a similar result. The code is telling you what the model has to be.

Eric: I'd like to shift rails a bit, I start from a more fundamental premise. I start from an observation that on any large project, with more than 10 people, you will have more than one conception of the domain that the system is based on. More than one conception means more than one domain model, and that will affect choices about design. You can just plunge ahead not realizing that, and not realize when one person's concept was controlling the design and when another person's different concept was. So that's where BOUNDED CONTEXT comes in. You would like to have a sense of which model applies in what part of a larger process. There is sometimes a very clear situation, where you have smaller subsystems worked on by different people, and each can be its own model, its own context. But with a large subsystem, you're more likely to end up with multiple inconsistent views. This chapter is about understanding that there are different points of view, and different ways to describe things, and that becoming aware of these different perspectives is important in dealing with larger systems. The "Blind Men and the Elephant" story would be less interesting if each blind man knew that he had a separate point of view on the same thing. And we want things to be less interesting in this case, with software development. So you want to start out by mapping out the territory as it exists, before making changes. So tactics like CONTINUOUS INTEGRATION support the decision to have a unified model within a single BOUNDED CONTEXT. This sort of CONTINUOUS INTEGRATION is the code, *plus* people consciously synchronizing their concepts with one another through exercise of the UBIQUITOUS LANGUAGE. But there are other successful ways of connecting things.

John B: System model vs. domain model? Most of these patterns, to me, seem like ways to integrate a system rather than a domain.

Eric: Usually people think of system integration as connecting a set of distinct programs. But you could create two systems based on the same domain model. Or you could create a program which was internally split between two domain models. You'd prefer to split your components along the boundary of the variant models. But I've seen components and subsystems (even classes!) with multiple models reflected in their implementation.

John B: Is Extreme Programming's continuous integration a different concept from yours?

Eric: I think it is the same thing. The XPers are exactly correct about continuous integration with a context, within a single model conception. If you need it to interoperate, you need continuous integration of the *code*, and also of the *model*.

John B: They're fumbling that direction with the System Metaphor.

Eric: And co-location.

Phil: And pairing.

Russ: I've seen a single developer with 3 different bounded contexts with name clashes in the same source file.

Eric: Three *unbounded* contexts.

Russ: Intermingled contexts.

Eric: If they had bounded those three, they would have been in good shape since they would have been separate; or more likely they would have unified them to remove the contradictions. But knowing what the practices help you achieve, knowing *why*, allows you to adjust to situations, to know where you are at. And knowing when to stop. You can't CI a whole company, you can't co-locate everyone. And at a certain scale, the overhead of continous integration in a large system becomes too much. So by making a context map, you tell yourself, your teams, where you are making CI work, where you can run XP full-out within a single bounded context, and where you want to establish a boundary.

Russ: There are two very different notions going on here. 1: You and I have different models of a system, with shared understanding of a subsystem, and no assumptions about the non-overlapping parts -- two separate but possibly overlapping models. Vs. 2, if you and I were working on things, and there was an overlap of concepts which were not part of the shared kernel, but were in conflict. It's an interesting distinction to talk about.

Eric: Yes, that's a very instructive example. So in the first case, let's say there *is* a shared set of concepts. What I call SHARED KERNEL. That's both concepts and code.

Russ: So if you were working on the dessert and I were working on the floor wax, we wouldn't have to interact on those distinct parts of the system.

Chris: Until someone comes up with a product which is both dessert and floor wax.

Eric: So in this case, you might subclass the thing we've already got in hand, say for me working on the dessert, I'd say a floor wax is a special kind of dessert, and you with the floor wax, you'd say a dessert is a special kind of floor wax.

John B: Elephant is a subclass of wall, floor, snake, tree, and rope. (p. 379)

Eric: The blind men were lucky, that they were each looking at a single part of a larger system. But with desserts and floor waxes, the systems are more complex. At first we might not have any problem. One way is we can say we go with your model, one way is to go with my model, or one way is to come up with a new model that meets everyone's needs. Let's say we introduce a new abstraction.

John: They're both Sprayables.

Eric: So we've discovered both the dessert topping and the floor wax are sprayables.

Dave: It opens up new product opportunities because you could make something that's a floor wax, dessert topping, and bug spray.

Eric: I think the marketing department would have trouble with that last one.

Jeff: Maybe lip gloss as something in the same unified space as floor wax and dessert toppings.

Russ: How are we making these trade-offs to decide how much of the system should be unified?

Eric: It's not always unification. you might have a system that's grown to the point where integration has become burdensome, so you decide to split things off and go separate ways.

Dave: As things scale, I've never seen it be easy to abstract a core.

Chris: Could you abstract out a framework?

Eric: I'm not talking about a huge company with a "chief architect" someplace dictating to everyone in the company "these are the objects you'll use."

Phil: During the development of J2EE at Sun, different groups had a concept of "qname" that was slightly diffferent. We got everyone in the same room and agreed on a common interface that everyone could use, and we created a JAR with just qname in it that everyone could use.

Eric: That's a Shared Kernel.

Phil: Right, and it's a little thing, not a big one.

Dave: What was the overhead involved in getting all the interested party together in a room to make that decision?

Phil: You have no idea.....

[...]

Eric: The first thing is to have contexts that are bounded. And have a map so you can say, "This thing belongs to this context."

John C (?): What about the tragedy of the commons problem, since the shared parts...?

Eric: But all we're agreeing on is the _boundaries_.

John B: "Good fences make good neighbors."

Jeff: Get that down.

Eric: You want to know, "Am I in my own context, where I can go my separate way, or am I in a shared context where I need to integrate with someone else?"

John C: I'm thinking of a company where there are two products, one of which is a big revenue producer, and another that gets less resources. The one that makes a lot of revenue basically gets to disregard the needs of the other one.

Eric: That sounds like a case for Conformist, because of the power differential.

Eric: I'm not saying the company has some global enterprise-wide context map. I'm just saying for your own project, identify the different contexts there.

Eric: Even in a one-person project, you'll have multiple contexts, like "current understanding", vs. "last years understanding". (The code you wrote last year, but haven't had a chance to refactor to your latest insight.)

???: What about upstream/downstream suppliers where one is stuck with a supplier.

???: "Ball and chain" pattern.

(Mike: discussion of a protocol with a large installed base with messaging to distributed clients -- difficulties with changing the protocol to enrich the service.)

Eric: So your clients have a presumption, a model for what the messages in the protocol mean. And how they handle the messages reflects that model. If they get back a response message in a different format than the one they asked for, then they have to handle that. They have to handle the fact that the variations in the new model are exposed by the new protocol. So what made this hard is that within your context, you changed your domain model, but the other systems at the boundary are related to you via an OPEN HOST SERVICE. The interface expresses a frozen model.

Mike: Because so many groups are connected to it.

Eric: And part of the problem was a change in the model as expressed in the protocol. If you had just made a slight re-arrangement of the same information, it would be no means as difficult. There's a technical dimension to the problem, but there is importantly, a conceptual one. And the conceptual difference is what it makes it hard.

John B: Sounds more like ANTICORRUPTION LAYER rather than OPEN HOST SERVICE.

Mike: We have an invariant API.

John B: If you had an ANTICORRUPTION LAYER, you would be able to fold the new protocol into the old one.

Eric: But let's say he is getting his message data from somewhere else, a legacy system. So what he does is set up an ANTICORRUPTION LAYER to translate the old stuff into the new, enhanced model. But it's the client-facing side, he's got clients who are asking for stuff. There might be a few with ANTICORRUPTION LAYERs because they need to express the concepts of the message internal in unusual ways, but most of them use CONFORMIST, expressing his message stream in the same terms.

Mike: We want to enrich the service without affecting the clients who are not interested in / capable of dealing with the information in the new protocol.

Eric: They've always had Sweet 'N Low before, but you want to give them sugar.

Russ: You can give them more feeds, by establishing a an upstream message feed that you can translate into Sweet N' Low for the old clients, and to Splenda for the new clients. (Arranges two diverging lines of pens and flatware with a pink paper packet in one line of the V, and a yellow one in the other line).

Eric: OK, so I understand you have a TRANSLATION LAYER which takes the new, enriched internal format and emits a message feed in the old format for your established customer base.

Eric: There's a stress point on the OPEN HOST SERVICE pattern. If you have two sets of clients who want different services, it's somewhat difficult. OPEN HOST SERVICE says that everyone gets the same thing, everyone can accept the same protocol. So if your situation is that each customer wants little, extra bits on the service, perhaps you want a bunch of one-off translators, one-off versions for the different groups, to keep the primary protocol simple and clean. Now we end up with more of a classic CUSTOMER-SUPPLIER relationship for the custom parts of the protocol. That frees most of the clients from dealing with the special interfaces, and the individual special needs can be managed without changing anything about the common assumptions.

John B: You have an off-the-rack interface, and then a set of tailor-made ones.

Eric: But you want it recognized that that's what you're doing, that there is a decision process being made.

Chris: The more I'm listening to this is more like a pattern I applied in a system I worked on. In this case, the requester specifies the format. If they didn't specify, you got the old format. If you needed something new, something else offered by the current system, the client would change their format specifier.

Charlie: Do some of the specializations, some of the customizations really belong on the client side?

Eric: If you're using OPEN HOST SERVICE, you need to keep it simple and consistent for you as the maintainer. For variations, you may choose to make a special adaptation, negotiating it one at a time based on company priorities or revenue, etc. If you have a custom protocol that only *one* customer can use, you can change the interface as often as your two groups agree to. Once there are multiple clients of the protocol, it's far, far harder. It's the OPEN HOST SERVICE situation, where the interface is frozen in place.

Darlene: At what point might you go toward a general solution, a new protocol with the space to accommodate a new set of variations? Rather than maintain half a dozen variations on the common protocol?

Russ: Maybe we should define ANTICORRUPTION LAYER, we've used it several times.

(p. 364, ANTICORRUPTION LAYER: picture of the Great Wall of China)

John B: I'm seeing this adapter-service thing, that's a lot like...

Eric: I use the terms TRANSLATION LAYER and ANTICORRUPTION LAYER. An ANTICORRUPTION LAYER is certainly a TRANSLATION LAYER. It's the difference in intent, in posture, that makes the difference. An ANTICORRUPTION LAYER defends your system from having to adapt to a divergent external model. I don't think you could mechanically tell the difference. But it's the difference between a wall and a bridge, almost. A bridge is like a regular TRANSLATION LAYER, where one side is reaching out to the other, or both to each other. An ANTICORRUPTION LAYER is protected, a wall, a moat, and a gate. You don't have an ANTICORRUPTION LAYER separating you from a protocol that you designed.

Russ: Maybe a protocol you designed in the past, that you don't want to work with any more.

Eric: With ANTICORRUPTION LAYER I make stronger statements about why you're doing it. It's that you are protecting your model from the concepts on the other side. The concepts on the other side of the wall will mess you up if you have to try and deal with them.

John B: Not just corrupting data, corrupting your model.

Eric: Your way of thinking. There isn't a functional distinction between the two.

Mike: The OO-SQL translation layer as one example of trying to bridge the gap.

Eric: An ANTICORRUPTION LAYER is one-sided, built by one side to protect itself. Vs. the Chunnel, a cooperative effort by the British and French to bring each other together.

Mike: You could think of an O-R persistence layer as an ANTICORRUPTION LAYER if you have to adapt to an organizational standard which interferes with how you can deal with things.

John C: A Cartesian to radial coordinate translation.

Eric: More like where you have Cartesian coordinates on one side and on the other, a tribal society which describes how to find things by how many days' walk between locations, considering weather conditions, and refers to locations by their historical association. You would want to protect the clean, simple Cartesian model from the complex expression of locations on the other side.

John B: So let's say you have an RDBMS with transaction scripts talking to a database. That's where you might put a translation layer to protect the database?

(some additional discussion of ANTICORRUPTION LAYER vs. TRANSLATION LAYER in different contexts)

Mark: Web pop-up blockers are an ANTICORRUPTION LAYER.

John B: They protect you from the advertisers' protocol.

Eric: By doing complicated gymnastics inside the browser. If you provide a compatible interface to protect your clients from changes, that's being nice.

John B: It's like being CONFORMIST to a layer that keeps squiggling out from under you, you conform to what the ANTICORRUPTION LAYER presents and adapt to the changes inside that layer.

Eric: If the old model is nice and clean, if it isn't a conceptually difficult translation... unless there were no longer a straightforward relationship between the new model and the old model, it's not something where the service is protecting yourself. I don't think that offering a

Russ: Insulation but not anti-corruption.

Eric: But if the old model were a BAD one, incompatible, a messy, complex translation from the current system's model, then perhaps it is an ANTICORRUPTION LAYER on an outward feed.

Tracy: Maybe I can make a point that will help. So let's say the new internal model is the brown sugar. So if the guys that wrote this offer a new interface that's sugar, and doesn't offer the interface of Sweet N' Low, then the client might build an ANTICORRUPTION LAYER to defend themselves from the incompatible new interface.

Russ: So if the motivation is trying to protect your old clients by offering a translation layer to a protocol they want, it's different from...

Eric: Yes, the attitude is different.

John B: It's where there is a meeting of minds (TRANSLATION LAYER) vs. no meeting of minds, a disagreement (ANTICORRUPTION LAYER).

Charlie: The word "corruption" is subjective itself, it depends on point of view.

(some additional discussion of ANTICORRUPTION LAYER to attempt to clarify its usage)

p. 371, SEPARATE WAYS

Phil: I love the picture for SEPARATE WAYS. You see all those team rowboat pictures in those motivational posters. Seeing that picture of that one guy in the rowing shell really captures the feel.

John B: It's like a standalone context, like your earlier discussion of STANDALONE CLASS.

Eric: Yes. But separate contexts may introduce duplication. If you have separate contexts, you can have duplication. But not sharing.

Russ: It's positive danger to share things between contexts.

Eric: Unless you have a SHARED KERNEL.

Mike: Does SHARED KERNEL drive you to use CONTINOUS INTEGRATION? Or another specific process to support the SHARED KERNEL.

Eric: Yes, if you have SHARED KERNEL, you have a process that needs to support it. CONTINUOUS INTEGRATION is an example of one process that could support it, but it's not the only way to do it. Frequent integration, appropriate to its rate of change; having each side supply some test cases, and each side runs all the shared, compiled test cases. I wouldn't recommend in more detail than that, but you do need a process.

John B: So you might have meetings or pow-wows between the teams sharing the SHARED KERNEL, to negotiate the interface changes, where an XP team would just go bam, there the interface changes.

Eric: *Within* a context, you can use full-on continuous integration.

Charlie: Does a SHARED KERNEL tend to be more stable than the rest of the system?

Eric: Sometimes, but not necessarily. Sometimes it has the most change at certain phases of the project, although it has more inertia from the multiple forces depending on it. You've traded away some agility.

John B: You need these patterns in order for XP to work, for changing the system to make it better?

Eric: The assumption that change makes things better is implicit to XP.

Chris: Does the way that XP works, that you surge forward, changing the model, in a couple of different contexts. Does that make integration of two divergent teams' work difficult at a later point? The lack of detailed design documentation?

Phil: Just read the tests?

John B: The tests will get you a long way. All the translations will have to be green-bar preserving.

Russ: That's where you encounter the greatest risk of the tests becoming irrelevant. When the model changes, the tests may be making irrelevant assertions. Incorrect assertions.

John B: The unit tests, yes. Not the acceptance tests. They reflect knowledge of the domain.

Eric: But those acceptance tests contain some assumptions about the model, they exist within a context. If the model changes slightly, what the acceptance tests express may be subtly different.

Jeff: Perhaps if the acceptance tests were expressed in different units, they might be able to be consistent within a larger framework. Say more detailed units of time or money or something. That you could translate the acceptance tests into a common larger perspective, but the new perspective might have lots of holes in the acceptance test coverage.

John B: But how do you do this in the context of a non-XP team? You have a document, maybe, but it doesn't reflect how things really are.

Phil: How things used to be, how things were supposed to be, how we thought the system was going to turn out.

Chris: Even if those two documents were inaccurate, they are marker points to bring up subtle points that people might forget. But they provide a place to start talking, a guide to find out if the two kinds of apples we're trying to merge are really two kinds of apples, rather than apples and something else.

Chris: To the extent you can automate the documentation (TogetherJ was mentioned)

John B: Supple design assertions, what's the invariant for an apple? Those can really help you reveal what the common points of view are between two models.

Russ: Sometimes it's how the actual artifacts of the code relate drives you in a direction. What Phil was saying earlier about refactoring driving you toward better understanding of how things were being used. When the problem is too big to hold in your head.

John B: The problem is not the technical issues so much that there is my model and your model, and clearly my model is better than yours, and there are two sets of (mine, yours) in the room. The difficulties are more sociological than technological.

Russ: But maybe we aren't even at this point. We have to decide whether the models have any correspondences where we can extract some common point of view. Using diagrams, pictures, descriptions, etc, to see if common points of correspondence occur.

Charlie: I was once a "swamp guide" for new hires at my company. There were lots of questions about certain idiosyncrasies in the code which related to evolution in the company's business model without the objects being changed to reflect the new point of view.

John B: The context of "now and then".

Eric: Similar to Mike's issue with the different messaging protocols. He had to deal with the protocol based on "then", and the internal model based on "now", and facing the challenge of how to get more "now" into "then".

p. 388: a diagram grouping the "context" patterns in relationships, from SEPARATE WAYS at one end (need no control of other systems, no communication) to Single BOUNDED CONTEXT (need high control, high communication).

Russ: Even on our small team, we have three different contexts in which there's a "Book" object

Eric: (discussing the diagram) But CONFORMIST has no control and requires high communication. ANTICORRUPTION LAYER is somewhat similar. Then there's a break to a set of patterns which require greater integration, greater control over other systems and more communication about internals... CUSTOMER-SUPPLIER TEAMS, OPEN HOST SERVICE, SHARED KERNELs are partway along toward the single BOUNDED CONTEXT.

Russ: You're really nice to XML on p. 376.

Eric: I wrote that back in the glory days of XML. We're all a little disillusioned these days. I really wanted to talk about XML as a stimulus to create common languages for interchange.

Eric: The E-commerce enthusiasts for XML as the magic bullet are not realizing that the really key thing is the common model. The problem isn't getting to a common syntax. With a common model, you can reach a common syntax fairly easily.

John B: The fact that there's a common syntax, a common way of parsing it did help take some of the syntax and formatting issues out of the way.

Russ: XML helps you with the easy problems, but not the hard ones, the conceptual meaning of the marked up object. Here's a price with a dollar value. But does it include tax? Not? How are you allowed to interpret this value you've been given, <price><value unit="USD">50</value></price> ?

(brief discussion of XML web services design, what might make it supple, will good designs win?)

Eric: p. 378, Notice the UML diagram is more compact than the poem!

Mark: What about the second and fifth guy?

Eric: Oops! Guess that was enough to make the point.

<!-- InstanceEndEditable -->