Saturday, September 5, 2020

Code Recording Project

 I'd like to go ahead and share a bit of something that I've been working on. I've been working on a code recording application that is meant to go hand in hand with programming video tutorials and essentially level up the programming video tutorial experience in multiple ways. I'll be touching on the two features that I've built so far, which are searchability and code accessibility, which I believe will make the video tutorial a more powerful learning experience.

Now it is worth noting that the reason why I'm only sharing videos of this functionality as opposed to providing a demo application is simply because I don't have this deployed to a production environment as of yet. That is in fact the current thing that I'm working on, and to that end I'm currently working through setting up Kubernetes, Istio, and OAuth. Hopefully within the next month or two, I'll be to a point where I'll have a simple MVP in place where I can send people and they can try it out and give me some feedback.

And so with that, let's take a look at things:

Searchability

So a scenario that I've run into frequently when it comes to learning from video tutorials is that I may not immediately need what I'm learning when I'm learning it, but rather it may be a few weeks or even a few months out before I run into a situation where I need to use what I learned. It's usually at this point in time that I remember that I'd learned something about this particular topic in a video tutorial or video tutorial series, but now I'm a little fuzzy on the details. So I then head back over to the video tutorial and then proceed to skip around the video, trying to find that one spot in the video that talked about the one thing that I need right now.

Searchability fixes this issue. I can simply type in a small snippet of the code that is relevant to what I'm trying to find, and the code recording will highlight the spot (or spots, if there were multiple instances) in the video where that snippet of code was typed in the video tutorial. This allows me to not waste time finding that part of the video that I'm looking for.

Here's an example of searchability in action:


Code Accessibility

The other issue that I've run into with programming video tutorials is that once you've found what you're looking for in the video, you run into the problem of getting the code out of the video and in to your own code so that you can start using and tweaking it. The process usually involves opening the video on one side of the screen and your code editor on the other side of the screen, pausing the video on the frame with the needed code snippet, and then transcribing the code over into your project. If you're unlucky enough to be looking at a code snippet that doesn't all fit on the screen at once, you'll likely have to skip around to different frames to be able to see all the code and transcribe the necessary parts. This is tedious and error prone.

Code Accessibility fixes this by making so that with the click of a single button, you're given access to what the code looks like in the project at that specific frame. And what's more, you can also choose to download the project in it's entirety at that specific frame. This gives you access to the code you need with minimal effort, allowing you to instead put all your effort into the code that you're crafting.

And with that, here's an example of code accessibility in action:


And with that, there's a sneak peak into what's been consuming my evening and weekends as of late. I personally think that it's got a lot of potential, but it's also got a long ways to go. So with that, I'll keep plugging at it, and with any luck before too long I'll have a fully working example up and running and in the wild.

Saturday, August 29, 2020

Domain Driven Design Review and Book Club Experience

 Reading through Domain Driven Design can be a real eye opener. While it can be hard to wrap your head around some of the content in the book, the author does an amazing job breaking down and explaining things, and the book is chock full of things that I wish more developers had a better understanding of. With that said, there are a few things here and there that are slightly dated in the book, but overall it's aged quite well. There's a reason why so many people consider the book to be a classic and a must read.

Now, as to the book club experience, I'd say that it went fairly well considering that it coincided with the Covid-19 state of emergency. We ultimately moved it online, such that we'd meet once a week using Google Meet. Most things were able to play out similarly to how we'd done things before, whereas before I'd cast my screen to a tv screen in the meeting room, now I simply present my screen during the conference call.

This book was another book that covered a number of things at a higher level, and as such practice problems wouldn't necessarily always apply well, so similar to the Accelerate book that we'd covered previously, I went ahead and did chapter summaries for this book. This ultimately helped stimulate conversation among the group, and also provided a way for those in the group who couldn't do the reading for the week a way to still come and participate. You can check out these chapter summaries below:

Chapter 1

Chapter 2

Chapter 3

Chapter 4

Chapter 5

Chapter 6

Chapter 7

Chapter 8

Chapter 9

Chapter 10

Chapter 11

Chapter 12

Chapter 13

Chapter 14

Chapter 15

Chapter 16

Chapter 17

Friday, August 28, 2020

Domain Driven Design Chapter 17 Summary

 Chapter 17: Bringing the Strategy Together

    • "The preceding three chapters presented many principles and techniques for domain-driven strategic design. In a large, complex system, you may need to bring several of them to bear on the same design."
  • Combining Large-Scale Structures and Bounded Contexts
    • "The three basic principles of strategic design (context, distillation, and large-scale structure) are not substitutes for each other; they are complementary and interact in many ways. For example, a large-scale structure can exist within one bounded context, or it can cut across many of them and organize the context map."
    • "But on many projects, the greater challenge is to understand how disparate parts fit together. They may be partitioned into separate contexts, but what part does each play in the whole integrated system and how do the parts relate to each other? Then the large-scale structure can be used to organize the context map."
  • Combining Large-Scale Structures and Distillation
    • "The concepts of large-scale structure and distillation also complement each other. The large-scale structure can help explain the relationships within the core domain and between generic subdomains."
    • "At the same time, the large-scale structure itself may be an important part of the core domain. For example, distinguishing the layering of potential, operations, policy, and decision support distills an insight that is fundamental to the business problem addressed by the software. This insight is especially useful if a project is carved up into many bounded contexts, so that the model objects of the core domain don’t have meaning over much of the project."
  • Assessment First
    • "Draw a context map. Can you draw a consistent one, or are there ambiguous situations?"
    • "Attend to the use of language on the project. Is there a ubiquitous language? Is it rich enough to help development?"
    • "Understand what is important. Is the core domain identified? Is there a domain vision statement? Can you write one?"
    • "Does the technology of the project work for or against a model-driven design?"
    • "Do the developers on the team have the necessary technical skills?"
    • "Are the developers knowledgeable about the domain? Are they interested in the domain?"
  • Who Sets the Strategy?
    • Emergent Structure from Application Development
      • "A self-disciplined team made up of very good communicators can operate without central authority and follow evolving order to arrive at a shared set of principles, so that order grows organically, not by fiat."
    • A Customer-Focused Architecture Team
      • " An architecture team can act as a peer with various application teams, helping to coordinate and harmonize their large-scale structures as well as bounded context boundaries and other cross-team technical issues. To be useful in this, they must have a mind set that emphasizes application development."
      • "[Architecture team] members are true collaborators with development, discovering patterns along with the developers, experimenting with various teams to reach distillations, and getting their hands dirty."
  • Six Essentials for Strategic Design Decision Making
      • "Decisions must reach the entire team."
        • "Obviously, if everyone doesn’t know the strategy and follow it, it is irrelevant. This requirement leads people to organize around centralized architecture teams with official “authority”—so that the same rules will be applied everywhere. Ironically, ivory tower architects are often ignored or bypassed. Developers have no choice when the architects’ lack of feedback from hands-on attempts to apply their own rules to real applications results in impractical schemes."
      • "The decision process must absorb feedback."
        • "Creating an organizing principle, large-scale structure, or distillation of such subtlety requires a really deep understanding of the needs of the project and the concepts of the domain. The only people who have that depth of knowledge are the members of the application development team. This explains why application architectures created by architecture teams are so seldom helpful, despite the undeniable talent of many of the architects."
      • "The plan must allow for evolution."
        • "Effective software development is a highly dynamic process. When the highest level of decisions is set in stone, the team has fewer options when it must respond to change. evolving order avoids this trap by emphasizing ongoing change to the large-scale structure in response to deepening insight."
      • "Architecture teams must not siphon off all the best and brightest."
        • "It is essential to have strong designers on all application teams. It is essential to have domain knowledge on any team attempting strategic design. It may simply be necessary to hire more advanced designers. It may help to keep architecture teams part-time. I’m sure there are many ways that work, but any effective strategy team has to have as a partner an effective application team"
      • "Strategic design requires minimalism and humility."
        • "Distillation and minimalism are essential to any good design work, but minimalism is even more critical for strategic design. Even the slightest ill fit has a terrible potential for getting in the way. Separate architecture teams have to be especially careful because they have less feel for the obstacles they might be placing in front of application teams. At the same time, the architects’ enthusiasm for their primary responsibility makes them more likely to get carried away."
      • "Objects are specialists; developers are generalists."
        • "The essence of good object design is to give each object a clear and narrow responsibility and to reduce interdependence to an absolute minimum. Sometimes we try to make interactions on teams as tidy as they should be in our software. A good project has lots of people sticking their nose in other people’s business. Developers play with frameworks. Architects write application code. Everyone talks to everyone. It is efficiently chaotic. Make the objects into specialists; let the developers be generalists."
    • The Same Goes for the Technical Frameworks
        • "Technical frameworks can greatly accelerate application development, including the domain layer, by providing an infrastructure layer that frees the application from implementing basic services, and by helping to isolate the domain from other concerns. But there is a risk that an architecture can interfere with expressive implementations of the domain model and easy change."
      • "Don't write frameworks for dummies"
        • "Team divisions that assume some developers are not smart enough to design are likely to fail because they underestimate the difficulty of application development. If those people are not smart enough to design, they shouldn’t be assigned to develop software. If they are smart enough, then the attempts to coddle them will only put up barriers between them and the tools they need.

          This attitude also poisons the relationship between teams. I’ve ended up on arrogant teams like this and found myself apologizing to developers in every conversation, embarrassed by my association. (I’ve never managed to change such a team, I’m afraid.)"
    • Beware the Master Plan
      • "A group of architects (the kind who design physical buildings), led by Christopher Alexander, were advocates of piecemeal growth in the realm of architecture and city planning. They explained very nicely why master plans fail."
      • "Without a planning process of some kind, there is not a chance in the world that the University of Oregon will ever come to possess an order anywhere near as deep and harmonious as the order that underlies the University of Cambridge.

        The master plan has been the conventional way of approaching this difficulty. The master plan attempts to set down enough guidelines to provide for coherence in the environment as a whole—and still leave freedom for individual buildings and open spaces to adapt to local needs.

        . . . and all the various parts of this future university will form a coherent whole, because they were simply plugged into the slots of the design.

        . . . in practice master plans fail—because they create totalitarian order, not organic order. They are too rigid; they cannot easily adapt to the natural and unpredictable changes that inevitably arise in the life of a community. As these changes occur . . . the master plan becomes obsolete, and is no longer followed. And even to the extent that master plans are followed . . . they do not specify enough about connections between buildings, human scale, balanced function, etc. to help each local act of building and design become well-related to the environment as a whole.

        . . . The attempt to steer such a course is rather like filling in the colors in a child’s coloring book . . . . At best, the order which results from such a process is banal.

        . . . Thus, as a source of organic order, a master plan is both too precise, and not precise enough. The totality is too precise: the details are not precise enough.

        . . . the existence of a master plan alienates the users [because, by definition] the members of the community can have little impact on the future shape of their community because most of the important decisions have already been made.

        —From The Oregon Experiment, pp. 16–28 (Alexander et al. 1975)"
      • "Alexander and his colleagues advocated instead a set of principles for all community members to apply to every act of piecemeal growth, so that “organic order” emerges, well adapted to circumstances."

Domain Driven Design Chapter 16 Summary

 Chapter 16: Large-Scale Structure

    • "In a large system without any overarching principle that allows elements to be interpreted in terms of their role in patterns that span the whole design, developers cannot see the forest for the trees. We need to be able to understand the role of an individual part in the whole without delving into the details of the whole."
    • "A “large-scale structure” is a language that lets you discuss and understand the system in broad strokes."
    • "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 particular parts of the application. Soon, developers will dumb down the application to fit the structure, or they will subvert it and have no structure at all, bringing back the problems of uncoordinated development."
    • "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."
    • "Large-scale structure should be applied when a structure can be found that greatly clarifies the system without forcing unnatural constraints on model development. Because an ill-fitting structure is worse than none, it is best not to shoot for comprehensiveness, but rather to find a minimal set that solves the problems that have emerged. Less is more. "
  • 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 in a useful direction, adopt it as a large-scale structure. Organize the design around this metaphor and absorb it into the ubiquitous language. The system metaphor should both facilitate communication about the system and guide development of it. This increases consistency in different parts of the system, potentially even across different bounded contexts. But because all metaphors are inexact, continually reexamine the metaphor for overextension or inaptness, and be ready to drop it if it gets in the way."
    • The "Naive Metaphor" and Why We Don't Need It
      • "Because a useful metaphor doesn’t present itself on most projects, some in the XP community have come to talk of the naive metaphor, by which they mean the domain model itself.

        One trouble with this term is that a mature domain model is anything but naive. In fact, “payroll processing is like an assembly line” is likely a much more naive view than a model that is the product of many iterations of knowledge crunching with domain experts, and that has been proven by being tightly woven into the implementation of a working application.

        The term naive metaphor should be retired."
  • 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."
    • "Look at the conceptual dependencies in your model and the varying rates and sources of change of different parts of your 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. Refactor the model so that the responsibilities of each domain object, aggregate, and module fit neatly within the responsibility of one layer."
    • Choosing Appropriate Layers
      • "As layers get switched out, merged, split, and redefined, here are some useful characteristics to look for and preserve."
        • "Storytelling. The layers should communicate the basic realities or priorities of the domain. Choosing a large-scale structure is less a technical decision than a business modeling decision. The layers should bring out the priorities of the business."
        • "Conceptual dependency. The concepts in the “upper” layers should have meaning against the backdrop of the “lower” layers, while the lower-layer concepts should be meaningful standing alone."
        • "Conceptual contours. If the objects of different layers should have different rates of change or different sources of change, the layer accommodates the shearing between them."
  • Knowledge Level
    • "[A knowledge level is] a group of objects that describes how another group of objects should behave. [Martin Fowler, “Accountability,” www.martinfowler.com]"
    • "Knowledge level untangles things when we need to let some part of the model itself be plastic in the user’s hands yet constrained by a broader set of rules. It addresses requirements for software with configurable behavior, in which the roles and relationships among entities must be changed at installation or even at runtime."
    • "In an application in which the roles and relationships between ENTITIES vary in different situations, complexity can explode. Neither fully general models nor highly customized ones serve the users’ needs. Objects end up with references to other types to cover a variety of cases, or with attributes that are used in different ways in different situations. Classes that have the same data and behavior may multiply just to accommodate different assembly rules."
    • "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. "
  • Pluggable Component Framework
    • "When a variety of applications have to interoperate, all based on the same abstractions but designed independently, translations between multiple bounded contexts limit integration. A shared kernel is not feasible for teams that do not work closely together. Duplication and fragmentation raise costs of development and installation, and interoperability becomes very difficult."
    • "Distill an abstract core of interfaces and interactions and create a framework that allows diverse implementations of those interfaces to be freely substituted. Likewise, allow any application to use those components, so long as it operates strictly through the interfaces of the abstract core."
  • How Restrictive Should a Structure Be?
    • "The large-scale structure patterns discussed in this chapter range from the very loose system metaphor to the restrictive pluggable component framework. Other structures are possible, of course, and even within a general structural pattern, there is a lot of choice about how restrictive to make the rules."
    • "A more restrictive structure increases uniformity, making the design easier to interpret. If the structure fits, the rules are likely to push developers toward good designs. Disparate pieces are likely to fit together better."
    • "On the other hand, the restrictions may take away flexibility that developers need. Very particular communication paths might be impractical to apply across bounded contexts, especially in different implementation technologies, in a heterogeneous system."
    • "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."
  • Refactoring Toward a Fitting Structure
    • "A team committed to evolving order must fearlessly rethink the large-scale structure throughout the project life cycle. The team should not saddle itself with a structure conceived of early on, when no one understood the domain or the requirements very well."
    • "Unfortunately, that evolution means that your final structure will not be available at the start, and that means that you will have to refactor to impose it as you go along. This can be expensive and difficult, but it is necessary. There are some general ways of controlling the cost and maximizing the gain."
    • Minimalism
      • "One key to keeping the cost down is to keep the structure simple and lightweight. Don’t attempt to be comprehensive. Just address the most serious concerns and leave the rest to be handled on a case-by-case basis."
    • Communication and Self-Discipline
      • "The entire team must follow the structure in new development and refactoring. To do this, the structure must be understood by the entire team. The terminology and relationships must enter the ubiquitous language."
    • Restructuring Yields Supple Design
      • "[A]ny change to the structure may lead to a lot of refactoring. The structure is evolving as system complexity increases and understanding deepens. Each time the structure changes, the entire system has to be changed to adhere to the new order. Obviously that is a lot of work."
      • "This isn’t quite as bad as it sounds. I’ve observed that a design with a large-scale structure is usually much easier to transform than one without. This seems to be true even when changing from one kind of structure to another, say from metaphor to layers."
      • "So it seems to be with models that are transformed repeatedly with sound transformations. Ever-increasing knowledge is embedded into them and the principal axes of change have been identified and made flexible, while stable aspects have been simplified. The broader conceptual contours of the underlying domain are emerging in the model structure."
    • Distillation Lightens the Load
      • "Another crucial force that should be applied to the model is continuous distillation. This reduces the difficulty of changing the structure in various ways. First, by removing mechanisms, generic subdomains, and other support structure from the core domain, there may simply be less to restructure."
      • "The principles of distillation and refactoring toward deeper insight apply even to the large-scale structure itself. For example, the layers may initially be chosen based on a superficial understanding of the domain; they are gradually replaced with deeper abstractions that express the fundamental responsibilities of the system. This sharp-edged clarity lets people see deep into the design, which is the goal. It is also part of the means, as it makes manipulation of the system on a large scale easier and safer."

Domain Driven Design Chapter 15 Summary

 Chapter 15: 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."
    • "Strategic distillation of a domain model does all of the following:"
      • "Aids all team members in grasping the overall design of the system and how it fits together"
      • "Facilitates communication by identifying a core model of manageable size to enter the ubiquitous language"
      • "Guides refactoring"
      • "Focuses work on areas of the model with the most value"
      • "Guides outsourcing, use of off-the-shelf components, and decisions about assignments"
  • Core Domain
    • "In designing a large system, there are so many contributing components, all complicated and all absolutely necessary to success, that the essence of the domain model, the real business asset, can be obscured and neglected."
    • "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. But scarce, highly skilled developers tend to gravitate to technical infrastructure or neatly definable domain problems that can be understood without specialized domain knowledge."
    • "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.

      Apply top talent to the core domain, and recruit accordingly. Spend the effort in the core to find a deep model and develop a supple design—sufficient to fulfill the vision of the system. Justify investment in any other part by how it supports the distilled core."
    • Choosing the Core
      • "The core domain you choose depends on your point of view. For example, many applications need a generic model of money that could represent various currencies and their exchange rates and conversions. On the other hand, an application to support currency trading might need a more elaborate model of money, which would be considered part of the core. Even in such a case, there may be a part of the money model that is very generic. As insight into the domain deepens with experience, the distillation process can continue by separating the generic money concepts and retaining only the specialized aspects of the model in the core domain."
      • "One application’s core domain is another application’s generic supporting component."
    • Who Does the Work?
      • "It is essential to [assemble] a team matching up a set of strong developers who have a long-term commitment and an interest in becoming repositories of domain knowledge with one or more domain experts who know the business deeply. Domain design is interesting, technically challenging work when approached seriously, and developers can be found who see it this way."
  • An Escalation of Distillations
    • Distillation techniques ordered by needed effort
      • Domain Vision Statement
      • Highlighted Core
      • Generic Subdomains
      • Cohesive Mechanisms
      • Segregated Core
      • Abstract Core
  • Generic Subdomains
    • "Some parts of the model add complexity without capturing or communicating specialized knowledge. Anything extraneous makes the core domain harder to discern and understand. The model clogs up with general principles everyone knows or details that belong to specialties which are not your primary focus but play a supporting role. Yet, however generic, these other elements are essential to the functioning of the system and the full expression of the model."
    • "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."
    • Generic Doesn't Mean Reusable
      • "Note that while I have emphasized the generic quality of these subdomains, I have not mentioned the reusability of code. Off-the-shelf solutions may or may not make sense for a particular situation, but assuming that you are implementing the code yourself, in-house or outsourced, you should specifically not concern yourself with the reusability of that code. This would go against the basic motivation of distillation: that you should be applying as much of your effort to the core domain as possible and investing in supporting generic subdomains only as necessary."
    • Project Risk Management
      • "Projects face risk from both sides, with some projects having greater technical risks and others greater domain modeling risks. The end-to-end system mitigates risk only to the extent that it is an embryonic version of the challenging parts of the actual system. It is easy to underestimate the domain modeling risk. It can take the form of unforeseen complexity, inadequate access to business experts, or gaps in key skills of the developers."
      • "Therefore, except when the team has proven skills and the domain is very familiar, the first-cut system should be based on some part of the core domain, however simple."
  • Domain Vision Statement
    • "At the beginning of a project, the model usually doesn’t even exist, yet the need to focus its development is already there. In later stages of development, there is a need for an explanation of the value of the system that does not require an in-depth study of the model. Also, the critical aspects of the domain model may span multiple bounded contexts, but by definition these distinct models can’t be structured to show their common focus."
    • "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."
  • Highlighted Core
    • "Even though team members may know broadly what constitutes the core domain, different people won’t pick out quite the same elements, and even the same person won’t be consistent from one day to the next. The mental labor of constantly filtering the model to identify the key parts absorbs concentration better spent on design thinking, and it requires comprehensive knowledge of the model. The core domain must be made easier to see.

      Significant structural changes to the code are the ideal way of identifying the core domain, but they are not always practical in the short term. In fact, such major code changes are difficult to undertake without the very view the team is lacking."
    • The Distillation Document
      • "Often I create a separate document to describe and explain the core domain. It can be as simple as a list of the most essential conceptual objects. It can be a set of diagrams focused on those objects, showing their most critical relationships. It can walk through the fundamental interactions at an abstract level or by example. It can use UML class or sequence diagrams, nonstandard diagrams particular to the domain, carefully worded textual explanations, or combinations of these. 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. The reader is given a broad view of how the pieces fit and guided to the appropriate part of the code for more details."
    • The Flagged Core
      • "Flag each element 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."
    • The Distillation Document as Process Tool
      • "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. When a model or code change affects the distillation document, it requires consultation with other team members. When the change is made, it requires immediate notification of all team members, and the dissemination of a new version of the document. Changes outside the core or to details not included in the distillation document can be integrated without consultation or notification and will be encountered by other members in the course of their work. Then the developers have the full autonomy that XP suggests."
  • Cohesive Mechanisms
    • "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."
    • "Partition a conceptually cohesive mechanism into a separate lightweight framework. Particularly watch for formalisms or welldocumented 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."
    • Generic Subdomain Versus Cohesive Mechanism
      • "Both generic subdomains and cohesive mechanisms are motivated by the same desire to unburden the core domain. The difference is the nature of the responsibility taken on. 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. A cohesive mechanism does not represent the domain; it solves some sticky computational problem posed by the expressive models."
    • When a Mechanism is Part of the Core Domain
      • "You almost always want to remove mechanisms from the core domain. The one exception is when a mechanism is itself proprietary and a key part of the value of the software. This is sometimes the case with highly specialized algorithms."
  • Distilling to a Declarative Style
    • " The value of distillation is being able to see what you are doing: cutting to the essence without being distracted by irrelevant detail. Important parts of the core domain may be able to follow a declarative style, when the supporting design provides an economical language for expressing the concepts and rules of the core while encapsulating the means of computing or enforcing them."
  • Segregated Core
    • "Elements in the model may partially serve the core domain and partially play supporting roles. core elements may be tightly coupled to generic ones. The conceptual cohesion of the core may not be strong or visible. All this clutter and entanglement chokes the core. Designers can’t clearly see the most important relationships, leading to a weak design."
    • "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. Factor all generic or supporting elements into other objects and place them into other packages, even if this means refactoring the model in ways that separate highly coupled elements."
    • The Costs of Creating a Segregated Core
      • "Segregating 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 other cost, of course, is that segregating the core is a lot of work. It must be acknowledged that a decision to go to a segregated core will potentially absorb developers in changes all over the system."
      • "The time to chop out a segregated core is when you have a large bounded context that is critical to the system, but where the essential part of the model is being obscured by a great deal of supporting capability."
    • Evolving Team Decision
      • "As with many strategic design decisions, an entire team must move to a segregated core together. This step requires a team decision process and a team disciplined and coordinated enough to carry out the decision. The challenge is to constrain everyone to use the same definition of the core while not freezing that decision. Because the core domain evolves just like every other aspect of a design, experience working with a segregated core will lead to new insights into what is essential and what is a supporting element. Those insights should feed back into a refined definition of the core domain and of the segregated core modules."
  • 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."
  • Deep Models Distill
    • "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."
  • Choosing Refactoring Targets
    • "In a pain-driven refactoring, you look to see if the root involves the core domain or the relationship of the core to a supporting element. If it does, you bite the bullet and fix that first."
    • When you have the luxury of refactoring freely, you focus first on better factoring of the core domain, on improving the segregation of the core, and on purifying supporting subdomains to be generic.

Monday, August 17, 2020

Domain Driven Design Chapter 14 Summary

 Chapter 14: Maintaining Model Integrity

    • Shares a story of one group trying to reuse the code of a Charge module written by a different group, and how that started breaking that other group's code.
    • "The problem was that these two groups had different models, but they did not realize it, and there were no processes in place to detect it. Each made assumptions about the nature of a charge that were useful in their context (billing customers versus paying vendors). When their code was combined without resolving these contradictions, the result was unreliable software."
    • "If only they had been more aware of this reality, they could have consciously decided how to deal with it. That might have meant working together to hammer out a common model and then writing an automated test suite to prevent future surprises. Or it might simply have meant an agreement to develop separate models and keep hands off each other’s code. Either way, it starts with an explicit agreement on the boundaries within which each model applies."
    • "[T]he most fundamental requirement of a model is that it be internally consistent; that its terms always have the same meaning, and that it contain no contradictory rules. The internal consistency of a model, such that each term is unambiguous and no rules contradict, is called unification. A model is meaningless unless it is logically consistent."
    • "To maintain that level of unification in an entire enterprise system is more trouble than it is worth. It is necessary to allow multiple models to develop in different parts of the system, but we need to make careful choices about which parts of the system will be allowed to diverge and what their relationship to each other will be. We need ways of keeping crucial parts of the model tightly unified. None of this happens by itself or through good intentions. It happens only through conscious design decisions and institution of specific processes. Total unification of the domain model for a large system will not be feasible or cost-effective"
    • "This chapter lays out techniques for recognizing, communicating, and choosing the limits of a model and its relationships to others. It all starts with mapping the current terrain of the project. A bounded context defines the range of applicability of each model, while a context map gives a global overview of the project’s contexts and the relationships between them. This reduction of ambiguity will, in and of itself, change the way things happen on the project, but it isn’t necessarily enough. Once we have a context bounded, a process of continuous integration will keep the model unified.

      Then, starting from this stable situation, we can start to migrate toward more effective strategies for bounding contexts and relating them, ranging from closely allied contexts with shared kernels to loosely coupled models that go their separate ways."
  • 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 often 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."
    • Recognizing Splinters Within a Bounded Context
      • "Combining elements of distinct models causes two categories of problems: duplicate concepts and false cognates."
      • "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. Every time new knowledge leads to a change in one of the objects, the other has to be reanalyzed and changed too. Except the reanalysis doesn’t happen in reality, so the result is two versions of the same concept that follow different rules and even have different data. On top of that, the team members must learn not one but two ways of doing the same thing, along with all the ways they are being synchronized."
      • "False cognates may be slightly less common, but more insidiously harmful. 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. [...] False cognates lead to development teams that step on each other’s code, databases that have weird contradictions, and confusion in communication within the team."
      • "When you detect these problems, your team will have to make a decision. You may want to pull the model back together and refine the processes to prevent fragmentation. Or the fragmentation may be a result of groups who want to pull the model in different directions for good reasons, and you may decide to let them develop independently. Dealing with these issues is the subject of the remaining patterns in this chapter."
  • Continuous Integration
    • "Having defined a bounded context, we must keep it sound."
    • "When a number of people are working in the same bounded context, there is a strong tendency for the model to fragment. The bigger the team, the bigger the problem, but as few as three or four people can encounter serious problems. Yet breaking down the system into ever-smaller contexts eventually loses a valuable level of integration and coherency."
    • "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."
    • "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. Meanwhile, the implementation artifacts are being integrated by a systematic merge/build/test process that exposes model splinters early. Many processes for integration are used, but most of the effective ones share these characteristics:"
      • A step-by-step, reproducible merge/build technique
      • Automated test suites
      • Rules that set some reasonably small upper limit on the lifetime of unintegrated changes
    • "Institute a process of merging all code and other implementation artifacts frequently, with automated tests to flag fragmentation quickly. Relentlessly exercise the ubiquitous language to hammer out a shared view of the model as the concepts evolve in different people’s heads."
  • Context Map
    • "An individual bounded context still does not provide a global view. The context of other models may still be vague and in flux."
    • "People on other teams won’t be very aware of the context bounds and will unknowingly make changes that blur the edges or complicate the interconnections. When connections must be made between different contexts, they tend to bleed into each other."
    • "Identify each model in play on the project and define its bounded context. This includes the implicit models of nonobject-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.
      Map the existing terrain. Take up transformations later."
    • Testing at the Context Boundaries
      • "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. They can act as a valuable early warning system, especially reassuring in cases where you depend on the details of a model you don’t control."
    • Organizing and Documenting Context Maps
      • "The bounded contexts should have names so that you can talk about them. Those names should enter the ubiquitous language of the team."
      • "Everyone has to know where the boundaries lie, and be able to recognize the context of any piece of code or any situation."
  • Relationships Between Bounded Contexts
    • "The following patterns cover a range of strategies for relating two models that can be composed to encompass an entire enterprise. These patterns serve the dual purpose of providing targets for successfully organizing development work, and supplying vocabulary for describing the existing organization."
  • Shared Kernel
    • "Uncoordinated teams working on closely related applications can go racing forward for a while, but what they produce may not fit together. They can end up spending more on translation layers and retrofitting than they would have on continuous integration in the first place, meanwhile duplicating effort and losing the benefits of a common ubiquitous language."
    • "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.

      Integrate a functional system frequently, but somewhat less often than the pace of continuous integration within the teams. At these integrations, run the tests of both teams."
  • 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 upstream team may even be inhibited, worried about breaking the downstream system. Meanwhile, the downstream team can be helpless, at the mercy of upstream priorities."
    • "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. Negotiate and budget tasks for downstream requirements so that everyone understands the commitment and schedule.
      Jointly develop automated acceptance tests that will validate the interface expected. Add these tests to the upstream team’s test suite, to be run as part of its continuous integration. This testing will free the upstream team to make changes without fear of side effects downstream."
    • There are two crucial elements to this pattern
      • " The relationship must be that of customer and supplier, with the implication that the customer’s needs are paramount. Because the downstream team is not the only customer, the different customers’ demands have to be balanced in negotiation—but they remain priorities. This situation is in contrast to the poor-cousin relationship that often emerges, in which the downstream team has to come begging to the upstream team for its needs."
      • "There must be an automated test suite that allows the upstream team to change its code without fear of breaking the downstream, and lets the downstream team concentrate on its own work without constantly monitoring the upstream team."
  • 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."
    • "In this situation, there are three possible paths."
      • Separate Ways - "One is to abandon use of the upstream altogether. This option should be evaluated realistically, making no assumptions that the upstream will accommodate downstream needs."
      • Anticorruption Layer - "If the design is very difficult to work with, perhaps for lack of encapsulation, awkward abstractions, or modeling in a paradigm the team cannot use, then the downstream team will still need to develop its own model. They will have to take full responsibility for a translation layer that is likely to be complex."
      • Conformist - "On the other hand, if the quality is not so bad, and the style is reasonably compatible, then it may be best to give up on an independent model altogether."
    • "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. "
  • Anticorruption Layer
    • "When a new system is being built that must have a large interface with another, the difficulty of relating the two models can eventually overwhelm the intent of the new model altogether, causing it to be modified to resemble the other system’s model, in an ad hoc fashion. The models of legacy systems are usually weak, and even the exception that is well developed may not fit the needs of the current project. Yet there may be a lot of value in the integration, and sometimes it is an absolute requirement."
    • "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."
    • Designing the Interface of the Anticorruption Layer
      • "The public interface of the anticorruption layer usually appears as a set of services, although occasionally it can take the form of an entity. Building a whole new layer responsible for the translation between the semantics of the two systems gives us an opportunity to reabstract the other system’s behavior and offer its services and information to our system consistently with our model. It may not even make sense, in our model, to represent the external system as a single component. It may be best to use multiple services (or occasionally entities), each of which has a coherent responsibility in terms of our model."
    • Implementing the Anticorruption Layer
      • "One way of organizing the design of the anticorruption layer is as a combination of facades, adapters (both from Gamma et al. 1995), and translators, along with the communication and transport mechanisms usually needed to talk between systems."
      • "We often have to integrate with systems that have large, complicated, messy interfaces. [...] Translating from one model to another (especially if one model is fuzzy) is a hard enough job without simultaneously dealing with a subsystem interface that is hard to talk to. Fortunately, that is what facades are for. A facade is an alternative interface for a subsystem that simplifies access for the client and makes the subsystem easier to use."
      • "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. I’m using the term adapter a little loosely, because the emphasis in Gamma et al. 1995 is on making a wrapped object conform to a standard interface that clients expect, whereas we get to choose the adapted interface, and the adaptee is probably not even an object. Our emphasis is on translation between two models, but I think this is consistent with the intent of adapter."
      • "The remaining element is the 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 adapters(s) it serves."
    • A Cautionary Tale
  • Separate Ways
    • "Integration is always expensive. Sometimes the benefit is small."
    • "Declare a bounded context to have no connection to the others at all, allowing developers to find simple, specialized solutions within this small scope."
  • Open Host Service
    • "When a subsystem has to be integrated with many others, customizing a translator for each can bog down the team. There is more and more to maintain, and more and more to worry about when changes are made."
    • "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
    • "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. A domain model is developed to solve problems for its users; such a model may contain features that needlessly complicate communication with another system. Also, if the model underlying one of the applications is used as the communications medium, it cannot be changed freely to meet new needs, but must be very stable to support the ongoing communication role."
    • "Direct translation to and from the existing domain models may not be a good solution. Those models may be overly complex or poorly factored. They are probably undocumented. If one is used as a data interchange language, it essentially becomes frozen and cannot respond to new development needs."
    • "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."
  • Unifying an Elephant
    • Starts off by quoting parts of "The Blind Men and the Elephant," by John Godfrey Saxe, where each blind man compares the elephant to something different depending on what part they touched: a wall, a snake, a tree, a rope, etc.
    • "Depending on their goals in interacting with the elephant, the various blind men may still be able to make progress, even if they don’t fully agree on the nature of the elephant. If no integration is required, then it doesn’t matter that the models are not unified. If they require some integration, they may not actually have to agree on what an elephant is, but they will get a lot of value from merely recognizing that they don’t agree. This way, at least they don’t unknowingly talk at cross-purposes."
    • "As the blind men want to share more information about the elephant, the value of sharing a single bounded context goes up. But unifying the disparate models is a challenge. None of them is likely to give up his model and adopt one of the others. After all, the man who touched the tail knows the elephant is not like a tree, and that model would be meaningless and useless to him. Unifying multiple models almost always means creating a new model."
    • "With some imagination and continued discussion (probably heated), the blind men could eventually recognize that they have been describing and modeling different parts of a larger whole. For many purposes, a part-whole unification may not require much additional work. At least the first stage of integration only requires figuring out how the parts are related. It may be adequate for some needs to view an elephant as a wall, held up by tree trunks, with a rope at one end and a snake at the other."
    • "Matters are more difficult when two models are looking at the same part in a different way. If two men had touched the trunk and one described it as a snake and the other described it as a fire hose, they would have had more difficulty. Neither can accept the other’s model, because it contradicts his own experience. In fact, they need a new abstraction that incorporates the “aliveness” of a snake with the water-shooting functionality of a fire hose, but one that leaves out the inapt implications of the first models, such as the expectation of possibly venomous fangs, or the ability to be detached from the body and rolled up into a compartment in a fire truck."
    • "Even though we have combined the parts into a whole, the resulting model is crude. It is incoherent, lacking any sense of following contours of an underlying domain. New insights could lead to a deeper model in a process of continuous refinement. New application requirements can also force the move to a deeper model. If the elephant starts moving, the “tree” theory is out, and our blind modelers may break through to the concept of “legs.”"
    • "This second pass of model integration tends to slough off incidental or incorrect aspects of the individual models and creates new concepts—in this case, “animal” with parts “trunk,” “leg,” “body,” and “tail”—each of which has its own properties and clear relationships to other parts. Successful model unification, to a large extent, hinges on minimalism. An elephant trunk is both more and less than a snake, but the “less” is probably more important than the “more.” Better to lack the water-spewing ability than to have an incorrect poison-fang feature."
  • Choosing Your Model Context 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. Here are some guidelines."
    • Team Decision or Higher
      • "Teams have to make these decisions, or at least the decisions have to be propagated to the entire team and understood by everyone. In fact, such decisions often involve agreements beyond your own team. On the merits, decisions about whether to expand or to partition bounded contexts should be based on the cost-benefit trade-off between the value of independent team action and the value of direct and rich integration. In practice, political relationships between teams often determine how systems are integrated"
    • Putting Ourselves in Context
      • "When we are working on a software project, we are interested primarily in the parts of the system our team is changing (the “system under design”) and secondarily in the systems it will communicate with. [...] We really are part of that primary context we are working in, and that is bound to be reflected in our context. This isn’t a problem if we are aware of the bias and are mindful of when we step outside the limits of that map’s applicability."
    • Transforming Boundaries
      • "[T]ypically the struggle is to balance some subset of the following forces:"
        • Favoring Larger Bounded Contexts
          • Flow between user tasks is smoother when more is handled with a unified model.
          • It is easier to understand one coherent model than two distinct ones plus mappings
          •  Translation between two models can be difficult (sometimes impossible).
          • Shared language fosters clear team communication.
        • Favoring Smaller Bounded Contexts
          • Communication overhead between developers is reduced.
          • Continuous integration is easier with smaller teams and code bases.
          • Larger contexts may call for more versatile abstract models, requiring skills that are in short supply.
          • Different models can cater to special needs or encompass the jargon of specialized groups of users, along with specialized dialects of the ubiquitous language.
    • Accepting That Which We Cannot Change: Delineating the External Systems
      • "Some subsystems will clearly not be in any BOUNDED CONTEXT of the system under development. Examples would be major legacy systems that you are not immediately replacing and external systems that provide services you’ll need. You can identify these immediately and prepare to segregate them from your design."
      • "Here we must be careful about our assumptions.It is not unusual to find semantic contradictions in different parts of such systems."
    • Relationships with the External Systems
      • "There are three patterns that can apply here. First, to consider separate ways. Yes, you wouldn’t have included them if you didn’t need integration. But be really sure. Would it be sufficient to give the user easy access to both systems? Integration is expensive and distracting, so unburden your project as much as you can."
      • "If the integration is really essential, you can choose between two extremes: conformist or anticorruption layer."
    • The System Under Design
      • "The software your project team is actually building is the system under design. You can declare bounded contexts within this zone and apply continuous integration within each to keep them unified. But how many should you have? What relationships should they have to each other? The answers are less cut and dried than with the external systems because we have more freedom and control."
    • Catering to Special Needs with Distinct Models
      • "Different groups within the same business have often developed their own specialized terminologies, which may have diverged from one another. These local jargons may be very precise and tailored to their needs. Changing them (for example, by imposing a standardized, enterprise-wide terminology) requires extensive training and analysis to resolve the differences. Even then, the new terminology may not serve as well as the finely tuned version they already had."
      • "You may decide to cater to these special needs in separate bounded contexts, allowing the models to go separate ways, except for continuous integration of translation layers. Different dialects of the ubiquitous language will evolve around these models and the specialized jargon they are based on. If the two dialects have a lot of overlap, a shared kernel may provide the needed specialization while minimizing the translation cost."
    • Deployment
      • "Coordinating the packaging and deployment of complex systems is one of those boring tasks that are almost always a lot harder than they look. The choice of bounded context strategy has an impact on the deployment. For example, when customer/supplier teams deploy new versions, they have to coordinate with each other to release versions that have been tested together. Both code and data migrations have to work in these combinations. In a distributed system, it may help to keep the translation layers between contexts together within a single process, so that you don’t have multiple versions coexisting.

        Even deployment of the components of a single bounded context can be challenging when data migration takes time or when distributed systems can’t be updated instantaneously, resulting in two versions of the code and data coexisting."
    • The Trade-off
      • "To sum up these guidelines, there is a range of strategies for unifying or integrating models. In general terms, you will trade off the benefits of seamless integration of functionality against the additional effort of coordination and communication. You trade more independent action against smoother communication. More ambitious unification requires control over the design of the subsystems involved."
    • When Your Project Is Already Under Way
      • "Most likely, you are not starting a project but are looking to improve a project that is already under way. In this case, the first step is to define BOUNDED CONTEXTS according to the way things are now."
      • "Once you have delineated your true current bounded contexts and described the relationships they currently have, the next step is to tighten up the team’s practices around that current organization. Improve your continuous integration within the contexts. Refactor any stray translation code into your anticorruption layers. Name the existing bounded contexts and make sure they are in the ubiquitous language of the project."
      • "Now you are ready to consider changes to the boundaries and relationships themselves. These changes will naturally be driven by the same principles I’ve already described for a new project, but they will have to be bitten off in small pieces, chosen pragmatically to give the most value for the least effort and disruption."
  • Transformations
    • "Like any other aspect of modeling and design, decisions about bounded contexts are not irrevocable. Inevitably, there will be many cases in which you have to change your initial decision about the boundaries and relationships between bounded contexts."
    • Merging Contexts: Separate Ways -> Shared Kernel
      • "This is hard to do. It’s not too late, but it takes some patience."
      • "Evaluate the initial situation. Be sure that the two contexts are indeed internally unified before beginning to unify them with each other."
      • "Set up the process. You’ll need to decide how the code will be shared and what the module naming conventions will be. There must be at least weekly integration of the shared kernel code. And it must have a test suite. Set this up before developing any shared code. (The test suite will be empty, so it should be easy to pass!)"
      • "Choose some small subdomain to start with—something duplicated in both contexts, but not part of the core domain. This first merger is going to establish the process, so it is best to use something simple and relatively generic or noncritical. Examine the integrations and translations that already exist. Choosing something that is being translated has the advantage of starting out with a proven translation, plus you’ll be thinning your translation layer."
      • "Form a group of two to four developers, drawn from both teams, to work out a shared model for the subdomain. Regardless of how the model is derived, it must be ironed out in detail. This includes the hard work of identifying synonyms and mapping any terms that are not already being translated. This joint team outlines a basic set of tests for the model."
      • "Developers from either team take on the task of implementing the model (or adapting existing code to be shared), working out details and making it function. If these developers run into problems with the model, they reconvene the team from step 3 and participate in any necessary revisions of the concepts."
      • "Developers of each team take on the task of integrating with the new shared kernel."
      • "Remove translations that are no longer needed."
    • Merging Contexts: Shared Kernel -> Continuous Integration
      • "This is not just a matter of resolving the model differences. You are going to be changing team structures and ultimately the language people speak."
      • "Be sure that all the processes needed for continuous integration (shared code ownership, frequent integration, and so on) are in place on each team, separately. Harmonize integration procedures on the two teams so that everyone is doing things in the same way."
      • "Start circulating team members between teams. This will create a pool of people who understand both models, and will begin to connect the people of the two teams."
      • "Clarify the distillation of each model individually."
      • "At this point, confidence should be high enough to begin merging the core domain into the shared kernel. This can take several iterations, and sometimes temporary translation layers are needed between the newly shared parts and the not-yet-shared parts. Once into merging the core domain, it is best to go pretty fast. It is a high-overhead phase, fraught with errors, and should be shortened as much as possible, taking priority over most new development. But don’t take on more than you can handle."
      • "As the shared kernel grows, increase the integration frequency to daily and finally to continuous integration."
      • "As the shared kernel approaches the point of encompassing all of the two former bounded contexts, you will find yourself with either one large team or two smaller teams that have a shared code base that they integrate continuously, and that trade members back and forth frequently."
    • Phasing Out a Legacy System
      • "Identify specific functionality of the legacy that could be added to one of the favored systems within a single iteration."
      • " Identify additions that will be required in the anticorruption layer."
      • "Implement."
      • "Deploy."
      • "Identify any unnecessary parts of the anticorruption layer and remove them."
      • "Consider excising the now-unused modules of the legacy system, though this may not turn out to be practical. Ironically, the better designed the legacy system is, the easier it will be to phase it out. But badly designed software is hard to dismantle a little at a time. It may be possible to just ignore the unused parts until a later time when the remainder has been phased out and the whole thing can be switched off."
    • Open Host Service -> Published Language
      • " If an industry-standard language is available, evaluate it and use it if at all possible."
      • "If no standard or prepublished language is available, then begin by sharpening up the core domain of the system that will serve as the host."
      • "Use the core domain as the basis of an interchange language, using a standard interchange paradigm such as XML, if at all possible."
      • " Publish the new language to all involved in the collaboration (at least)."
      • "If a new system architecture is involved, publish that too."
      • "Build translation layers for each collaborating system."
      • "Switch over."

Friday, August 7, 2020

Domain Driven Design Chapter 13 Summary

 Chapter 13: Refactoring Toward Deeper Insight

    • "Refactoring toward deeper insight is a multifaceted process. It will be helpful to stop for a moment to pull together the major points. There are three things you have to focus on."
      • Live in the domain.
      • Keep looking at things a different way.
      • Maintain an unbroken dialog with domain experts.
  • Initiation
    • "Refactoring toward deeper insight can begin in many ways. It may be a response to a problem in the code—some complexity or awkwardness. Rather than apply a standard transformation of the code, the developers sense that the root of the problem is in the domain model. Perhaps a concept is missing. Maybe some relationship is wrong."
    • "Seeing the trouble spot is often the hardest and most uncertain part."
  • Exploration Teams
    • "Whatever the source of dissatisfaction, the next step is to seek a refinement that will make the model communicate clearly and naturally. This might require only some modest change that is immediately evident and can be accomplished in a few hours. In that case, the change resembles traditional refactoring. But the search for a new model may well call for more time and the involvement of more people."
    • Keys to keeping the process productive:
      • "Self-determination. A small team can be assembled on the fly to explore a design problem. The team can operate for a few days and then disband. There is no need for long-term, elaborate organizational structures."
      • "Scope and sleep. Two or three short meetings spaced out over a few days should produce a design worth trying. Dragging it out doesn’t help. If you get stuck, you may be taking on too much at once. Pick a smaller aspect of the design and focus on that."
      • "Exercising the ubiquitous language. Involving the other team members—particularly the subject matter expert—in the brainstorming session creates an opportunity to exercise and refine the ubiquitous language. The end result of the effort is a refinement of that language which the original developer(s) will take back and formalize in code."
  • Prior Art
    • "It isn't always necessary to reinvent the wheel"
    • "You can get ideas from books and other sources of knowledge about the domain itself. Although the people in the field may not have created a model suitable for running software, they may well have organized the concepts and found some useful abstractions. Feeding the knowledge-crunching process this way leads to richer, quicker results that also will probably seem more familiar to domain experts."
    • "Sometimes you can draw on the experience of others in the form of analysis patterns. This kind of input has some of the effect of reading about the domain, but in this case it is geared specifically toward software development, and it should be based directly on experience implementing software in your domain. Analysis patterns can give you subtle model concepts and help you avoid lots of mistakes. But they don’t give you a cookbook recipe. They feed the knowledgecrunching process."
  • A Design for Developers
    • "Software isn’t just for users. It’s also for developers. [...] Refactoring toward deeper insight both leads to and benefits from a supple design."
    • "A supple design communicates its intent. The design makes it easy to anticipate the effect of running code—and therefore it easy to anticipate the consequences of changing it. A supple design helps limit mental overload, primarily by reducing dependencies and side effects. "
  • Timing
    • "If you wait until you can make a complete justification for a change, you’ve waited too long."
    • "Continuous refactoring has come to be considered a “best practice,” but most project teams are still too cautious about it. They see the risk of changing code and the cost of developer time to make a change; but what’s harder to see is the risk of keeping an awkward design and the cost of working around that design. Developers who want to refactor are often asked to justify the decision. Although this seems reasonable, it makes an already difficult thing impossibly difficult, and tends to squelch refactoring (or drive it underground). Software development is not such a predictable process that the benefits of a change or the costs of not making a change can be accurately calculated."
    • 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)
      • You see an opportunity to make some important part of the design suppler.
    • "This aggressive attitude does not justify any change at any time. Don’t refactor the day before a release. Don’t introduce “supple designs” that are just demonstrations of technical virtuosity but fail to cut to the core of the domain. Don’t introduce a “deeper model” that you couldn’t convince a domain expert to use, no matter how elegant it seems. Don’t be absolute about things, but push beyond the comfort zone in the direction of favoring refactoring."
  • Crisis as Opportunity
    • "For over a century after Charles Darwin introduced it, the standard model of evolution was that species changed gradually, somewhat steadily, over time. Suddenly, in the 1970s, this model was displaced by the “punctuated equilibrium” model. In this expanded view of evolution, long periods of gradual change or stability are interrupted by relatively short bursts of rapid change. Then things settle down into a new equilibrium. Software development has an intentional direction behind it that evolution lacks (although it may not be evident on some projects), but nonetheless it follows this kind of rhythm."
    • "Such a situation often does not look like an opportunity; it seems more like a crisis. Suddenly there is some obvious inadequacy in the model. There is a gaping hole in what it can express, or some critical area where it is opaque. Maybe it makes statements that are just wrong."

      "This means the team has reached a new level of understanding. From their now-elevated viewpoint, the old model looks poor. From that viewpoint, they can conceive a far better one."