by andrei
15. August 2008 22:34
You can read about the purpose of this list and how to use it here.
Also, the list of resources is here.
- general implementation
E1 - E7
E10
B1
B3 - concepts
- Other Domain Model Styles
There are lots of variations on how the Domain Model pattern is used
resources
E17 - free of non-business aspects
you should really, really try to avoid modifying the Domain Model in order to suit it to the needs of the PL
Why not just put the GetFullName () method in the Domain Model Person class? We could, if it had a use in some business logic operation, but if the only use of the GetFullName () method is in the PL, the method should go in the PM and not in the Domain Model.
Keeping the Domain Model free from any non-business aspects is key to keeping the "heart" of your application understandable and maintainable.
resources
B4 - database
we avoid having logic in stored procedures (and actually avoid stored procedures altogether). This is intentional because we want to achieve a better maintenance story by having all the logic in the Domain Model and its nearby surroundings. (And again, when we really have to, we can optimize the rare places with stored procedures.)
resources
B4 - versioning
I now want to add some versioning information to the Domain Model as a way of stating where we need to deal with controlling concurrency
resources
B4 - Persistence Ignorance
PI means clean, ordinary classes where you focus on the business problem at hand without adding stuff for infrastructure-related reasons
resources
B4 - repositories PI
saying you use PI for Repositories as well is pushing it. This is because the purpose of Repositories is pretty much to give the consumer the illusion that the complete set of Domain Model instances is around, as long as you adhere to the protocol to go to the Repository to get the instances. The illusion is achieved by the Repositories talking to infrastructure in specific situations, and talking to infrastructure is not a very PI-ish thing to do.
resources
B4 - persistence abstraction layer
Thanks to that abstraction layer, I can move the Repositories back to the Domain Model, and I only need one Repository implementation per Aggregate root. The same Repository can work both against an O/R Mapper and against a Fake that won't persist to a database but only hold in memory hashtables of the instances, but with similar semantics as in the O/R Mapper-case.
It's still a stretch to talk about PI Repositories, but with this solution I can avoid a reference to the infrastructure in the Domain Model. That said, in real-world applications I have kept the Repositories in a separate assembly anyway
resources
B3
B4
code & implementation
E12
- POCO
plain old c# object
resources
B4
- Prevayler
http://www.prevayler.org/wiki/ - visitor
code & implementation
E2 - visitor framework
code & implementation
E2
- value object
To take an extreme example of something that isn't an Entity, let's think about the integer 42. I don't care about the identity of 42 at all; I only care about the value. And when the value changes, I no longer think it's the 42 that has changedit's a totally new value with no connection to the old one. Forty-two is a Value Object
the objects that describe things, an attribute that describes the state of something else and does not need a distinct identity
the CopyTo class is a Value class, as evidenced by having to supply all
of the data for the class to its constructor.
resources
B1
B3
B4
code & implementation
B3 - validation framework
resources
E13 - real-time validation
One alternative solution is to update the list of broken rules after each change to a property so that it is pre-calculated when it is needed
A problem is that it requires some help with dirty tracking, or you will have to write loads of code yourself in your setters (unless you apply AOP for dealing with the crosscutting concern of course). You will also have to use properties instead of public fields, even if public fields would otherwise do very well.
This style is used in the CSLA.NET-framework
resources
B4 - undo
the CSLA.NET-framework Lhotka BO, which also has support for something I haven't touched upon: multi-step undo.
resources
B4 - usage in the persistance layer
I talked about how to prepare for the persistence infrastructure by working with an abstraction layer that I called NWorkspace (which is just an example of such an abstraction of course). As you might have guessed, it has some support for validation as well, because the reactive nature needs to be dealt with when we make calls to PersistAll().
resources
B4 - consistency
I think that in this case it's usually OK not to expect real-time consistency here, only something pretty close to real-time consistency. I mean, check the sum of the other orders just before saving this order, but do not span the read with a high isolation level or not even do the check within the same transaction.
strive for real-time consistency within an Aggregate, but not between Aggregates. Consistency problems between Aggregates can be dealt with a little later.
So if you find the approach acceptable (again, we are talking about a pretty low risk here, for a typical system at least), but you would like to detect the problem, you could create some batch program that kicks in every now and then and checks for problems like this and reports back. Or why not put a request on a queue at persist time that checks for problems like this regarding the particular customer? It's such an unlikely problem, so why should any user have to wait synchronously for it to be checked?
resources
B4 - gather messages
we can, of course, aggregate several such lists into a single one in an Application layer Evans DDD, such as from several Aggregate root instances.
resources
B4 - entry point
Normally the consumer only has to ask the Aggregate Evans DDD root if it's valid or not to be persisted and the Aggregate root will check its children.
The unit for checking rules is... Aggregates
resources
B4 - transition
It's possible to deal with this by having a method called Rename(string newName) that takes care of the work. During the execution of the method, the state of the object isn't correct, but we only consider it a problem before and after the method execution.
This is in line with invariants according to Design by Contract Meyer OOSC. Such invariants are like assertions that the instance should abide by at all times, both before the method execution and after. The only exception is during the method execution.
resources
B4 - Broken Rules
the list of broken rules is an implementation of the Notification pattern
The key difference is that the actual rule (IRule) is exposed as opposed to a surrogate object which simply says it has been broken as is the case with the Notification pattern
resources
B3
B4
code & implementation
B3 - SmartCA
mini - framework for dealing with the concept of Broken Rules, which I am borrowing
(although simplifying it a bit here) from Rocky Lhotka ’ s CSLA Framework (CSLA)
resources
B3
code & implementation
B3
- ubiquitous language
a domain model can be the core of a common language for a software project, which can become the channel for all the information to flow between developers, domain experts, and the software, and the primary carrier of the aspects of design that don't appear in code
resources
B1 - traversing & processing entity hierarchies
resources
B3
code & implementation
B3 - the Identity Operation
Each ENTITY must have an operational way of establishing its identity with another object
I'm actually intermingling two separate concepts, namely the Identity Field pattern for coupling an instance to a database row (by using the primary key from the database row as a value in the object) and the ID that has business meaning. Sometimes they are the same, but quite often they should be two different identifiers.
This depends very much on the requirements (whether it's good or bad), but I get a growing feeling that we are mixing two different things here the business identification and the persistence identification.
resources
B1
B3
B4 - Template Method pattern
can be used for Repositories, to construct queries based on templates
resources
B3
B4
code & implementation
B3 - strategy = policy
the need to substitute different rules or make a decision based on a policy; Whereas the conventional view of STRATEGY as a design pattern focuses on the ability to substitute different algorithms, its use as a domain pattern focuses on its ability to express a concept, usually a process or a policy rule.
for example, the decision between fastest or cheapest; separate those tuning parameters into STRATEGIES
resources
B1 - state pattern
The idea is to encapsulate the different states as individual classes (see ConcreteStateA and ConcreteStateB). Those concrete state classes inherit from an abstract State class. Context has a state instance as a field and calls Handle() of the state instance when Context gets a Request() call. Handle() has different implementations for the different state classes.
resources
B4
code & implementation
B4 - Shared Kernel
Designate some subset of the domain model that the two teams agree to share. Of course this includes, along with this subset of the model, the subset of code or of the 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.
The SHARED KERNEL is often the CORE DOMAIN, some set of GENERIC SUBDOMAINS, or both
resources
B1 - service
operations that do not conceptually belong to any object; they stand alone in the model and do not have state
resources
B1
B3
B4 - Separate Ways
We must ruthlessly scope requirements. Two sets of functionality with no indispensable relationship can be cut loose from each other.
In many circumstances, integration provides no significant benefit. If two functional parts do not call upon each other's functionality, or require interactions between objects that are touched by both, or share data during their operations, then integration, even through a translation layer, may not be necessary. Just because features are related in a use case does not mean they must be integrated.
resources
B1 - segregated core
Refactor the model to separate the CORE concepts from supporting players (including ill-defined ones) and strengthen the cohesion of the CORE while reducing its coupling to other code.
This is basically taking the same principles we applied to GENERIC SUBDOMAINS but from the other direction.
resources
B1 - Rule-based programming
with an inference engine and a rule base - Responsibility Layers
When each individual object has handcrafted responsibilities, there are no guidelines, no uniformity, and no ability to handle large swaths of the domain together. To give coherence to a large model, it is useful to impose some structure on the assignment of those responsibilities. - repository
the middle and end of the life cycle, encapsulating the mechanisms of storage, retrieval, and query: 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. They are usually ENTITIES, sometimes VALUE OBJECTS with complex internal structure, and sometimes enumerated VALUES.
represents all objects of a certain type as a conceptual set (usually emulated)
for every object that is an Aggregate, create a repository for the object and give it the look and feel of an in - memory collection of objects of that particular type.
If I can get away with it, I will try not to let any of my domain model classes know about any of the repositories; only their interfaces will live in the domain layer, yet the implementation of the actual repositories will be in the infrastructure layer
SPECIFICATIONS mesh smoothly with REPOSITORIES
resources
B1
B3
code & implementation
B3 - AOP
Instead of starting with a base class that "never" has the right granularity, another approach is to build up the right Repository out of several tiny aspects, mixing in the right aspects to the right Repository.
resources
B4 - location
Conceptually, I like to think about the repositories as part of the Domain Model, but when no abstraction layer is used on top of the O/R Mapper, I let the repositories live in a separate assembly
resources
B4 - repository framework
resources
B3
code & implementation
E1
E2
- Published Language
When two domain models must coexist and information must pass between them, the translation process itself can become complex and hard to document and understand. When businesses want to exchange information with one another, how do they do it? Not only is it unrealistic to expect one to adopt the domain model of the other, it may be undesirable for both parties.
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.
resources
B1 - provider
The Client Membership System Provider is very much like that of a repository, only it does not
necessarily represent an in - memory collection of Aggregate Root Entities.
resources
B3
code & implementation
B3 - patterns
The only requirement is that the pattern should say something about the conceptual domain, not just be a technical solution to a technical problem.
resources
B1 - list of patterns
resources
E18
- packaging
Unless there is a real intention to distribute code on different servers, keep all the code that implements a single conceptual object in the same MODULE, if not the same object.
resources
B1 - Open Host Service
When a subsystem has to be integrated with many others, customizing a translator for each can bog down the team.
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.
resources
B1 - null object pattern
Take an Order, for example. Assume that the shipment of an Order is taken care of by a transporter.
At first, the Order hasn't been shipped (and in this case we have not thought much about shipment at all), so we can't give it any transporter object, but instead of just leaving the TRansporter property as null, I set the property to the empty ("not chosen," perhaps) transporter instead. In this way, I can always expect to find a description for the TRansporter property like this:
anOrder.Transporter.Description
If TRansporter had been null, I would have needed to check for that first.
resources
B4
code & implementation
E2 - module
the modules tell the story of the domain on a larger scale
resources
B1 - modelling out loud
One of the best ways to refine a model is to explore with speech, trying out loud various constructs from possible model variations
resources
B1 - model-driven design
discards the dichotomy of analysis model and design to search out a single model that serves both purposes. Setting aside purely technical issues, each object in the design plays a conceptual role described in the model
resources
B1 - membership framework
One of the main differences between my Membership implementation on the client and Microsoft ’ s ASP .NET Membership implementation is that I am keeping my membership - related logic in the domain
model, whereas with the ASP.NET Membership there is logic scattered across several classes and even in stored procedures in the out of the box SqlMembershipProvider implementation that comes with the ASP.NET Provider Toolkit.
resources
B3
code & implementation
B3 - lifecycle
Every object has a life cycle. An object is born, it likely goes through various states, and it eventually dies—being either archived or deleted
Don't mix this up with how the infrastructure (for example NHibernate) sees the transient/persistent. What I talk about here is the way I want the life cycle semantics for my Domain Model instances. It's then up to the infrastructure to help me with the wanted semantics behind the scenes.
resources
B1
B4 - map
resources
B4 - transient
an instance starts its life as transient when you do the following, for example:
Product p = new Product();
It is not fetched from the database as it has never become persistent
resources
B4 - Transient + delete
Repository.Delete(instance)
(instance will get deleted from database at x.PersistAll)
resources
B4
- persistent
If we want it to become persistent (and stored to the database at next call to PersistAll()), we need to ask a Repository for help by calling AddProduct(). Depending upon the infrastructure that is used, the Repository makes the infrastructure aware of the product.
Then again, when I ask the Repository for help with reconstituting an instance from the database, that fetched instance is persistent when I get it. All changes I make to it will be stored at next PersistAll().
resources
B4 - cascaded persistence
But what about OrderLine? I didn't ask the Repository to AddOrderLine(), but I did ask the Aggregate root Order to AddOrderLine(), and because of that the order line is made persistent, too. Within Aggregates, I think the persistence aspect should be cascaded.
resources
B4 - Persistent in Domain Model (and Database)
Repository.Get()
resources
B4 - Persistent in Database
x.PersistAll()
resources
B4 - Persistent in Domain Model
Repository.Add(instance) or persistentInstance.Add(instance)
resources
B4
- Layered Supertype pattern
a type that acts as the supertype for all types in its layer
entity base class
resources
B3
code & implementation
B3 - large model integrity strategy
It is important always to draw the CONTEXT MAP to reflect the current situation at any given time. Once that's done, though, you may very well want to change that reality. Now you can begin to consciously choose CONTEXT boundaries and relationships.
resources
B1 - 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, the other reflecting rules and knowledge that a user or superuser is able to customize.
KNOWLEDGE LEVEL is an application to the domain layer of the REFLECTION pattern, used in many software architectures and technical infrastructures. REFLECTION accommodates changing needs by making the software "self-aware," and making selected aspects of its structure and behavior accessible for adaptation and change.
This pattern should be used sparingly
resources
B1 - knowledge crunching
Through knowledge crunching, a team distills a torrent of chaotic information into a practical model
resources
B1 - immutability
in order for an object to be shared safely, it must be immutable: it cannot be changed except by full replacement.
resources
B1 - Highlighted Core
Marking off a privileged part of a model, along with the implementation that embodies it, is a reflection on the model, not necessarily part of the model itself. Any technique that makes it easy for everyone to know the CORE DOMAIN will do.
resources
B1 - The Flagged CORE
Flag the elements of the CORE DOMAIN within the primary repository of 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.
resources
B1 - The Distillation Document
Write a very brief document (three to seven sparse pages) that describes the CORE DOMAIN and the primary interactions among CORE elements.
resources
B1 - Process
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.
Use the distillation document as a guide. When developers realize that the distillation document itself requires change to stay in sync with their code or model change, then consultation is called for. Either they are fundamentally changing the CORE DOMAIN elements or relationships, or they are changing the boundaries of the CORE, including or excluding something different. Dissemination of the model change to the whole team is necessary by whatever communication channels the team uses, including distribution of a new version of the distillation document.
resources
B1
- generic subdomains
Identify cohesive subdomains that are not the motivation for your project. Factor out generic models of these subdomains and place them in separate MODULES. Leave no trace of your specialties in them.
Once they have been separated, give their continuing development lower priority than the CORE DOMAIN, and avoid assigning your core developers to the tasks (because they will gain little domain knowledge from them). Also consider off-the-shelf solutions or published models for these GENERIC SUBDOMAINS.
A GENERIC SUBDOMAIN is based on an expressive model that represents some aspect of how the team views the domain. In this it is no different than the CORE DOMAIN, just less central, less important, less specialized.
resources
B1 - flags
Take a look at the Flags attribute on the enumeration. This means that the values of this enumeration can be combined, and when ToString() is called on the enumeration, it will render a comma - separated list of enumeration values, such as “ Fax, Mail. ”
resources
B3 - factory
The Factory pattern of DDD is straightforward implementation-wise and is only about capturing and encapsulating the creation concept for certain classes.
some instantiation complexity was moved from the Order into a concept of its own. This also helped the clarity of the Domain Model to some degree. It's a good clue that the instantiation logic is interesting and complex.
beginning of the life cycle: create and reconstitute complex objects and AGGREGATES, keeping their internal structure encapsulated
there are two types of Factories, those for building the root Entity of an Aggregate (usually from some type of resultset data) and those for building Value objects (usually from some type of configuration data)
resources
B1
B3
B4
code & implementation
E1
E2 - valid state
What is typical of the Factory is that it sets up the instance in a valid state.
resources
B4 - null object pattern
One thing I have become pretty fond of doing is setting up the sub-instances with Null Objects if that's appropriate.
resources
B4
- factory framework
resources
B3
code & implementation
B3 - default values
Another example is that you can (indirectly) let the Factory go to the database to fetch default values.
resources
B4 - constructor
First of all, please note that sometimes a constructor is just what we want. What I'm getting at is that the complexity of the constructor increases
resources
B4
- explanatory model
one model should underlie implementation, design, and team communication. There is no need for explanatory models to be object models, and it is generally best if they are not.
resources
B1 - equality
necessary equality tests to determine whether two entity objects are equal to each other. These come in very andy later when comparing entity values in collections, trying to find matches, and so forth.
resources
B3 - equality for value objects
This is what the Equals() could look like for the Value Object ReferencePerson. (Note that I'm comparing all the fields of the Value Object, unlike how I did it with the Entity before. Also note that, Identity Map or not, overriding Equals() for Value Objects is needed.)
resources
B4
- entity
objects that are not fundamentally defined by their attributes, but rather by a thread of continuity and identity
resources
B1
B3
code & implementation
B3 - copy of entity
One thing I didn't like much was that Order has a relationship with Customer. Sure, an Order has a Customer, that's fine, but if I look at an Order one year later, I probably want to see the Customer information as it was when the Order was created, not as it is now.
I think creating another type with only the properties that are interesting might be a good solution here because it will also create an explicit boundary between the Aggregates, but especially because that's what the underlying model indicates. Let's create a CustomerSnapshot that only has the minimum amount of properties, and let it be a value object
resources
B4
- DSL
client code is written in a programming language tailored to a particular model of a particular domain. The program is then compiled, often into a conventional object-oriented language, where a library of classes provides implementations for the terms in the language.
In such a language, programs can be extremely expressive, and make the strongest connection with the UBIQUITOUS LANGUAGE. - domain vision statement
identifies the CORE DOMAIN in broad terms
A DOMAIN VISION STATEMENT can be used as a guidepost that keeps the development team headed in a common direction in the ongoing process of distilling the model and code itself. It can be shared with nontechnical team members, management, and even customers (except where it contains proprietary information, of course).
Write a short description (about one page) of the CORE DOMAIN and the value it will bring, the "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.
resources
B1 - domain modelling
Just as a moviemaker selects aspects of experience and presents them in an idiosyncratic way to tell a story or make a point, a domain modeler chooses a particular model for its utility
Each concept from the domain model should be reflected in an element of implementation
I will be designing the domain model, determining the RFI Aggregate
and its boundaries, and designing the Repository for RFI s.
resources
B1
B3
code & implementation
B3 - distillation
how to focus on the important and minimize or separate everything else; an object should be distilled until nothing remains that does not relate to its domain meaning or support its role in interactions.
resources
B1 - dependency
Every association is, of course, a dependency, and understanding a class requires understanding what it is attached to. Those attached things will be attached to still more things, and they have to be understood too. The type of every argument of every method is also a dependency. So is every return value.
Every dependency is suspect until proven basic to the concept behind the object. This scrutiny starts with the factoring of the model concepts themselves. Then it requires attention to each individual association and operation. Model and design choices can chip away at dependencies—often to zero.
Of course, there will be dependencies, and that isn't a bad thing when the dependency is fundamental to the concept.
when two objects are naturally tightly coupled, multiple operations involving the same pair can actually clarify the nature of the relationship. The goal is not to eliminate all dependencies, but to eliminate all nonessential ones. If every dependency can't be eliminated, each one that is removed frees the developer to concentrate on the remaining conceptual dependencies.
resources
B1 - declarative style
resources
B1 - declarative design
indicates a way to write a program, or some part of a program, as a kind of executable specification; this could be done through a reflection mechanism or at compile time through code generation (producing conventional code automatically, based on the declaration)
Rule-based programming is another promising approach to declarative design
resources
B1 - ddd framework
resources
B3
code & implementation
B3 - Customer/Supplier Development Teams
Often one subsystem essentially feeds another; the "downstream" component performs analysis or other functions that feed back very little into the "upstream" component, and all dependencies go one way. The two subsystems commonly serve very different user communities, who do different jobs, where different models may be useful. The tool set may also be different, so that program code cannot be shared.
The freewheeling development of the upstream team can be cramped if the downstream team has veto power over changes, or if procedures for requesting changes are too cumbersome. The up-stream team may even be inhibited, worried about breaking the downstream system. Meanwhile, the downstream team can be helpless, at the mercy of upstream priorities.
The process can be organized to balance the needs of the two user communities and schedule work on features needed downstream.
CUSTOMER/SUPPLIER TEAMS are more likely to succeed if the two teams work under the same management
resources
B1 - core domain
The harsh reality is that not all parts of the design are going to be equally refined. Priorities must be set. To make the domain model an asset, the model's critical core has to be sleek and fully leveraged to create application functionality.
Boil the model down. Find the CORE DOMAIN and provide a means of easily distinguishing it from the mass of supporting model and code. Bring the most valuable and specialized concepts into sharp relief. Make the CORE small.
it is unlikely that the CORE DOMAIN can be purchased.
you should be applying as much of your effort to the CORE DOMAIN as possible and investing in supporting GENERIC SUB-DOMAINS only as necessary.
Although a breakthrough to a deep model provides value anywhere it happens, it is in the CORE DOMAIN that it can change the trajectory of an entire project.
With the concept of the CORE DOMAIN, this impact can be made clear. Changes to the model of the CORE DOMAIN should have a big effect. Changes to widely used generic elements may require a lot of code updating, but they still shouldn't create the conceptual shift that CORE changes do.
Both GENERIC SUBDOMAINS and COHESIVE MECHANISMS are motivated by the same desire to unburden the CORE DOMAIN.
resources
B1 - continuous integration
CONTINUOUS INTEGRATION means that all work within the context is being merged and made consistent frequently enough that when splinters happen they are caught and corrected quickly. CONTINUOUS INTEGRATION, like everything else in domain-driven design, operates at two levels: (1) the integration of model concepts and (2) the integration of the implementation.
CONTINUOUS INTEGRATION is essential only within a BOUNDED CONTEXT
resources
B1 - integration of the implementation
the implementation artifacts are being integrated by a systematic merge/build/test process that exposes model splinters early
resources
B1 - integration of model concepts
Concepts are integrated by constant communication among team members. The team must cultivate a shared understanding of the ever-changing model. Many practices help, but the most fundamental is constantly hammering out the UBIQUITOUS LANGUAGE.
resources
B1
- context map
You can reduce confusion by defining the relationship between the different contexts and creating a global view of all the model contexts on the project.
Whatever form the MAP takes, it must be shared and understood by everyone on the project. It must provide a clear name for each BOUNDED CONTEXT, and it must make the points of contact and their natures clear.
Model contexts always exist, but without conscious attention they may overlap and fluctuate. By explicitly defining BOUNDED CONTEXTS and a CONTEXT MAP, your team can begin to direct the process of unifying models and connecting distinct ones.
resources
B1 - Conformist
When two development teams have an upstream/downstream relationship in which the upstream has no motivation to provide for the downstream team's needs, the downstream team is helpless. Altruism may motivate upstream developers to make promises, but they are unlikely to be fulfilled. Belief in those good intentions leads the downstream team to make plans based on features that will never be available. The downstream project will be delayed until the team ultimately learns to live with what it is given. An interface tailored to the needs of the downstream team is not in the cards.
Eliminate the complexity of translation between BOUNDED CONTEXTS by slavishly adhering to the model of the upstream team. Although this cramps the style of the downstream designers and probably does not yield the ideal model for the application, choosing CONFORMITY enormously simplifies integration. Also, you will share a UBIQUITOUS LANGUAGE with your supplier team. The supplier is in the driver's seat, so it is good to make communication easy for them. Altruism may be sufficient to get them to share information with you.
resources
B1 - conceptual load & overload
Practically speaking, "integers" don't add to the intellectual load. Beyond that, every additional concept that has to be held in mind in order to understand an object contributes to mental overload. Although we can generally ignore dependencies on primitive values such as integers and strings, we can't ignore what they represent.
For example, in the first paint mixing examples, the Paint object held three public integers representing red, yellow, and blue color values. The creation of the Pigment Color object did not increase the number of concepts involved or the dependencies. It did make the ones that were already there more explicit and easier to understand. On the other hand, the Collection size() operation returns an int that is simply a count, the basic meaning of an integer, so no new concept is implied.
resources
B1 - conceptual contour
Find the conceptually meaningful unit of functionality, and the resulting design will be both flexible and understandable. For example, if an "addition" of two objects has a coherent meaning in the domain, then implement methods at that level. Don't break the add() into two steps. Don't proceed to the next step within the same operation. On a slightly larger scale, each object should be a single complete concept, a "WHOLE VALUE."
The goal is a simple set of interfaces that combine logically to make sensible statements in the UBIQUITOUS LANGUAGE, and without the distraction and maintenance burden of irrelevant options.
resources
B1 - composite
We often encounter, while modeling complex domains, an important object that is composed of parts, which are themselves made up of parts, which are made up of parts—occasionally even nesting to arbitrary depth. In some domains, each of these levels is conceptually distinct, but in other cases, there is a sense in which the parts are the same kind of thing as the whole, only smaller.
Clients deal with the abstract type and have no need to distinguish leaves from containers.
resources
B1
http://www.dofactory.com/Patterns/PatternComposite.aspx - communication
everything in a domain-driven design is a communication mechanism
resources
B1 - Cohesive Mechanisms
The model of the CORE DOMAIN or a GENERIC SUBDOMAIN formulates a fact, rule, or problem. A COHESIVE MECHANISM resolves the rule or completes the computation as specified by the model.
Computations sometimes reach a level of complexity that begins to bloat the design. The conceptual "what" is swamped by the mechanistic "how." A large number of methods that provide algorithms for resolving the problem obscure the methods that express the problem.
You almost always want to remove MECHANISMS from the CORE DOMAIN.
COHESIVE MECHANISMS are by far most useful when they provide access through an INTENTION-REVEALING INTERFACE, with conceptually coherent ASSERTIONS and SIDE-EFFECT-FREE FUNCTIONS.
resources
B1 - bounded context
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.
BOUNDED CONTEXTS Are Not MODULES; keep track of which MODULE belongs in which CONTEXT. A naming convention might be used to indicate this, or any other mechanism that is easy and avoids confusion.
Bounded Contexts isn't the same as aggregates, but rather the same as subsystems or sub-models.
A typical reason for applying Bounded Contexts is that they provide a way of making it possible to scale up DDD to larger contexts.
resources
B1
B4 - partitions
It's possible that the Bounded Context is the same as a typical partition. It might also be that a Bounded Context is built up of several partitions instead, but probably not the opposite.
resources
B4 - cost
Although I see great value in boundaries, there are also costs. You might introduce a lot of overhead when it comes to communication and performance. As usual, keep it simple and add complexity when you gain more than the cost.
resources
B4 - Splinter
Many symptoms may indicate unrecognized model differences. Some of the most obvious are when coded interfaces don't match up. More subtly, unexpected behavior is a likely sign.
Combining elements of distinct models causes two categories of problems: duplicate concepts and false cognates.
what do you do if you've discovered a splinter—a model that is completely entangled but contains inconsistencies? Put a dragon on the map and finish describing everything. Then, with an accurate global view, address the points of confusion.
what do you do if you've discovered a splinter—a model that is completely entangled but contains inconsistencies? Put a dragon on the map and finish describing everything. Then, with an accurate global view, address the points of confusion.
resources
B1 - False cognates
This is the 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.
resources
B1 - Duplication of concepts
Duplication of concepts means that there are two model elements (and attendant implementations) that actually represent the same concept. Every time this information changes, it has to be updated in two places with conversions.
resources
B1 - code reuse
Code reuse between BOUNDED CONTEXTS is a hazard to be avoided. Integration of functionality and data must go through a translation.
resources
B1 - automated tests
Contact points with other BOUNDED CONTEXTS are particularly important to test. Tests help compensate for the subtleties of translation and the lower level of communication that typically exist at boundaries.
resources
B1
- association
For every traversable association in the model, there is a mechanism in the software with the same properties.
resources
B1 - archiving
- Anticorruption Layer
an ANTICORRUPTION LAYER is a means of linking two BOUNDED CONTEXTS
New systems almost always have to be integrated with legacy or other systems, which have their own models. Translation layers can be simple, even elegant, when bridging well-designed BOUNDED CONTEXTS with cooperative teams. But when the other side of the boundary starts to leak through, the translation layer may take on a more defensive tone.
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 no modification to the other system. Internally, the layer translates in both directions as necessary between the two models.
One way of organizing the design of the ANTICORRUPTION LAYER is as a combination of FACADES, ADAPTERS and translators, along with the communication and transport mechanisms usually needed to talk between systems.
resources
B1 - translator
The ADAPTER'S job is to know how to make a request. The actual conversion of conceptual objects or data is a distinct, complex task that can be placed in its own object, making them both much easier to understand. A translator can be a lightweight object that is instantiated when needed. It needs no state and does not need to be distributed, because it belongs with the ADAPTER(S) it serves.
resources
B1 - facade
A FACADE is an alternative interface for a subsystem that simplifies access for the client and makes the subsystem easier to use.
The FACADE belongs in the BOUNDED CONTEXT of the other system. It just presents a friendlier face specialized for your needs.
resources
B1 - adapter
An ADAPTER is a wrapper that allows a client to use a different protocol than that understood by the implementer of the behavior. When a client sends a message to an ADAPTER, it is converted to a semantically equivalent message and sent on to the "adaptee." The response is converted and passed back.
For each SERVICE we define, we need an ADAPTER that supports the SERVICE'S interface and knows how to make equivalent requests of the other system or its FACADE.
resources
B1
- Anemic Domain Model
- Analysis Patterns
Analysis patterns are groups of concepts that represent a common construction in business modeling. It may be relevant to only one domain or it may span many domains. For example there are analysis patterns for "Inventory and Accounting".
resources
B1 - aggregate
a cluster of associated objects that we treat as a unit for the purpose of data changes. Any object internal to an AGGREGATE is prohibited from access except by traversal from the root. This pattern is crucial to maintaining integrity in all phases of the life cycle
each Aggregate can only have one root object, and that object is an Entity object.
decide what objects belongs to the certain clusters of objects that you typically work with as single units, loading together (by default, at least for write scenarios), evaluating rules for together, and so on.
SPECIFICATIONS mesh smoothly with AGGREGATES
resources
B1
B3
B4
code & implementation
B3 - reachability
aggregates are the default mechanism for determining how big the loadgraphs should be ( how far from the target instance we should load instances)
O/R Mappers are often able to be configured for how far the reach of persist by reachability should go. But even when they are configured that way, the Aggregates are a very good guide in my opinion. What I mean is that I use the Aggregates for determining how far the reachability should reach, when I do the configuration.
resources
B4
code & implementation
B3 - Lazy Load
resources
B4 - snapshot
A typical example is to not load complete graphs when you need to list instances, such as Orders. Instead, you create a cut down type, perhaps called OrderSnapshot, with just the fields you need in your typical list situations. It's also the case that those lists won't be integrated with the Unit of Work and Identity Map, which probably is exactly what you want
resources
B4
- atomic operation
Again, I see Order and its OrderLines as an Aggregate, and the solution I plan to use for this feature will be oriented around that.
I will probably use an implementation of the Unit of Work pattern Fowler PoEAA for keeping track of the instances that have been changed, which are new, and which are deleted. Then the Unit of Work will coordinate those changes and use one physical database transaction during persistence.
resources
B4 - Concurrency unit
the Aggregate pattern is a good tool for controlling concurrency
Thanks to it, I get the unit I want to use and work with as a single whole.
resources
B4 - composition
All of the other classes in the diagram, except for ProjectContact, Company, and
SpecificationSection, belong to the RFI Aggregate. As shown in earlier chapters, ProjectContact belongs
to the Project Aggregate, Company is the root of its own Aggregate, and the SpecificationSection class is
part of the Submittal Aggregate.
resources
B3
code & implementation
B3
- Abstract Core
When there is a lot of interaction between subdomains in separate MODULES, either many references will have to be created between MODULES, which defeats much of the value of the partitioning, or the interaction will have to be made indirect, which makes the model obscure.
Identify the most fundamental concepts in the model and factor them into distinct classes, abstract 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, while the specialized, detailed implementation classes are left in their own MODULES defined by subdomain.
resources
B1 - trial and error
The examples I've given don't convey the amount of trial and error involved. I might follow half a dozen leads in conversation before finding one that seems clear and useful enough to try out in the model. I'll end up replacing that one at least once later, as additional experience and knowledge crunching serve up better ideas. A modeler/designer cannot afford to get attached to his own ideas.
resources
B1 - specification
SPECIFICATION is an adaptation of an established formalism, the predicate.
specialized objects that evaluate to a Boolean, little truth tests that can be factored out into a separate VALUE OBJECT; concise way of expressing certain kinds of rules, extricating them from conditional logic and making them explicit in the model
resources
B1
B3
code & implementation
E1
E2 - evaluation
For example, there might be a Specification class called ReadyToInvoiceSpecification with a method like this:
public bool Test(Order o);
resources
E13 - Subsumption
A more stringent SPEC subsumes a less stringent one. It could take its place without any previous requirement being neglected.
resources
B1 - specification framework
resources
B3
code & implementation
E1
E2 - composition
works very well with composition: a class can respond to clients queries by checking if it satisfies the specifications it contains
code & implementation
E2 - Combining Using Logical Operators
When using SPECIFICATIONS, you quickly come across situations in which you would like to combine them. As just mentioned, a SPECIFICATION is an example of a predicate, and predicates can be combined and modified with the operations "AND," "OR," and "NOT." These logical operations are closed under predicates, so SPECIFICATION combinations will exhibit CLOSURE OF OPERATIONS.
resources
B1 - Validation
The simplest use of a SPECIFICATION is validation: To validate an object to see if it fulfills some need or is ready for some purpose
resources
B1
B3
code & implementation
B3 - SPECIFICATION-based queries
One particularly apt approach to generalizing REPOSITORIES through a framework is to use SPECIFICATION-based queries
resources
B1 - Selection (or Querying)
The same concept of SPECIFICATION can be applied here: To select an object from a collection
resources
B1 - Building to Order (Generating)
can mean creation of an object from scratch, but it can also be a configuration of preexisting objects to satisfy the SPEC. The same concept of a SPECIFICATION that was applied to validation and selection. We are specifying criteria for objects that are not yet present.
- Processes
processes that exist in the domain, which we have to represent in the model (example: a shipping system that routed cargo; this routing process was something with business meaning)
A SERVICE is one way of expressing such a process explicitly
When there is more than one way to carry out a process, another approach is to make the algorithm itself, or some key part of it, an object in its own right. The choice between processes becomes a choice between these objects, each of which represents a different STRATEGY.
resources
B1 - predicates
Predicates are functions that evaluate to "true" or "false" and can be combined using operators such as "AND" and "OR" to express more complex rules
resources
B1 - Explicit Constraints
there are lots of cases when a constraint just can't fit comfortably in a single method. Or even if the method stays simple, it may call on information that the object doesn't need for its primary responsibility. The rule may just have no good home in an existing object.
resources
B1 - domain refactoring
nearly all the literature on how to refactor focuses on mechanical changes to the code that make it easier to read or to enhance at a very detailed level. The refactorings that have the greatest impact on the viability of the system are those motivated by new insights into the domain or those that clarify the model's expression through the code.
resources
B1 - breakthrough
To set the stage for a breakthrough, concentrate on knowledge crunching and cultivating a robust UBIQUITOUS LANGUAGE. Probe for important domain concepts and make them explicit in the model. Refine the design to be suppler. Distill the model. Push on these more predictable levers, which increase clarity—usually a precursor of breakthroughs. Don't hold back from modest improvements
resources
B1 - books
Don't overlook the obvious when seeking model concepts. In many fields, you can find books that explain the fundamental concepts and conventional wisdom.
resources
B1 - "find or create" functionality
One other case that drives people to combine FACTORY and REPOSITORY is the desire for "find or create" functionality, in which a client can describe an object it wants and, if no such object is found, will be given a newly created one. This function should be avoided
resources
B1
You can find the entire list of techniques in progress in the Development base concepts category. Please feel free to leave any comments or suggestions which could make these lists more useful for everyone.
Also, if you are interested in learning these skills you can try the Developer training modules.
Enjoy programming!
I am putting together a set of concept lists for the main programming techniques, which should help developers learning or using them to be more efficient. Here are the techniques in progress:
Please feel free to leave any comments or suggestions which could make these lists more useful for everyone.
Also, if you are interested in learning these techniques you can try the developer training modules.
Again, please feel free to leave any comments or suggestions which could make the training modules more useful for everyone. We are having great results with them at Akcedo (so they really work), but they can always be improved. Also, if you would like to use the modules or are already using them and you want to discuss about the process feel free to comment and ask questions here.