Notes from Eric Evans book Domain-Driven Design - Tackling Complexity in the Heart of Software.
Pattern names should be in bold, when introduced first time.
Foreword & Preface
- The premise of the book:
- For most software projects, the primary focus should be on the domain and domain logic.
- Complex domain designs should be based on a model.
Part I - Putting the Domain Model to Work
- Example: Map
- Maps are models, and every model represents some aspect of reality or an idea that is of interest.
- A model is a simplification.
- It is an interpretation of reality that
- abstracts the aspects relevant to solving the problem at hand
- ignores extraneous detail
- Domain modeling
- is not a matter of making as "realistic" model as possible.
- It is more like moviemaking, loosely representating reality to a particular purpose.
Chapter 1 - Crunching knowledge
- Knowledge crunching
- Continuous learning
Chapter 2 - Communication and the Use of the Language
- Ubiquitous Language - Use the model as the backbone of a language
- Commit the team to exercising that language relentlessly in all communication within the team and in the code.
- Model is not the diagram
- The diagram's purpose is to help communicate and explain the model.
- Code has the details
Chapter 3 - Binding Model and Implementation
- Model-Driven Design - Design a portion of the software system to reflect the domain model in a very literal way.
- Revisit the model and modify it to be implemented more naturally in software, even as you seek to make it reflect deepre insight into the domain.
- Demand a single model that servers both purposes well, in addition to support a robust Ubuquitous Language.
- Hands-On Modelers - Any technical person contributing to the model must spend some time touching the code
Part II - The Building Blocks of a Model-Driven Design
Chapter 4 - Isolating the Domain
- Layered Architecture
- The Smart UI "Anti-Pattern"
- If an unsophisticated team with a simple projects decides to try a Model-Driven Design with Layered Architecture, it will face a difficult learning curve.
Chapter 5 - A Model expressed in Software
- Entity vs Value Object
- Does an object represent something with continuity and identity - something that is tracked through different states or even across different implementations?
- Or is it an attribute that describes the state of something else?
- Service
- There are those aspects of the domain that are more clearly expressed as actions or operations, rather than objects.
- Associations
- For each traversable association in the model, there is a mechanism in the software with the same properties.
- It is important to constrain relationships as much as possible.
- Entities (a.k.k Reference Objects)
- Many objects are not fundamentally defined by their attributes, but rather by a thread of continuity and identity.
- Sometimes an object must be matched with another object even if their attributes differ.
- And an object must be distinquished from other objects even though they might have the same attributes.
- Value Objects
- Many objects have no conceptual identity.
- These objects describe some characteristics of a thing.
- Services
- Some concepts from the domain aren't natural to model as objects. Forcing them to be resposibility of an Entity or a Value either distorts the definition of a model-based objects or adds meaningless artificial objects.
- Characteristics of a good service:
- The opration relates to a domain concept that is not a natural part of an Entity or Value Object
- The interface is defined in terms of other elemnts of the domain model.
- The operation is stateless.
- Modules (a.k.a packages)
- Everyone uses Modules, but few treat them as a full-fledged part of the model
Chapter 6 - The Life Cycle of a Domain Object
- Aggregates
- First we need an abstraction for encapsulating references within the model.
- Aggregate is a cluster of associated objects that we treat as a unit for the purpose of data changes.
- Aggregate has a root (one entity) and a ary.
- Cluster the entities and Value objects into Aggregates and define boundaries around each.
- Factories
- When creation of an object, or an entire Aggregate, becomes complicated or reveals too much of the internal structure, Factories provide encapsulation.
- Creation of an object can be a major operation in itself, but complex assemble operations do not fit the responsibility of the created object.
- ->
- Shift the responsibility for creating complex objects and Aggregates to a separate object, which may itself have no responsibility in the domain model but is still a part of the domain design.
- Create entires Aggregates as a piece, enforcing their invariants.
- Factory can also be a factory method.
- Repositories
- A subset of persistent objects must be globally accessible through a search based on object attributes.
- Such access is needed for the roots of Aggregates that are not convenient to reach by traversal
- Usually Entities, sometimes VAlue objects with complex internal structure, and sometimes enumerated Values.
- ->
- For each type of object that requires global access, create an object that can provide an illusion of an in-memory collection of all objects of that type.
- Provide methods to add and remove objects, which will encapsulate the actual insertion or removal of data in the data store.
- Provide Repositories only for Aggregate roots
Chapter 7 - Using the Language - an extended Example
- Designing associations: Avoid bi-directional associations
Part III - Refactoring toward Deeper Insight
- Success developing useful models comes down to three points
- Sophisticated domain models are achievable and worth the effort
- They are seldom developed except through an iterative process of refactoring, including close involvement of the domain experts with developers interested in learning about the domain.
- They may call for sophisticated design skills to implement and to use effectively.
- A deep model provides a lucid expression of the primary concern of the domain experts and their most relevant knowledge while it sloughs off the superficial aspects of the domain.
Chapter 8 - Breakthrough
Chapter 9 - Making Implicit Concepts Explicit
- May transformations of domain models and the corresponding code happen when developers recognize a concept that has been hinted at in discussion or present implicitly in the design, and they represent in explicitly in the model with one or more objects or relationships.
- Experimentation is the way to learn what works and doesn't.
- Trying to avoid missteps in design will result in a lower quality result because it will be based on less experience.
- And it can easily take longer than a series of quick experiments.
- Constraints and processes are two broad categories of model concepts that don't come leaping to mind when programming in an object-oriented language, yet they can really sharpen up a design once we start thinking about them as model elements.
- Specification
- Business rules often do not fit the responsibility of any of the obvious Entities or Value Objects, and their variety and combinations can overwhelm the basic meaning of the domain object. But moving the rules out of the domain layer is even worse, since the domain code no longer expresses the model.
- -> Create explicit predicatelike Value objects for specialized purposes. A Specification is a predicate that determines if an object does or does not satisfy some criteria.
- Need to specify the state of an objects usually for one or more of three purposes:
- To validate an object to see if it fulfills some need or is ready for some purpose.
- To select an object from a collection
- To specify the creation of a new object to fit some need.
Chapter 10 - Supple Design
- Intention-revealing Interfaces
- Name classes and operations to describe their effect and purpose, without reference to the means by which they do what they promise. This relieves the client developer of the need to understand the internals.
- These names should conform to the Uquiquitous Language.
- Side-Effect-Free Function
- Assertions
- Conceptual Contours
- (contour: ääriviiva, korkeuskäyrä)
- Decompose design elements (operations, interfaces, classes and Aggregates) into cohesive units, taking into concideration your intuition of the important divisions in the domain.
- Observe the axes of change and stability through successive refactorings and look for the underlying Conceptual Contours that explain these shearing patterns.
- Align the model with the consistent aspects of the domain that make it a viable area of knowledge in the first place.
- It may never emerge from technically oriented refactoring: It emerges from refactoring toward deeper insight.
- Stand-Alone Classes
- Low coupling is fundamental to object design. When you can, go all the way. Eliminate all other concepts from the picture. Then the class will be completely self-contained and can be studied and understood alone.
- Closure of Operation
- Where it fits, define an operation whose return type is the same as the type of its argument(s).
- Such an operation is closed under the set of instances of that type.
- Angles of attack
- Carve off subdomains
- You can't tackle the whole design at once. Pick away at it.
- It is more useful to make a big impact on one area, making a part of the design very suppple, than to spread your efforts thin.
- Draw of established formalisms, when you can
- Creating a right conceptual framework from scratch is something you can't do every day.
- You can often use and adapt conceptua systems that are long established in your domain or others.
- Carve off subdomains
Chapter 11 - Applying Analysis Patterns
- Discussion on applying Analysis Patterns with DDD.
Chapter 12 - Relating Design Patterns to the Model
- Discussion on applying Design Patterns with DDD.
- Some, not all, of the patterns in Design Patterns can be used as domain patterns.
Chapter 13 - Refactoring Toward Deeper Insight
- Multifaceted process
- Three things to focus on:
- Live in the domain.
- Keep looking at things a different way.
- Maintain an unbroken dialog with domain experts.
- Continuous refactoring has come to be considered a "best practise", but most project teams are still too cautious about it.
- Refactor when
- The design does not express the team's current understanding of the domain,
- Important concepts are implicit in the design (and you see a way to make them explicit), or
- You see an opportunity to make some important part of the design suppler.
Part IV - Strategic Design
- As systems grow too complext to know completely at the level of individual objects, we need techniques for manipulating and comprehending large modules.
- This part of the book presents principles that enable the modeling process to scale up to very complicated domains.
Chapter 14 - Maintaining Model Integrity
- The most fundamental requirement of a model is that it be internally consistent
- that its terms always have the same meaning
- that it contain no contradictory rules
Total unification of the domain model for a large system will not be feasible or cost-effective.
Bounded Context
- Multiple models are in play on any large project.
- Yet when code based on distinct models is combined, software becomes buggy, unreliable and difficult to understand.
- Communication among team members becomes confused.
- It is unclear in what context a model should not be applied.
- -> Explicitly define the context within which a model applies.
- Explicitly set boundaries in terms of team organization, usage within specific parts of the application, and physical manifestations such as code bases and database schemas.
- Keep the model strictly consistent within these bounds, but don't be distracted or confused by issues outside.
- Combining elements of distinct models causes two categories of problems:
- Duplicate concepts: there are two model elements that actually represent the same concept.
- False cognates: Case when two people who are using the same term (or implemented object) think they are talking about the same thing, but really are not. (slightly less common, but more insidiously harmful)
- Multiple models are in play on any large project.
Continuous Integration
- All work within the context is being merged and made consistent frequently enough that when splinters happen they are caught and corrected quickly.
Context Map
- Identify each model in play on the project and define its Bounded Context.
- Name each Bounded Context and make the names part of the Ubiquitous Language.
- Map the currently existing terrain. Take up transformations later.
Different patterns/approaches for the relationships between Bounded Contexts:
Shared Kernel
- Designate some subset of the domain model that multiple teams agree to share.
- Including the subset of code or database design associated with that part of the model.
- This explicitly shared stuff has special status, and shouldn't be changed without consultation with the other team.
Customer/Supplier Development Team
- Establish a clear customer/supplier relationship between the two teams.
- In planning sessions, make the downstream team play the customer role to the upstream team.
Conformistm
- There might be Upstream/Downstream case in which the upstream has no motivation to provide for the downstream team's needs. Three possible paths:
- Abandon the use of upstream altogether. (see Separate Ways below)
- Developing an own model in the downstream team (translation layer will probably be complex - see Anticorruption Layer below)
- Conformist strategy
- -> Eliminate the complexity between translation between Bounded Contexts by slavishly adhering to the model of the Upstream team.
- There might be Upstream/Downstream case in which the upstream has no motivation to provide for the downstream team's needs. Three possible paths:
Anticorruption Layer
- In translation, data types etc. must be translated. But often overlooked is the certainty that the other system does not use the same conceptual domain model.
- -> Create an isolating layer to provide clients with functionality in terms of their own domain model. The layer talks to the other system through its existing interface, requiring little or not modification to the other system. Internally, the layer translates in both directions as necessary between the two models.
Separate Ways
- Declare a Bounded Context to have no connection to the other(s) at all, allowing developers to find simple, specialized solutions within this small scope.
Open Host Service
- Define a protocol that gives access to your subsystem as a set of Services. Open the protocol so that all who need to integrate with you can use it. Enhance and expand the protocol to handle new integration requirements, except when a single team has idiosyncratic needs. Then, use a one-off translator to augment the protocol for that special case so that the shared protocol can stay simple and coherent.
Published Language
- Use a well-documented shared language that can express the necessary domain information as a common medium of communication, translating as necessary into and out of that language.
Chapter 15 - Distillation
- Process of separating the components of a mixture to extract the essence in a form that makes it more valuable and useful.
- A model is a distillation of knowledge.
With every refactoring to deeper insight, we abstract some crucial aspect of domain knowledge and priorities.
Core Domain
- Not all parts of the domain are going to be equally refined.
- To make the domain model an asset, the model's critical core has to be sleek and fully leveraged to create application functionality. But scarce, highly skilled developers tend to gravitate to technical infrastructure or neatly definable domain problems that can be understood without specialized domain knowledge.
- Find the Core Domain and provide a means of distinquishing it from the mass of supporting model and core. Bring the most valueable and specialized concepts into sharp relief. Make the Core small.
- Apply top talent to the Core Domain.
Generic Subdomains
- ->
- Identify cohesive subdomains that are not the motivation for your project.
- Factor out generic modules of these subdomains and place them in separate Modules.
- Leave no trace of your specialties in them.
- Note: These can be found as off-the-self solutions
- NOTE: We technical people tend to enjoy definable problems like time zone conversion, and we can easily justify spending our time on them. But a disciplined look at priorities usually points to the Core Domain.
- Projects face risk from both sides, with some projects having greater technical risks and others greater domain modeling risks. It is easy to underestimate the domain modeling risk.
- ->
Domain Vision Statement
- Write a short description (~one page) of the Core Domain and the value it will bring, "value proposition"
- Ignore those aspects that do not distinguish this domain model from others.
- Show how the domain model serves and balances diverse interests.
- Keep it narrow.
- Write this statement early and revise it as you gain new insight.
Highlighted Core
- -> Write a very brief document (3-7 pages) that describes the Core Domain and the primary interactions among Core elements.
- -> (another form) Flag each element of the Core Domain within the primary repository in the model, without particularly trying to elucidate its role. Make it effortless for a developer to know what is in or out of the Core.
- If the distillation document outlines the essentials of the Core domain, then it serves as a practical indicator of the significance of a model change. (If a change affects the distillation document, it requires consultation with the other team memeber)
Cohesive mechanisms
- Partition a conceptually Cohesive Mechanism into a separate lightweight framework. Particularly watch for formalisms or well-documented categories of algorightms. Expose the capabilities of the framework with an Intention-Revealing Interface.
- For example, graph traversal network would be a cohesive mechanism.
- Generic Subdomain vs Cohesive Mechanism
- Both are motivated by desire to unburden the Core Domain
- Generic Subdomain is based on an expressive model that represents some aspect of how the team views the domain
- A Cohesive Mechanism does not represent the domain; it solves some sticky computational problem posed by the expressive models.
Abstract Core
- Identify the most fundamental concepts in the model and factor them into distinct classes, or interfaces.
- Design this abstract model so that it expresses most of the interaction between significant components.
- Place this abstract overall model in its own Module. (Detailed implementations are left in their own Modules defined by subdomain)
Chapter 16 - Large-Scale Structure
Devise a pattern of rules or roles and relationships that will span the entire system and that allows some understanding of each part's place in the whole - even without detailed knowledge of the part's responsibility.
Evolving Order
- Design free-for-alls produce systems no one can make sense of as a whole, and they are very difficult to maintain. But architectures can straitjacket a project with up-front design assumptions and take too much power away from the developers/designers of a particular part of the application.
- -> Let this conceptual large-scale structure evolve with the application, possibly changing to a completely different type of structure along the way. Don't overconstrain the detailed design and model decisions that must be made with detailed knowledge.
- System Metaphor
- Software designs tend to be very abstract and hard to grasp. Developers and users alike need tangible ways to understand the system and share a view of the system as a whole.
- -> When a concrete analogy to the system emerges that captures the imagination of team members and seems to lead thinking i a useful direction, adopt it as a large-scale structure.
- Organize the design around this metaphor and absorb it into the Ubiquitous language.
- Because all metaphors are inact, continually re-examine the metaphor for overextension or inaptness, and be ready to drop it if it gets in the way.
Responsibility Layers
- Look at the conceptual dependencies in your model and the varying rates and sources of change of different parts in the domain. If you identify natural strata in the domain, cast them as broad abstract responsibilities. These responsibilities should tell a story of the high-level purpose and design of your system.
- Choosing appropriate layers:
- Some characteristics to look for and preseve:
- Storytelling
- Conceptual dependency
- Conceptual contours
- Some characteristics to look for and preseve:
- Example layering scheme
- Potential
- What can be done / what could we do? (Never mind what we are planning to do)
- Resources, contracts
- Reality of the situation
- Operational
- What is being done?
- What have we managed to do out of those potentials?
- Reality of the situation
- Policy
- What are the rules and goals?
- Rules and goals are mostly passive but constrain the behaviour in other layers.
- Decision Support
- What action should be taken or what policy should be set?
- Analysis and decision support
- Potential
Knowledge Level
- Create a distinct set of objects that can be used to describe and constrain the structure and behavior of the basic model. Keep these concerns separate as two "levels", one very concrete and the other reflecting roles and knowledge that a user or superuser is able to customize.
- Example of HR system with Employee types etc.
Pluggable Component Framework
- You have to fight the temptation to build frameworks and regiment the implementation of the large-scale structure. The most important contribution of the large-scale structure is conceptual coherence, and giving insight into the domain.
- Each structural rule should make development easier.
Chapter 17 - Bringing the Strategy Together
- Three basic principles of strategic design (context, distillation, and large-scale structure) are not subsitues for each other, they are complementary and interact in many ways.
- E.g. a large-scale structure can exist within one Bounded Context, or it can cut across many of them.
- Six essentials for Strategic Design Decision Making
- Decisions must reach the entire team.
- The decision process must absorb feedback.
- The plan must allow for evolution.
- Architecture teams must not siphon off all the best and brightest.
- Strategic design requires minimalism and humility.
- Objects are specialists, developers are generalists.
Some links
- DDD quickly minibook
- Summary & concept maps can be found at DDD Reference
No comments:
Post a Comment