10
Applying the Principles, Practices, and Patterns of DDD

WHAT’S IN THIS CHAPTER?

  • How to sell Domain-Driven Design
  • Applying the principles and practices of Domain-Driven Design to your project
  • Understanding the importance of exploration and experimentation in the quest to find a useful model
  • Why avoiding ambiguity will greatly improve your modeling efforts
  • Removing the complexities of technology when problem solving
  • Why you shouldn’t worry about the perfect domain model
  • How you know when you are doing it right

Wrox.com Code Downloads for This Chapter

The wrox.com code downloads for this chapter are found at www.wrox.com/go/domaindrivendesign on the Download Code tab. The code is in the Chapter 10 download and individually named according to the names throughout the chapter.

Over the previous nine chapters, you have gained an overview into the philosophy of Domain-Driven Design (DDD). This chapter brings all of that knowledge together to show you how you can start to apply the principles and practices of DDD to your next project. The remainder of this book focuses on coding patterns to produce an effective domain model in code, integrate bounded contexts, and architect maintainable applications.

Selling DDD

DDD is not a silver bullet, and it shouldn’t be sold as one. In the same way that following an agile methodology won’t solve all of your problems, neither will DDD; however, it is a powerful and extremely effective philosophy when used in the correct circumstances, such as these:

  • You have a skilled, motivated, and passionate team that is eager to learn.
  • You have a nontrivial problem domain that is important to your business.
  • You have access to domain experts who are aligned to the vision of the project.
  • You are following an iterative development methodology.

Without these key ingredients, applying the principles and practices of DDD will overcomplicate your development effort rather than simplify it. However, if your particular circumstances meet the preceding list, then applying the principles and practices of DDD can greatly increase the value of your development effort.

Don’t sell DDD as a project methodology; instead, understand and apply the principles appropriately and where you can gain value. Just as design patterns are best arrived at when you refactor, the principles and practices of DDD should be used only when necessary, and with each on its own merit. Apply any technique judiciously and only when you can gain an advantage and it can give you value.

Educating Your Team

When communicating the philosophy of DDD to your team, focus not on the pattern language but instead on the alignment with the business, the importance of strategic contexts, and the focus on language used to describe a model. The principles and patterns of strategic DDD are far more powerful and useful than the tactical patterns. A team focused solely on the software patterns will miss the true value of DDD and will likely pay the cost of applying the practices without reaping the rewards.

Technology is not the solution to business problems; it is merely an implementation detail. Problem solving is achieved through collaboration with domain experts who hold the key to discovering a useful model. This model is brainstormed on cards or a whiteboard before being implemented in Visual Studio (or your favorite IDE). Remember: Technology can complicate problem solving; focusing on an abstract conceptual model free from the clutter of infrastructure and technical concerns will enable teams to build a solution that communicates the intent of the domain and can be understood by the business.

Speaking to Your Business

Your business stakeholders don’t want to hear about the next new development philosophy or methodology; they just want you to deliver value for them. Agile, Service-Oriented Architecture (SOA) and the cloud have all been overhyped, promising to solve all development problems but failing to do so. Instead, talk only of your desire to learn more about the business you work within to give more value. Talk of the need for the development team to be more aligned to the vision and intent of the business. A stakeholder will see the value in the development team spending time with business experts and aligning themselves to the expectations of the business.

DDD does not work without the commitment of domain experts. If you can articulate the importance of having an expert from the business available to your stakeholders, you are setting yourself up to succeed. Of course, you are free to talk to your stakeholders about DDD, but it’s best to focus on the need for collaboration. The success of a product falls on the commitment level of the business and its experts; this is how you sell DDD. Empowering a team with a deep understanding of the problem domain logic enables it to produce a better product.

Applying the Principles of DDD

With a business that understands the value of a domain expert’s time and a development team that is focused on driving a solution to a complex problem around a model of the domain created in collaboration with a domain expert, you will be in a good position to apply the principles of DDD. This section details the stages of project inception to developing a solution, and which practices to use when. However, the key to applying DDD is to start simple. Do the simplest thing possible until you encounter complexity or ambiguity. When you find ambiguity during conversation, explicitly define it within the ubiquitous language (UL). When your model is becoming too large, decompose the complexity and apply the strategic patterns of code organization and modeling techniques. If you keep things simple and arrive at applying the principles and practices rather than trying to crack a nut with a sledgehammer, you will get immense value from DDD.

Understand the Vision

Before capturing requirements, it’s important to align your team with stakeholders’ expectations. Start a meeting with a stakeholder by asking open questions that draw out the reason you are opting to build rather than buy a product, and that help to explain the vision of the product. The following questions are powerful:

  • What is the business goal/driver for this product?
  • What value will this product bring to the business?
  • How will you know if this is a success? What does good look like?
  • How is this different from what has been done before?

By listening to the stakeholder answering your questions, you can identify the most important part of the product—the area of the software that is the fundamental reason you are building it. Capture this information and create a domain vision statement that aligns your team to a common goal. Your team needs to understand what will make or break the product, what is essential, and where the value is.

During the meeting, you may discover that the product is not special and is in fact a generic solution that just happens to be more cost effective to build in-house. If so, make that explicit, and understand its importance to the business and its future. It could also be the case that this is a fail-fast product—a prototype to test the appetite of customers. These insights will enable you to understand where the value lies and what the business is trying to achieve. With this understanding, you can determine if all the practices of DDD are going to be effective for your project.

Once you understand and share the intent of the product and the stakeholders’ goals, you can capture the features of the product while always aligning to the overall vision of the product.

Capture the Required Behaviors

An effective way to engage stakeholders when gathering requirements is to apply the behavior-driven development (BDD) methodology. BDD is a shared language that helps you capture the behaviors of a system. You can think of it as a UL for requirements. It enables your team to understand the requirements from your stakeholder from a nontechnical perspective. The practice of BDD and the focus on capturing requirements in a language the business understands and which explicitly shows value is a great exercise in demonstrating the power of a shared language to aid communication. This process helps to educate the team on the power of language and the evil of ambiguity in meaning. Use these sessions to explicitly define terminology. This exercise will warm up the team members for when they collaborate on a UL to describe the model that will implement the rules, logic, and processes needed to satisfy the system’s behaviors.

What you are capturing from the stakeholders are use-cases, inputs, and outputs. These business use cases form your application services. If they are complex, they drive the decision on what domain logic pattern you will implement. During requirements gathering, focus on what the stakeholder wants, when, and why. The why part is essential. Asking the question helps to validate why the stakeholder wants what he says. During the requirements stage, stay in the problem space, and focus on the opportunities that this product is going to bring. How you are going to satisfy the requirements can wait until you understand and share the vision.

I have seen many teams rush through requirements, eager to jump to a solution without fully exploring the problem. Don’t jump to a solution too quickly; ensure that you explore the problem space with your stakeholders. Often, stakeholders are unclear on exactly what they want. By exploring the problem space, you can draw out the real business need and often offer better behaviors before wasting time on solutions to needs the business doesn’t really have.

As you start to generate story cards full of features, you may find that the size of the product is becoming too big to manage or ambiguity is occurring in the problem space. You might also be losing sight of the bigger picture and the core reason that this product is being built. When this occurs, the problem space needs to be distilled.

Distilling the Problem Space

If you find that the problem domain is becoming too large to manage, you can ease cognitive load by abstracting the problem to a higher level by creating subdomains. It’s useful to look for the capabilities that support the product and create subdomains from these. Business capabilities are the activities that support a business process; look for these activities outside of departmental structures or functions. Some will be generic, some supporting. The ones of real interest that will make or break the product are the core domains.

Focus on What Is Important

When you have decomposed your problem space, ensure that you spend the majority of your time with stakeholders understanding required behaviors for the core domain. Your core domain may very well be small, which is fine. Pay particular attention to conversations in this area, because they will be the most interesting and offer the most value to you. The core domain should directly support the overall vision that the stakeholders have; if it does not, you may have incorrectly identified the core domain, or you may need to clarify the vision with your stakeholders.

Understand the Reality of the Landscape

With a thorough understanding of the problem space and an alignment on where the value of the system is, you can start to model a solution. However, before you start creating a solution to any project, it’s of utmost importance to understand the environment that you will be working in. Understanding the state of the software solutions already in production is essential to making informed decisions on how you will integrate your product. The best way to capture the landscape is by creating a context map.

The team needs to identify the different bounded contexts in play that will directly affect or be affected by your product. The team needs to identify how these contexts interact, what protocols they integrate through, and what data they manage. To achieve this, follow these steps:

  1. Determine what models the team is aware of that directly affect or will be affected by the problem area. Draw these contexts, name them, and show who is responsible for them. If you are not sure where to start, look at the organizational structure of the domain you are working in, because most systems are built around departmental communication. Then look at the development team structures.
  2. Map the integration points and methods of integration.
  3. Map the data that is exchanged and who owns it.
  4. Label the relationship between the contexts. Is your team downstream and reliant on another team? Or is your team upstream and must communicate changes to other teams downstream from it?
  5. Rinse and repeat until you have captured all that you can about the landscape you will be developing in.

The whole team must understand the context map. Hang it on the wall for all the team to see and other teams to understand. This is your war map. It should be simple enough for all to draw quickly, so don’t spend too much time on UML diagrams. Instead, get a bird’s-eye view, and as you start to integrate, zoom in on touch points and then go into detail.

Modeling a Solution

Before starting to model a solution and applying the principles of DDD, you need to ensure the product you are about to provide a solution for meets the following criteria:

  • Is a complex problem or has complexity in a subdomain
  • Is important to the business and has high expectations of it
  • Has accessibility to a domain expert
  • Has a motivated and smart team

If you don’t have a complex problem or a portion of your problem is not complex, then building a domain model may be overkill. When there is little logic and merely data manipulation, you should follow a simpler method to manage domain logic, such as transaction script or active record. That way you can avoid some of the more costly practices.

If the product is not important to the business and there are low expectations, it’s probably not worth the effort of building a solution to stand the test of time. Build good enough and build for replacement rather than investment. You can try and utilize an off-the-shelf solution. If your problem is generic there may well already be an open source solution out there that fits your needs.

If you don’t have access to a domain expert, discoveries in the domain will not happen. The team will abstract around technical concerns, and the language in the codebase will not reflect the problem domain. Contexts will not be well defined, and quickly the code will evolve into a ball of mud.

If your team is not motivated or lacks the knowledge of enterprise design patterns and principles, it may be best to favor a simpler pattern to organize domain logic so you don’t overcomplicate the development efforts.

All Problems Are Not Created Equal

Not all parts of the problem space require the full spectrum of the principles and practices of DDD. You must pick your battles. For areas of your solution that don’t require the collaboration with a domain expert, don’t involve her. For areas that don’t require the domain model pattern to represent an abstract model in code, don’t create one.

If a portion of your problem space is complex, your business has high expectations, you have access to a domain expert and a team up to the challenge, you have the exact criteria for which DDD can help you manage the development of your product.

Engaging with an Expert

A domain expert is a subject matter expert with deep knowledge of the problem domain. Whereas a stakeholder defines what the system needs to do, a domain expert collaborates with the development team, using his insight, expertise, and experience to model a solution that satisfies the behaviors. A domain expert could be a long-term user of a current system that has in-depth knowledge of the processes and logic of the problem space. The domain expert could equally be the systems product owner or simply someone who works in the department and has worked in the domain for many years. The point is that the term domain expert does not refer to a title; it’s anyone in the business who can offer expertise in the problem domain.

DDD doesn’t work without a domain expert. It’s as simple as that. Without a domain expert, much of the insight and rich domain knowledge and language will not be discovered. Without an expert, the development team may seek advice from users of a current system, and while knowledgeable on the current processes, may not be best placed to provide game-changing wisdom or domain intelligence. It cannot be stressed enough the importance of seeking out a domain expert and engaging with that person. A domain expert will have a day job; her time will be precious, so it is vital that you utilize time with her wisely.

Business analysts are not invalid. They hold skills that developers and domain experts may not possess. Business analysts can facilitate conversations with domain experts and can help the team capture terminology that forms the UL.

It is important for the stakeholder to trust the domain expert and regard this person as an expert. It is also important for the expert to understand why the project is being undertaken and what its goals are. A domain expert at odds with the nature of the project may turn out to be more of a hindrance than a help. However, her concerns and challenge with the project might be justified. In this case, ensure that the stakeholder and domain expert communicate to allow any fears or worries to be alleviated.

Try to collocate your project team with the business. Your team should be able to access the domain experts and users easily and regularly to ensure constant feedback. Domain experts are your primary source of knowledge when validating your domain model. Extract as much information from the heads of your domain experts as possible. By facilitating domain experts’ knowledge, you unlock a more useful model.

Select a Behavior and Model Around a Concrete Scenario

When working in the solution space, ensure that you focus on satisfying the behaviors of the product rather than trying to model the entire problem domain. Drive your modeling endeavors by selecting a behavior and defining concrete scenarios to use as examples. From this, the team and the domain expert can produce a model that is appropriate to the problem at hand. This practice helps to prevent overzealous developers from producing a one-model-to-rule-them-all view of the problem domain that isn’t really tailored to the needs of the system, and is more a reflection of reality rather than a useful abstraction of it.

As an example, consider this coupon feature for an e-commerce domain:

  • To increase customer spending
  • As a shop
  • I want to offer money-off coupons

To start to shape a model for this feature, you must model to meet specific concrete scenarios. This feature has several scenarios associated with it. The following is one example:

  • Scenario: A customer receives a discount on a basket.
  • He has a coupon that offers a discount of 10% off the value of a basket.
  • The coupon is valid for baskets that have an initial total exceeding $50.
  • When a coupon is applied to a basket with a total of $60, the discount should be $6.

During knowledge crunching, the team should listen to the domain expert’s choice of language and capture concepts that are used to fulfill the scenario. If the team spots potential issues or problems with the model, it should challenge them with the domain expert.

Collaborate with the Domain Expert on the Most Interesting Parts

When picking scenarios to model, don’t go for the low-hanging fruit; ignore the simple management of data. Instead, go for the hard parts—the interesting areas deep within the core domain. Focus on the parts of the product that make it unique; these will be hard or may need clarification. Time spent in this area will be well served, and this is exactly why collaboration with domain experts is so effective. Using domain experts’ time to discuss simple create, read, update, and delete (CRUD) operations will soon become boring, and the domain expert will quickly lose interest and time for you. Modeling in the complicated areas that are at the heart of the product is exactly what the principles of DDD were made for.

Evolve UL to Remove Ambiguity

Ambiguity alongside ignorance of your problem domain is your worst enemy as a developer. Teams must ensure that during modeling and knowledge crunching, all terms and language are defined explicitly and the domain expert is happy with the terminology. Everyone must be on the same page and have a single understanding of a concept. Besides talking to domain experts and each other in a single language, you must write the codebase with the same terms and concepts to ensure the code model reflects the mental models in conversation.

The UL is formed from the knowledge crunching exercise between domain experts and the development team as they start to model a solution to the more important and trickier parts of a product. Clear and unambiguous communication between the development team and the domain expert is vital to enable discoveries and to reduce translation cost between the team’s code model and the domain expert’s mental model. Teams that talk to domain experts about design patterns, principles, and practices will soon lose their interest due to the painful and costly translation that is required. The model, even though implemented in code, should be discussed at a higher level of abstraction so that the domain expert can lend his expertise to solving challenges with every new scenario that is thrown at it.

As you gain a deeper understanding of the domain you are working in, your UL will evolve. As the language evolves, so must your code. Refactor your code to embrace the evolution by using more intention-revealing method names. If you find a grouping of complex logic starting to form, talk through what the code is doing with your domain expert, and see if you can define a domain concept for it. If you find one, separate the logical grouping of code into a specification or policy class.

Throw Away Your First Model, and Your Second

When you are starting out on a project, you know little about it, but this is the time when you will be making important decisions. Your initial model will be wrong, but don’t get too hung up. The process of learning more about the problem domain is achieved over many iterations. Your knowledge will grow, and with this you will be able to evolve your model into something useful and appropriate.

When arriving at the first useful model, most teams usually stop exploring and jump to their keyboards to implement it. Your first model will unlikely be your best. Once you have a good model, you should park it and explore the problem from a different direction. Exploration and experimentation are vital to enable deep discoveries and to learn more about the problem domain; therefore, make mistakes and validate good ideas by comparing them to bad ones.

Sometimes while modeling, you become stagnant; your solution may have painted you into a corner, and a new scenario cannot be fulfilled with the current model. This is fine. Instead of trying to make the scenario fit the model, make a new model that is useful for the existing and new scenarios. Try to unlearn everything you gained for the first model and take a new direction. Explore and experiment to reveal insights and offer new solutions.

The result of tackling a problem from various angles is not the creation of a perfect model but instead the learning and discovery of concepts in the problem domain. This is far more valuable and leads to a team able to produce a useful model at each iteration.

Implement the Model in Code

Once you have derived a model for the complex subdomains of your problem domain from sessions with a domain expert, you need to prove it in code. The mental model that was created between you and your domain expert should be reflected in code with the same terminology, language, and concepts. Once it turns the mental model into code, the development team may find that the model does not meet the needs of the scenario, and it needs to make a new concept or change an existing one. Because of the use of the UL and the shared understanding of the model throughout the team, communication with the domain expert is easy, and the new solution can be validated in collaboration and without translation. The update to the code model is reflected in the mental model, and the two models evolve together.

Creating a Domain Model

The creation of a domain model is an iterative exercise, and the quest to discover a useful model will see it constantly evolve as new business problems are tackled with it. It is important not to try to model the whole problem domain but instead select well-thought-through business scenarios that can be used as an example to test any model produced.

A domain model should constantly adhere to these two principles:

  • Be relevant: Able to answer questions in the problem domain and enforce rules and invariants.
  • Be expressive: Able to communicate to developers exactly why it’s doing what it’s doing.

The creation of a useful model is never completed at the first attempt. In fact, often the initial incarnation of a domain model is naive and contains little insight into the rich problem domain. Instead, constant refactoring is required to expose domain knowledge within the codebase.

Evolution and an effective model are discovered through exploration and experimentation. BDD and Test-Driven Development (TDD) allow you to experiment, knowing that the inputs and outputs won’t be affected. Start with an anemic domain or simpler patterns, and refactor toward the rich domain model when needed. Model only when the problem requires a complex solution or the team is unsure of or new to the problem domain (for example, the team has never worked in finance).

Keep the Solution Simple and Your Code Boring

Keep your model simple and focused, and strive for boring plain code. Often teams quickly fall into the trap of overcomplicating a problem. Keeping a solution simple does not mean opting for the quick and dirty; it’s about avoiding mess and unnecessary complexity. Use simplicity during code review or pair programming. Developers should challenge each other to ensure they are proving a simple solution and that the solution is explicitly focused only on the problem at hand, not just a general solution to a generalized problem.

Carve Out an Area of Safety

If you are working in a legacy codebase or are integrating with a legacy code, it is vital to ensure that your code is not contaminated by the mess that already exists. (If there is mess; remember that legacy doesn’t mean bad code!) It may be tempting to clean up the legacy codebase, but this is a task that can quickly become time consuming and distract from your real goal of introducing new functionality. Instead, lean on the anticorruption layer pattern to create a boundary between your new code and the existing code. This protection boundary enables you to create a clean model that is isolated from other teams’ influences.

Integrate the Model Early and Often

While modeling, it is important to validate and prove the model in code as early as possible. Whiteboard drawings and cards are good, but working code is the only true measure of progress. Working code means integrated code. Working code connects to databases and to user interfaces; it proves the model from an end-to-end process.

Nontechnical Refactoring

Experienced developers are familiar with employing technical refactorings to increase the quality of the software construction by migrating to well-known code organizing patterns. However, a different type of refactoring is required to ensure a model communicates what it does clearly. It’s important to reflect in code any domain knowledge breakthroughs that happen with domain experts or indeed anyone working on the software product. Code within the domain model should be clear and expressive.

A domain model starts out simple based on a shallow view of the domain, usually based on the nouns and verbs of the requirement documentation or from initial discussions with domain experts. However, as the depth of knowledge within the team grows through iterations, so should the richness of the domain model. Even if the technical design of the code has been modified to increase clarity, the names and methods of classes, along with the namespaces, should continue to be updated to reflect the more insightful abstractions that are discovered through knowledge-crunching sessions. This continued investment in the model helps keep it relevant and match the vision and intent of the domain experts.

Decompose Your Solution Space

As your model grows, you will find ambiguity in language or overloaded terms, or you may just find it difficult to manage due to its size. To make large and complex domain models simpler and easier to maintain, divide by context based on natural language and invariants. Focus on minimizing the coupling between contexts. Don’t strive for perfect code; strive for perfect boundaries. Bounded context and aggregates are powerful concepts in DDD that enable complexity to be reduced. These patterns help to manage complexity.

You should arrive at the strategic patterns of DDD due to complexity rather than up-front design. Boundaries are hard to remove when they are defined so refactor toward them after several iterations of development and when you are more knowledgeable within the problem domain. Favor small modules of code with a focus on boundaries that you can replace rather than perfection within those boundaries. Isolate and protect data.

Rinse and Repeat

Figure 10.1 visualizes the steps of applying the principles and practices of DDD.

images

FIGURE 10.1 The process of DDD.

A model is constantly evolving and changing; you cannot effectively utilize the practices and patterns of DDD without embracing evolution. You should perform the steps presented in this section constantly. Keeping the complexity of the software solution as low as possible is the goal of DDD. All the principles and practices are aimed at this overall goal. As a developer, it is your job to continuously challenge the effectiveness and simplicity of your model design as iterations change and evolve it to meet the new behaviors of the stakeholders.

A useful model is arrived at through hundreds of small refactorings. Adjustments to the model are made constantly, with discoveries being unlocked through small transformations.

During development, you may find that your assumption on the core domain may change. The business may discover that it was wrong. Things change. Your boundaries will also change as you realize that new invariants invalidate your design. With new features, you may find that ambiguity creeps in. If it does, split the model and explicitly define the two parts in specific contexts.

Remember to start simple, and move toward the principles and practices when you absolutely need them. Otherwise, you may very well overcomplicate a simple solution to a simple problem.

Exploration and Experimentation

A rich and useful model is a product of exploration and creativity. Experimentation is about looking at the code in a different way. If you find that coding is hard, you are probably doing something wrong. Don’t just stop at the first useful model you produce. Because a model evolves over a number of iterations, it is a good idea to delay refactoring until you know enough about the domain. Let the model live a little and evolve. You won’t get it right the first time. Experimentation and exploration fuel learning.

Challenge Your Assumptions

During every iteration, the development team must challenge its assumptions because additional features may mean that a previously useful model is no longer fit for purpose. This skill enables your software to be flexible and evolve as the product evolves, thus preventing it from turning into a Big Ball of Mud (BBoM).

A team should not become too attached to a model based on the requirements from a first iteration. Subsequent iterations may see the model become inadequate for the new feature requests. Teams that are inflexible about evolving will soon find that the code works against them. When teams follow a test-driven development methodology, they do not stop when the system is working. Instead, they make a test pass and then refactor their design to make it more expressive. This is by far the most important aspect of test-driven development and one that should be applied to DDD. Refactoring when knowledge is gained helps to produce a model that is more expressive and revealing.

Modeling Is a Continuous Activity

The activity of modeling happens whenever you need it; it is not a step in a project methodology. You break out and collaborate with domain experts whenever it is required. If the area you are working on is well understood, you may find that you don’t need to model at all. Don’t get too attached to your software; be prepared to throw away your best code when the business model changes. With each iteration comes a new challenge. You need to ensure that you refine and reshape your model to meet the needs of new features and scenarios.

There Are No Wrong Models

There is no such thing as a stupid question or a stupid idea. Wrong models help to validate useful ones, and the process of creating them aids learning. When working in a complex or core area of a product, teams must be prepared to look at things in a different way, take risks, and not be afraid of turning problems on their head.

For a complex core domain, a team should produce at least three models to give itself a chance at producing something useful. Teams that are not failing often enough and that are not producing many ideas are probably not trying hard enough. When deep in conversation with a domain expert, a team should not stop brainstorming at the first sign of something useful. Once the team gets to a good place, it should wipe the whiteboard and start again from a different angle and try the what-if route of investigation. When a team is in the zone with an expert, it should stay there until it exhausts all its ideas.

Supple Code Aids Discovery

In Parts II, III, and IV of this book, you will learn about patterns to organize your codebase to enable it to change more effectively with new requirements. This supple code is derived from iterations of small refactors. Constantly refactoring toward deeper insight helps lead to a supple design and flexible code that is able to facilitate change and adapt to new features of the system as they are added in each iteration. If a model is not supple, it is not useful. Martin Fowler states an important modeling principle in his book Analysis Patterns: Reusable Object Models: “Design a model so that the most frequent modification of the model causes changes to the least number of types.”

However, be careful of premature refactoring. Don’t refactor until you know enough about the domain, and don’t become preoccupied with applying design patterns. Delaying refactoring can also reveal which areas of the code change most often and why. With this knowledge, you can make more informed design changes to your codebase.

Making the Implicit Explicit

When teams are working deep within a codebase, they often ignore or dismiss logic statements as simple artifacts of programming. These small implicit code blocks hide important details about the domain, often disguising their importance. If these design decisions are not made explicit, they cannot be added to the mental model, and further design discoveries will be harder.

As mentioned previously, delaying refactoring can reveal important details in the code and thus important details of the model. If you find a code grouping that represents some kind of domain logic that doesn’t have an explicit name, inform the domain expert, name the logic concept, and wrap the code in the concept. It is vital to make implicit concepts explicit. Any decisions you make in code need to be explicitly fed back to the domain expert and captured as a concept of the model.

Tackling Ambiguity

It’s often the things the domain experts don’t say or barely hint at that are the key to unlocking deep discoveries within a model. These implicit concepts that may not appear important to domain experts should be made explicit, be named, and be fully understood by the development team. For example, consider an e-commerce site that prevents overseas customers from adding more than 50 of any one item to their basket. Developers can easily implement this business rule, as can be seen in Listing 10-1.

However, in future months, other developers may not understand why such a rule exists. Instead, you should understand why the rule exists and name the portion of code accordingly. As it transpires, suppliers enforce such a rule to prevent sites acting as wholesalers. With this knowledge, you can make the code explicitly reveal this rule by wrapping it in a class that indicates a deeper insight and understanding of the domain. This refactoring is seen in Listing 10-2.

Developers should watch for ambiguity or inconsistency in code or in the language of a domain expert. You should also ensure that you pay particular attention to the language of other team members when discussing the domain model. Always validate assumptions about the language and details of the model by talking to domain experts. Validate aloud, and confirm your language and design decisions with linguistic consistency. If a domain expert doesn’t say it, it shouldn’t be in the language or codebase. If a term in the model no longer makes sense or is not useful, remove it. Keep your language small and focused. Domain experts should object to inadequate terms or structure in the language or model.

Give Things a Name

If domain experts talk about it, make it explicit. If domain experts hint at a concept, make it explicit. If you talk about something that puzzles domain experts, maybe you have misunderstood something they have said and you need to work on your UL. Give things a name, and if you can’t think of a good name, defer it and call it the blue policy until you can think of something more meaningful.

A domain model should communicate the intent of the business. Ensure that you take care in naming all methods and properties of your classes. Try to describe the behaviors by involving the UL. Don’t leave your code design up to interpretation. Help yourself and other developers by writing code that is insightful, revealing the rich language of the domain.

A Problem Solver First, A Technologist Second

A software developer is primarily a problem solver who utilizes technology to implement a solution. Developers are fantastic at educating themselves on technology and project methodologies; however, decomposing a problem and being able to distill what is important from what is not will enable a good developer to become a great one. You should spend as much time in the problem space as you do in the solution space.

Just as a useful model is derived over a series of iterations, so too must a problem space be refined to reveal the true intent behind a stakeholder’s vision. Listening and drawing the why as well as the what and when from stakeholders is a skill that developers should practice just as they practice coding katas.

Code is a product of DDD, not the process; you can solve problems without having a technical solution.

Don’t Solve All the Problems

All problems are not created equal; some are complex and are of little business value, so it makes no sense to waste effort in finding automated solutions for them. Complex edge cases do not always need automated solutions. Humans can manage by exception. If a problem is complex and forms an edge case, speak to your stakeholder and domain expert about the value of automating it. Your effort could be better served elsewhere, and a human might better handle this exception.

How Do I Know That I Am Doing It Right?

Unlike becoming a scrum master, there is no certificate awarded when applying the principles and practices of DDD. Your reward from your investment will result in a product that is easily understood, straightforward to maintain, meets the expectations of your stakeholders, and is fun to work on.

You will also find that your team members understand the business better. You will notice that they will be able to talk more fluently with stakeholders and offer solutions to problems that the business didn’t know it had or maybe did not have a solution for.

Aligning a team and a business ensures everyone in the organization understands what value means. Teams will no longer spend time on overcomplicated, technical, influenced solutions that use the same architecture and effort, striving for code perfection even for areas that are of little importance to the business. They will instead be able to decompose problems and work with the business to focus on value and spend time in this area, proving good enough, simple solutions to any supporting or generic domains. They will understand where the true value is and where they can make a difference.

Teams will focus on the problem domain, understanding it rather than focusing only on the technical solution. They will spend increased time on the what, why, and when, leaving the how to later.

Good Is Good Enough

Teams that are aligned with the philosophy of DDD focus more on the bigger picture and understand where to put the most effort. They will not apply the same architecture to all parts of a solution, and they will not strive for perfection in areas of little value. They will trade isolated and working software for unnecessary elegance and gold plating.

Only the core domains need to be elegant due to complexity or importance. This is not to say that all other code should be poorly written, but it should be isolated, defined by a boundary, and expose behavior to support the core domain.

Practice, Practice, Practice

Software development is a learning process, and so is DDD. If you want to be good at anything, you need to practice, practice, practice. If you want to be a great developer rather than a good one, you need to show passion for the problem and passion for the solution. To apply the principles of DDD, you need a driven and committed team—a team committed to learning about its craft and the problem domains it works in. Passion lies within all of us, and if you feel value in the practices of DDD, it is up to you to inspire your team and become an evangelist. Passion is contagious; if you commit to spend time with your domain experts to understand a domain at a deeper level and can show how this results in a more expressive codebase then your team will follow.

Many developers are turned off when working in a brownfield environment because of fear of having to work on another developer’s codebase. When working on enterprise systems, you have to integrate or work on brownfield environments at some point. Great developers excel at introducing new features into an existing codebase in a safe and maintainable manner.

The Salient Points

  • Don’t sell DDD as a silver bullet. Focus on the alignment with the business and learning more about the domain you are building software for.
  • Apply the principles of DDD only when they are needed. Don’t use them as a tool for all problems.
  • Decompose the problem space and focus on the core domain. All interesting conversations will happen here. This is where you apply the principles of DDD to maximize value and where you should apply the most effort.
  • Before modeling a solution, capture the reality of the landscape, and understand other models and contexts in play. Who owns these? What relationships do you have with them? What and how is data exchanged?
  • Build a model to satisfy feature scenarios. Start with the most risky or complex. Utilize your domain expert’s time here, and don’t bother him with simple data management.
  • If you are working in a legacy environment, ensure that you protect yourself from external code, don’t trust anyone, and enforce your borders. Carve out an area to add new functionality. Don’t try to clean up everything.
  • Constantly integrate, refine, and challenge your model. Don’t stop at your first good idea. Explore and experiment, and validate good ideas by trying new models and solutions. Have at least three useful models.
  • Don’t assume anything, keep things simple, delay large design decisions, and wait for complexity or new behaviors to challenge your solution. Then refactor toward strategic patterns when you need to.
  • Modeling is a team activity, and one that should happen whenever the team is stuck, encounters an area it is unsure of, or needs clarification. It should not be confined to a predefined step in a project time line.
  • The model and the language evolve together. A model that cannot be communicated and talked about with ease will have limited usefulness and will be hard to evolve.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.223.160