1) The document discusses the experiences of applying domain-driven design (DDD) principles to a project to build a new underwriting platform for an insurance company called Beazley.
2) Key aspects of DDD discussed include identifying the domain model, ubiquitous language, bounded contexts, and modeling concepts like entities, value objects, aggregates and events.
3) Applying these DDD principles revealed insights but also led to some misunderstandings along the way. Maintaining integrity across bounded contexts as the model evolved proved challenging.
Handwritten Text Recognition for manuscripts and early printed texts
DDD-Experience-Report
1. domain driven design: Experience report Putting the Model at the heart of development
2. Who are you? Software Developer for 18 years Worked mainly for ISVs Reuters, SunGard, Misys Worked for a couple of MIS departments DTI, Beazley Microsoft MVP for C# Interested in OO design Interested in Agile methodologies and practices No smart guys Just the guys in this room Ian Cooper www.codebetter.com
3. Revelations and Misunderstandings Distillation Ubiquitous Language Maintaining Model Integrity A Model Expressed in Software Ian Cooper www.codebetter.com
4. What was wanted? Ian Cooper www.codebetter.com Distillation Revelations
5. Beazley’s Goal A new underwriting platform Ian Cooper www.codebetter.com
6. Key Requirements Manage the Underwriting lifecycle High-Volume, Low Margins Configure new products, rules and workflows Ian Cooper www.codebetter.com
7. Build or Buy Customer focused on build vs. buy Ian Cooper www.codebetter.com
9. Splitting out Domains Domains often relate to business activities Within a team still look for activities Ian Cooper www.codebetter.com
10. Finding our Generic Domains Document Generation Rules Engine Rating Engine General Ledger Feeds Human Workflow Ian Cooper www.codebetter.com
11. Finding Our Supporting Domains Document Management System Broker Database Ian Cooper www.codebetter.com
12. Core Domain Vision Statement The Domain Model will represent the life cycle of a risk such that the key decision points required to process risk may be audit trailed. The model should also represent the notion of an account with whom Beazley do business, to allow key events on the account to be easily identified. The view of accounts and their associated risks must be sufficiently detailed to support underwriting decisions. The model should support the addition of new products by configuration instead of changes to the model. Ian Cooper www.codebetter.com
13. What was wanted? Ian Cooper www.codebetter.com Requirements Misunderstandings
14. Segregate the Core Do not stop distilling at component boundary An application has generic and sub-domains The core is smaller than you think! Ian Cooper www.codebetter.com
15. Cohesive Mechanisms Ian Cooper www.codebetter.com Cohesive mechanisms an important way to ease the burden of using the model It get hard to see the model if you have too much CS noise Some cohesive domains seem to emerge from the domain as complexity increases Some we know about from discussing the model
16. State and Rules Engines A risk proceeds through states in response to events We execute rules at key life-cycle points Ian Cooper www.codebetter.com
17. ‘What’ from ‘How’ Want to define rules that run at a transition, not how rules are run Want rules to be point of extension that users can use to add rules too Ian Cooper www.codebetter.com
18. Specifications and Rules Engines A specification is a predicate, an abstraction for a rule A rules engine can be used to provide a DSL to allow user extension Confusion from two mechanisms Ian Cooper www.codebetter.com
19. Hiding Complexity User Defined Rules are implemented by the rules engine But we abstract them as part of the same rules engine at state transition that executes all specifications So we hide the complexity behind a cohesive mechanism Ian Cooper www.codebetter.com
20. Exploring the language of the domain Ian Cooper www.codebetter.com Ubiquitous Language - Revelations
21. The Ubiquitous Language Some concepts hidden without this No real notion of Account for example Ubiquitous language reduces re-work Sharing model flushes out concepts Ian Cooper www.codebetter.com
22. Exploring the language of the domain Ian Cooper www.codebetter.com Ubiquitous Language - Misunderstandings
23. Beware Context Shifts Sometimes it sounds like people are talking about the same thing, because they use the same terms Beware you may be in different contexts without realizing it Recognize that the ubiquitous language describes a model Ian Cooper www.codebetter.com
24. Confusion Sometimes its not a context shift People can be inexact in terminology Try two ‘domain experts’ who don’t work together Remember the model may not be real Ian Cooper www.codebetter.com
25. Ian Cooper www.codebetter.com Maintaining Model Integrity
26. Context Mapping Ian Cooper www.codebetter.com Identified multiple Bounded Contexts (BC) Our BCs came from different teams All had different views of shared concepts In some cases multiple BCs with one development team, in other cases across teams
29. Where we are heading Ian Cooper www.codebetter.com
30. Ian Cooper www.codebetter.com A Model Expressed In Software
31. Ian Cooper www.codebetter.com Modeling - Revelations
32. Aggregates have great power Help prevent anemic domain models They simplify Reduces complexity of the graph Are forces for cohesion Keep infrastructure from domain (Aggregates look to play nice with NoSQL) Ian Cooper www.codebetter.com
33. Entities and Value Types A lot of objects are not entities Comparison by state more common than by Id Allows us to use immutability (Still hard to get developers to see value types) (Still too many primitives not decently clothed in value types) Ian Cooper www.codebetter.com
34. Events are a natural part of the model ‘Risk’ lifecycle is a series of events State is sum of all events that have happened A lot of MI is ‘what happened when’ What events occurred on the risk Events may be ‘out-of-sequence’ Traditionally a thorny problem for MTAs Event sourcing is a powerful tool for this Also solves problem of ‘view on date’ etc. Ian Cooper www.codebetter.com
35. Ian Cooper www.codebetter.com Modeling - Misunderstandings
36. References between aggregates Holding a reference to an aggregate root encourages use of one aggregate within methods on another. Also leads to one root composing other roots Use Domain Events to Update across aggregates Ian Cooper www.codebetter.com
37. Repositories of Queries Queries crust over Repositories like barnacles on the hull of a ship Breaks the ‘collection’ paradigm Introduces Infrastructure concerns like lazy loading At best buries domain logic, at worst is not a domain concern Query Object can help… But separating commands and queries better Ian Cooper www.codebetter.com
38. Ian Cooper www.codebetter.com One thing to remember
39. The Key to Success “One way or another, creating distinctive software comes back to a stable team accumulating specialized knowledge and crunching it into a rich model. No shortcuts. No magic bullets.” Domain Driven Design – Evans Ian Cooper www.codebetter.com
Build a new underwriting platform Initially targeting US business Existing legacy landscape Bastardized mix of older systems designed for UK and local ‘tactical’ choices Written in ASP.NET, Windows Forms, Access, ExcelExisting platform cannot scale and allow growth Back office capacity seen as key limiter to US growth The Challenge The company concerned about an in-house project Feeling that underwriting not IT is its core capability Previous large IT projects had failed External bidders in Lloyds market immature ROI and cost a factor in choosing final system
Key RequirementsThe solution should be highly configurable Ability to add new products easily A new product is: New fields to capture New rules about how to process Specialist rules like rating General rules like validation, tax Ability to alter workflow System should not determine business process Business process should be alterable by configuration
Build vs. Buy is a problem because it makes a binary choice, build locally, with advantages of capturing “our special sauce” and buy with advantages of third-party expertise and maintenance. We wanted to look at building some parts and buying others. Our goal was to find the core domain and build that, buying, outsourcing, or using other low cost solutions to meet other needs. DDD calls this approach to searching out the core domain model, distillation.Identify core domain – not build/buySystems are a mixBuild where you add valueBuild where you can do ‘just enough’Buy where it is a commodityBuy where easier to adapt than buildReduces cost and riskFocus the effort on where you can add valueBest people in the domain - not infrastructure
Distillation Distillation is the 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. Now, stepping back for a strategic view, this chapter looks at ways to distinguish broad swaths of the model and distill the domain model as a whole. As with many chemical distillations, the separated by-products are themselves made more valuable by the distillation process (as GENERIC SUBDOMAINS and COHERENT MECHANISMS), but the effort is motivated by the desire to extract that one particularly valuable part, the part that distinguishes our software and makes it worth building: the “ CORE DOMAIN.” Strategic distillation of a domain model does all of the following: 1 . Aids all team members in grasping the overall design of the system and how it fits together 2. Facilitates communication by identifying a core model of manageable size to enter the UBIQUITOUS LANGUAGE 3. Guides refactoring 4. Focuses work on areas of the model with the most value 5. Guides outsourcing, use of off-the-shelf components, and decisions about assignments A simple DOMAIN VISION STATEMENT communicates the basic concepts and their value with a minimum investment. The HIGHLIGHTED CORE can improve communication and help guide decision making—and still requires little or no modification to the design. More aggressive refactoring and repackaging explicitly separate GENERIC SUB DOMAINS, which can then be dealt with individually. COHESIVE MECHANISMS can be encapsulated with versatile, communicative, and supple design. Removing these distractions disentangles the CORE. Repackaging a SEGREGATED CORE makes the CORE directly visible, even in the code, and facilitates future work on the CORE model. And most ambitious is the ABSTRACT CORE, which expresses the most fundamental concepts and relationships in a pure form (and requires extensive reorganizing and refactoring of the model). Each of these techniques requires a successively greater commitment, but a knife gets sharper as its blade is ground finer. Successive distillation of a domain model produces an asset that gives the project speed, agility, and precision of execution. To start, we can boil off the least distinctive aspects of the model. GENERIC SUBDOMAINS provide a contrast to the CORE DOMAIN that clarifies the meaning of each. . . The planning process must drive resources to the most crucial points in the model and design. To do that, those points must be identified and understood by everyone during planning and development. Those parts of the model distinctive and central to the purposes of the intended applications make up the CORE DOMAIN. The CORE DOMAIN is where the most value should be added in your system. The greatest value of custom software comes from the total control of the CORE DOMAIN. A well-designed framework may be able to provide high-level abstractions that you can specialize for your use. It may save you from developing the more generic parts and leave you free to concentrate on the CORE. But if it constrains you more than that, then there are three likely possibilities. 1 . You are losing an essential software asset. Back off restrictive frameworks in your CORE DOMAIN . 2. The area treated by the framework is not as pivotal as you thought. Redraw the boundaries of the CORE DOMAIN to the truly distinctive part of the model. 3. You don't have special needs in your CORE DOMAIN. Consider a lower-risk solution, such as purchasing software to integrate with your applications. One way or another, creating distinctive software comes back to a stable team accumulating specialized knowledge and crunching it into a rich model. No shortcuts. No magic bullets. GENERIC SUBDOMAINThere is a part of your model that you would like to take for granted. It is undeniably part of the domain model, but it abstracts concepts that would probably be needed for a great many businesses. For example, a corporate organization chart is needed in some form by businesses as diverse as shipping, banking, or manufacturing. For another example, many applications track receivables, expense ledgers, and other financial matters that could all be handled using a generic accounting model. Can really be divided up furhter into two parts, and Eric seems to identify this split now too: GENERIC DOMAIN – Needed by a wide variety of businesses, a commodity software item i.e. accounting packagesSUPPORTING SUBDOMAIN – Not an area where you can add critical value but one where you have behaviour that is not a commodity. Option 1: An Off-the-Shelf Solution Sometimes you can buy an implementation or use open source code. Advantages • Less code to develop. • Maintenance burden externalized. • Code is probably more mature, used in multiple places, and therefore more bulletproof and complete than homegrown code. Disadvantages • You still have to spend the time to evaluate it and understand it before using it. •Quality control being what it is in our industry, you can't count on it being correct and stable. • It may be overengineered for your purposes; integration could be more work than a minimalist homegrown implementation. Option 2: A Published Design or Model Advantages More mature than a homegrown model and reflects many people's insights • Instant, high-quality documentation Disadvantage May not quite fit your needs or may be overengineered for your needs Option 3: An Outsourced Implementation Advantages Keeps core team free to work on the CORE DOMAIN, where most knowledge is needed and accumulated. Allows more development to be done without permanently enlarging the team, but without dissipating knowledge of the CORE DOMAIN. Forces an interface-oriented design, and helps keep the subdomain generic, because the specification is being passed outside. Disadvantages Still requires time from the core team, because the interface, coding standards, and any other important aspects need to be communicated. Option 4: An In-House Implementation Advantages • Easy integration. • You get just what you want and nothing extra. •Temporary contractors can be assigned. DisadvantagesOngoing maintenance and training burden. It is easy to underestimate the time and cost of developing such packages.
Domains often relate to business activitiesSeparate teams may own different domainsUnderwritingComplianceFinanceReinsuranceWithin a team still look for activitiesConfiguration different from useWorkflow different from system of record
Document GenerationOff-the-shelf solutionPitney-BowesAdvantagesLess code to develop (integration only)Maintenance burden externalizedMature, feature richDisadvantagesTime to understand 3rd party modelComplexity of model mappingRules EngineOff-the-shelf solutionInRule AdvantagesLess code to develop Mature, feature richMaintenance burden externalizedDisadvantagesTime to understand Rule author training training, API trainingEntity model, rule languagesComplexity of model mappingHuman WorkflowOff-the-Shelf JobTraQ (Swift)AdvantagesLess code to developCan swap to a different workflow system if something “better” emergesForces clean separation of workflow and system of recordMaintenance burden externalizedDisadvantagesAPI allows us to call the workflow engine but not vice-versaNeed to rely on well-know points to call workflow engineDiminishes separation of concernsHave to exchange a lot of “catalogue” dataRating EngineOff-the-Shelf Solution (DRC)AdvantagesLess code to developMature features such as Excel based definition of rating algorithmMaintenance burden externalizedDisadvantagesConstrained to expression via Excel functionsFeedsOff-the-Shelf Solutions (Pitney Bowes, others)AdvantagesLess code to developLess need to manage 3rd party sourcesDisadvantagesGeneric so require model-to-model mappingFrequent API Change
Document Management SystemAn In-House ImplementationUsing SharePointNot just generic as we need to define taxonomy, produce team pages etc.AdvantagesBuilt to orderEasy integrationDisadvantagesOwn maintenance costs going forwardEasy for costs to spiralInteraction between teams increases ceremonyBroker DatabaseNot just generic as domain has business rulesBrokers need to be licensedAn Outsourced ImplementationAdvantagesTeam unfamiliar with the product being used MS CRMTeam free to focus on core domainIncreases capacity of team without increasing permanent headcountForces a ‘design-by-contract’ approachDisadvantagesHave to adopt a more “waterfall” approach with up-front requirements documents “over-the-fence”Re-work as ‘actual’ requirements uncoveredNot developed to similar standards i.e. test-first approachesMakes hand-back internally much more difficultTime required from the core team to communicate may have exceeded time savings on outsourcing.
“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.”Core Domain seen as the ‘glue’Perception of core domain as glue for other partsBy controlling this hub we canSwap 3rd party componentsAdd other components in the futureThe Domain Vision Statement may not be enough to properly identify the core.It may be necessary to highlight what is in the core.A distillation document is one way to achieve this. “A distillation document is not a complete design document. It is a minimalist entry point that delineates and explains the CORE and suggests reasons for closer scrutiny of particular pieces”Domain Driven Design – Evans
Do not stop distilling at application boundary We stopped distilling once we had identified the risk lifecycle management application as ‘core’. But really this was too high a level.An application has generic and sub-domains Within that application we had some sub-domains. For example, as for any application we had a significant amount of catalogue data such as lists of underwriters, markets, teams etc. None of these needed the analysis, effort or design of the core domain. They emerged to be a supporting sub-domain. We needed the information in them to do our work, but these were not core parts of our model. The Account was seen as a key part of our model, but again there was little interaction with it that was task based. Our risk lifecycle used such core information but was not consumed by it. Our core domain was our risk lifecycle – the stages in the processing of the risk, the decisions made at those stages, and the consequences of those decisions. Even there it was possible to separate out an abstract of the interaction of submission – risk – policy. Conversely we too often treated product configuration as a supporting domain, not spending sufficient resources on it, treating more as a generic sub-domain, because it faced back office consumers. Yet the ease of configuration was a key system goal and we did not emphasize it enough as a core domain. One advantage of having recognized this earlier would have been making earlier decisions around packaging into modules that would have given us advantage.The Costs of Creating a SEGREGATED CORESegregating the CORE will sometimes make relationships with tightly coupled non- CORE classes more obscure or even more complicated, but that cost is outweighed by the benefit of clarifying the CORE DOMAIN and making it much easier to work on. The SEGREGATE D CORE will let you enhance the cohesion of that CORE DOMAIN . There are many meaningful ways of breaking down a model, and sometimes in the creation of a SEGREGATED CORE a nicely cohesive MODULE may be broken, sacrificing that cohesion for the sake of bringing out the cohesiveness of the CORE DOMAIN . This is a net gain, because the greatest value added of enterprise software comes from the enterprise-specific aspects of 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’.Domain Driven Design – EvansEncapsulating mechanisms is a standard principle of object-oriented design. Hiding complex algorithms in methods with intention-revealing names separates the “what” from the “how.” This technique makes a design simpler to understand and use. Yet it runs into natural limits.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.This proliferation of procedures is a symptom of a problem in the model. Refactoring toward deeper insight can yield a model and design whose elements are better suited to solving the problem. The first solution to seek is a model that makes the computation mechanism simple. But now and then the insight emerges that some part of the mechanism is itself conceptually coherent. This conceptual computation will probably not include all of the messy computations you need. We are not talking about some kind of catch-all “calculator.” But extracting the coherent part should make the remaining mechanism easier to understand.Therefore: Partition a conceptually COHESIVE MECHANISM into a separate lightweight framework. Particularly watch for formalisms or well-documented categories of algorithms. Expose the capabilities of the framework with an INTENTION-REVEALING INTERFACE. Now the other elements of the domain can focus on expressing the problem (“what”), delegating the intricacies of the solution (“how”) to the framework.For usboth the state machine and decision points became a cohesive mechanism
We use a state-machine to handle transitions, driven by events.We have two types of rulesWell-KnownDo not varyApply across product rangesUsually simpleE.g. Broker Commission, if TRIA selected -> add a percentage…User-DefinedVary across product, US state, timeE.g. State based taxes
We do not want to cloud processing a riskHow we execute rule is infrastructure concernWe need to abstract rules engineMake it declarativeSeparate what from howBut allow domain to know of ruleDomain formulates the ruleOr point that check can be performedCohesive mechanism resolves the rule
A specification is a predicateDetermines if an object meets criteriaMany are simple testsDoes broker commission exceed 100%Can be combined with logical operatorsAnd, Or, XOR etc.Just create an abstract base class for combiningAllows us to declaratively express combinationCan be created by a factoryUnder these conditions, use these rules
User Defined Rules are implemented by the rules engineIt is a separate bounded contextWe use an Open API to communicateMore on this laterBut we abstract them behind a specificationWe call it a Decision PointAnd it just implements ISpecification<T>So we can combine it with other specificationsSo we hide the mechanism And just allow you to declare a call to user-defined rules
“The model-based language should be used among developers to describe not only artifacts in the system, but tasks and functionality. This same model should supply the language for the developers and domain experts to communicate with each other, and for the domain experts to communicateamong themselves about requirements, development planning, and features. The more pervasively the language is used, the more smoothly understanding will flow.”Domain Driven Design – EvansWe used ubiquitous language in the CoreEasier communication with expertsNo need to translate to the modelEasier expression of acceptance criteriaEasier ‘problem’ reportingIts ‘turtles all the way down’Model expressed in UI termsSo if we change UI… we change modelModel expressed in DbNot just in the OO layerSeparate reporting and transactional storeBut not for renamingFocus on shared language flushes concepts from cover“Synonyms” often hide two conceptsYou may need to flush both outFor us a key one was Account vs. RiskOften used together by customerSo we asked: are they the same?Revealed lack of ‘account’ perspectiveTurned out to be key issue with old system
Beware hidden context shiftsToo easy to miss subtleties if you don’t listenFor brokers we equated two modelsGroup -> Branch -> ContactAgency->Affiliate->IndividualWe heard both termsAnd we proposed the mappingDon’t propose…listenRemember – White Men Can’t JumpThese correspondences were falseThe Underwriting ModelBroker -> Group -> ContactInterested in who we do business withWas not…The Compliance ModelAgency -> Affiliate -> IndividualInterested in licensing of brokers
Sometimes its not a context shiftPeople can be inexact in terminologyTry two ‘domain experts’ who don’t work together They’ll ask each other questions and try to understand if this is the ‘same’ or different, far faster than you would.
“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”Domain Driven Design – EvansIdentify each model in play on the project and define its BOUNDED CONTEXT. This includes the implicit models of non-object-oriented subsystems. Name each BOUNDED CONTEXT, and make the names part of the UBIQUITOUS LANGUAGE.Describe the points of contact between the models, outlining explicit translation for any communication and highlighting any sharing.Identified multiple Bounded Contexts (BC)Our BCs came from different teams All had different views of shared conceptsIn some cases multiple BCs with one development team, in other cases across 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.”Domain Driven Design – EvansXP Style Customer->DeveloperCustomer defines prioritiesDefines acceptance testsAutomated preferablySupplier deliversBy priority in iterationTo meet acceptance testsAnti-Corruption Layer“On a large project, one subsystem will often have to interface with several other, independently developed subsystems. These will reflect the problem domain differently. When systems based on different models are combined, the need for the new system to adapt to the semantics of the other system can lead to a corruption of the new system's own model.”Domain Driven Design – EvansOpen-Host Interfaces“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 oneoff translator to augment the protocol for that special case so that the shared protocol can stay simple and coherent”. Domain Driven Design – Evans
Aggregates provide transactional boundaries Only the aggregate needs to be consistent and atomic We get few deadlocks, and can handle concurrency optimistically trough versioningAggregates prevent anemic domain modelsInstead of working in the serviceOr working in the DbThe service grabs the aggregateFrom the repositoryAnd methods on the aggregateNavigate the graph to provide functionalityBecause your force the domain logic into codeBy being against the entitiesYou become full-bloodedAggregates simplify Reducing the number of links between entities simplifies models(Aggregates play nice with NoSQL) Get/Post by id, hold your dependent object graph in JSON
A lot of objects are not entities Its easy to think of everything as an entity, particularly when storing to a relational tableComparison by state more common than by Id But in most cases we never compare them by identity only by state (if we compare them at all)Allows us to use immutability Besides their value in simplifying concurrency issues, value types can be simpler to use when trying to get information hiding on our objects.
Holding a reference to an aggregate root encourages use of one aggregate within methods on another. Methods on one aggregate, such as Submission, end up calling methods on other aggregates such as on Risk, so logic flows across many aggregates. This leads to the question of how we can preserve a transactional boundary at the aggregate level when we are updating one or more aggregates! We end up with a transaction spanning multiple aggregates in this case, which breaks the transactional boundary and can lead to deadlocks if someone else is accessing the ‘other’ aggregate through a different mechanism.Leads to one root aggregating others Most of our aggregate roots hold an instance or instances of other aggregate roots. So for example a Submission holds one or more risks. This can be awkward if we wanted to forget to make the other aggregate abstract as it prevents us from easily swapping one aggregate root implementation for another. Effectively we couple between our aggregates. This would not work well with NoSQL for example as the JSON graph would contain another document’s contents – where would the truth live. Better to think of all references as implying compositionUse Domain Events to Update across aggregates When we change one aggregate root publish an event. Allow other aggregates to subscribe to that event if they are interested and take appropriate action. By making the event publishing reliable we overcome the problem of transactional boundaries as now we can start a transaction on the subscriber when they handle an event.