Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Table of Contents
maxLevel2

...

Chapter 3 Binding Model and Implementation and Chapter 4 Isolating the Domain

Quotes

“Software development is all design. All teams have specialized roles for members, but over separation of responsibility for analysis, modeling, design, and programming interferes with MODEL-DRIVEN DESIGN.”

Example: “A user of Internet Explorer thinks of 'Favorites' as a list of names of Web sites that persist from session to session. But the implementation treats a Favorite as a file containing a URL, and whose filename is put in the Favorites list.”

“If the people who write the code do not feel responsible for the model, or don’t understand how to make the model work for an application, then the model has nothing to do with the software.”

“Every developer must be involved in some level of discussion about the model and have contact with domain experts.”

Discussion

Expand
  • How would this apply to a functional programming language (author examines procedural and logical paradigms, but not FP)?
    • Artifact of when it was written?
    • Would probably work fine.
    • Not as layered.
    • Examples in JS of functional composition (e.g. React).
    • Django's MVC setup actually makes it harder.
      • Not a place for a lot of domain logic (e.g. utils.py)
      • One strategy: Separate layer to proxy lower level models.
      • Another strategy: Service pattern, service encapsulates business logic.
      • Example of what's talked in the book about frameworks dictating a lot of the design.
      • Grades app does have classes to encapsulate domain, but have to go without using niceties like DRF serializers.
      • Question: Are some of the tools that make it easy to write code making it harder to separate out domain logic?
        • Do we need a layer of our own/special tooling to enable this?
  • Analogs between the Smart UI pattern and Django's "Smart Model" and its conveniences.
    • Django optimizing for building it fast? Easy to leak implementation.
    • Useful middle ground?
    • Enterprise API – package that's installed, but API calls are via REST API as if it were a separate system.
      • Business logic encapsulated in models.
    • How to handle internal Python APIs?
      • Best practice to not pass back models?
      • api.py is the public interface between Django apps (though we're not sure if we want to continue using it)
      • Pass back the model but only allow certain methods to be called?
      • Write business logic as functional modules and use the model methods just as a proxy to that?
    • What is the problem we're solving?
      • Enrollment example
      • Separating domain logic from underlying details
      • Simplifying testing
  • Question: Difference between Application Layer and Domain Layer?
    • Application layer manages jobs and tasks and lifecycle of the application. Very thin.
    • Layer for orchestration.
    • No business logic, just knowing who to call.
    • Initialization of the application, setup, teardown.
    • Django "best practice" as view, but this is often not followed.
      • Need to have a clear location for business logic.
    • In async tasks (grades example), is the thing that kicks off task the app layer and the task itself the domain layer?
      • tasks.py is the Django interface
      • domain logic is in the classes: CourseGrade, CourseGradeFactory, SubsectionGrade, and SubsectionGradeFactory
    • Where does app end and domain begin?
      • Where the framework ends and you create domain layer concepts and return domain layer concepts.
  • Question: Are permissions domain logic or app?
    • The notion of "readable by superusers" (app) vs. domain concept of who should be a superuser?
    • Attached to the View in our code.
    • Mapping of of roles to permissions, permissions to views in Django.
    • Permission a Guard on the view, and therefore a separate Domain?
    • Are permissions for what can be done in a Domain a separate Domain?
    • Implementation of permission is app, where to attach it is Domain.
      • Combination, since there's a lot of permission checking in the domain itself.
    • Artifact of the fact that it's a web app, because the conceptual Domain wouldn't even allow certain methods to be invoked? Different objects for different kinds of people?
    • Purer form of this might be to just pass permissions down to the domain layer and let it make the decisions.
    • When will we know that we've outgrown Django?
      • Many of the things we run into are fundamental to the framework.
      • Gradually outgrow it by pieces (asset pipeline, templates, etc.)
    • Django not strictly object oriented, applying separation of concerns without adhering too strictly to DDD?
      • In the end, it's just Python, we can shape it as we need to.
        • Easy to do in a small team, harder to do at large.
          • Especially at open source.
    • Workflow as business logic, app layer just doing I/O, piping to the next thing.
  • Monolith and Folder Structure: Anyone interested in figuring this out, contact Nimisha Asthagiri (Deactivated)
    • First a template, then a script to generate that structure (manage.py – startapp at a specific URL already supported?)
  • Layers and directionality of layers
    • We should think about separation of communication and not just arrangement of app.
    • "You are talking to way too many places in the code."
      • Compositional components
    • Are we missing anything by having Django apps that cross all four layers?
      • Just a matter of discipline, would be confusing to separate out
      • Cross dependencies without directionality
      • Each Django app as its own Context
        • But part of a higher level tiering (different apps at different layers)
        • Middleware as an example of an app layer concern
          • But can be part of an app that spans all layers, e.g. language preference middleware that also has UI for users and model layer, etc.
            • How does this work for extraction, say pulling language related logic into a separate service?
            • App as glue, so app can get the language preference and pass it to the next thing that cares about language.
            • Common anti-pattern: Passing the request object instead of the things you need from it.
            • Service pattern, letting the Domain query from a service as it's needed.
            • Should we need to pass it down through the layers? Should things near the bottom need to know how to access services?
            • Pass in the service you need to use (for in-process services) to make testing easier
            • Don't like to pass the same parameters over and over again
            • Not opposed to passing the model (User instead of say six fields on the user)
              • If you're always sending the same parameters together, it's probably its own model
              • Difference between passing around simple structure vs. smart object that can make queries
              • Be transparent whether a call is a blocking call to an external service
        • Tracking and analytics are infrastructure layers

...

Expand
  • The anti-corruption diagram above is amusing
    • showcases the engineer's mindset about how "the system under design" is expected to be the new good stuff compared to the older legacy "other subsystem".
  • Anti-corruption layer example from previous job
    • legacy code that integrated with Facebook's AD API, which constantly changed and difficult to keep up-to-speed
    • so they created an anti-corruption layer as an intermediary, as they were a Conformist
    • but sometimes it still broke down since there sometimes wasn't a mismatch in the model.
    • every quarter they had to update the translations - and tried to contain the logic within that layer
    • couldn't really be a Conformist - since they were in a legacy system that was hard to refactor
  • Tradeoffs in the size of the bounded contexts
  • Typically, a bounded context is owned by a single team
  • Enterprise repo
    • More Conformist than Anti-corruption or Separate Ways
    • For platform, try to be Conformist in order not to change the core course-experience
    • For discovery-service, could be Customer/Supplier
      • things are specific to edx.org and may not apply to enterprise or affiliates
      • it's not clear who owns discovery-service, but enterprise is currently a consumer
  • Unifying an elephant
    • Different perspectives → can have individual different bounded contexts → can strive for a common model → may or may not arrive at the elephant
  • Model Context strategy
    • not a how-to-guide, but provides guidelines for trade-offs that would need to be made
  • Transformations
    • If we had bounded contexts with consistent models and isolation, then:
      • Generally speaking, breaking up CONTEXTS is pretty easy, but merging them or changing the relationships between them is challenging.
  • What should be the next steps?
    • openedx/Features directory versus LMS directory
      • unclear on which code should go in the Features directory
      • not just the newest place to put stuff
    • current issues
      • poor organization
      • split across modules
      • cognitive load
      • hard to discover/find code
      • multiple implementations of features
      • large modules
    • when people encounter things that don't belong somewhere, why don't they move/refactor it?
      • is it because they don't know what the vision is?
    • do we need to first align on a domain, before defining the bounded contexts?
    • if we have edx-platform be a pip-installable app, then it will help splitting up modules into their own repo.
    • proposal:
      • finish the book
      • follow-up with discussions with this group to develop the domain and bounded contexts (start with 1 or 2 more meetings)
      • will help us cement this topic and give us a jump-start
      • start at the top-level to determine the higher-level context map

Chapter 15 Distillation

Quotes

  • 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 SUBDOMAINS, 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).
  • Factoring out GENERIC SUBDOMAINS reduces clutter, and COHESIVE MECHANISMS serve to encapsulate complex operations. This leaves behind a more focused model, with fewer distractions that add no particular value to the way users conduct their activities. But you are unlikely ever to find good homes for everything in the domain model that is not CORE. The SEGREGATED CORE takes a direct approach to structurally marking off the CORE DOMAIN.

...

  • 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.
  • Steps:
    1. Identify a CORE subdomain (possibly drawing from the distilla- tion document).
    2. Move related classes to a new MODULE, named for the concept that relates them.
    3. Refactor code to sever data and functionality that are not directly expressions of the concept. Put the removed aspects into (possibly new) classes in other packages. Try to place them with conceptually related tasks, but don’t waste too much time being perfect. Keep focused on scrubbing the CORE subdomain and making the references from it to other packages explicit and self-explanatory.
    4. Refactor the newly SEGREGATED CORE MODULE to make its relationships and interactions simpler and more communicative, and to minimize and clarify its relationships with other MODULES. (This becomes an ongoing refactoring objective.)
    5. Repeat with another CORE subdomain until the SEGREGATED CORE is complete.

Discussion

...

  • Move the core into an isolated location so that its very clear what it is

...

  • This chapter is the core domain!
  • It did feel verbose

...

  • Identify the core domain and start there
  • Focus on the core

...

Abstract Core

  • 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.

Choosing Refactoring Targets

  1. In a pain-driven refactoring, you look to see if the root involves the CORE DOMAIN or the relationship of the CORE to a support- ing element. If it does, you bite the bullet and fix that first.
  2. When you have the luxury of refactoring freely, you focus first on better factoring of the CORE DOMAIN, on improving the segrega- tion of the CORE, and on purifying supporting subdomains to be GENERIC.

Discussion

Expand
  • What is segregated core?
    • Move the core into an isolated location so that its very clear what it is
  • We are thinking this chapter should have come earlier in the book
    • This chapter is the core domain!
    • It did feel verbose
  • Choosing refactoring targets
    • Identify the core domain and start there
    • Focus on the core
  • Developers solving generic problems are not delivering nearly as much value to the business as those who are working on the core
  • Do we have a course model?
    • Kinda? CourseOverviews? CourseModule? Catalog/Publisher?
  • Where do we want to be flexible and where do we want to be fixtured?
    • Too much flexibilty
  • Question on page 398 figure 15.1
    • Is all of this a bounded context? Should we be doing this at the level of our domain? Or our business?
    • Is there one core per bounded context?
    • Take e-commerce
      • You might have core things you really care about within e-commerce
      • Everything about e-commerce might be outside of our core
      • George thinks its a supporting function - not core
      • We can be less rigorous, outsource etc
    • Figure out what our core domain is
    • A core domain might span multiple bounded contexts
    • Split up edX into a core domain, supporting domain, generic domain
      • Each one of these might have multiple bounded contexts
      • A bounded context would not span across core and generic for example
    • Rule of thumb: core should be 20% of your code base
    • You can break things up by modules
  • Figuring out what's core and not core could be done at a macro or micro level
  • Domain vision sounds useful to us
  • There is a more detailed document that talks about the domain 
    • Highlighed core tells us what the true core is within the domain
  • Extracting the core should be a goal in-and-of itself to clarify what is the core
  • You often have to add in a bunch of cruft in order to separate stuff out
  • Having a segregated core is more important than everything else
    • Pay the price! It's worth it.
    • Moving it into its own bounded context is important since it allows you to aggressively work on the core and limit the splash damage.
  • Core, Supporting and Generic are separate domains
  • Having a model that spans the bounded contexts is a problem that needs to be solved
  • This chapter is mostly about how to get started with where we are with the ultimate goal of having domain models that match your code
  • Your core must be beautiful
  • Try to identify the core so that you can put most of your effort into that
    • Hard to figure out what's valuable and prioritize
  • What and where should edX core domain go?
    • Should it be in edx-platform? Or should we put it somewhere else?
  • What is edX's core?
    • What's edX's competitive advantage? What does our business think is our differentiator?
    • Proposal: we provide high quality, rigorous education to a massive audience
    • We need the business and development to be aligned about what the core actually is
    • Could help us build business cases for refactoring
    • We aren't behind a paywall
      • Why aren't our courses indexed by google?
      • We could change our URL structures to make our content rank better in search results
    • Bug triage becomes a simpler
      • Is it core? → CAT-1 otherwise CAT-3
    • Let's take a cut at it - strawman
  • Take discussions
    • Some people might say it's not in the core
    • would that be useful for making certain decisions? if we defined it?
    • How do we resolve disagreements
  • It's easy to get distracted by generic and supporting stuff
  • Generic Subdomain versus Cohesive Mechanism
    • Cohesive mechansim is essentially removing any complicated algorithms (into even helper functions) from the core domain
    • Generic Subdomain is like the modulestore, which is a generic domain that can be used by the core domain or multiple domains
  • Abstract Core
  • Re-read the Segregated Core
    • severing relationships
    • will impact many developers
    • end-goal is to have a module that is your core and nothing else
  • Discussions around tradeoffs between extracting the segregated core versus removing generic domains; whether we could use both tactics at once.

...

    • Cohesive mechansim is essentially removing any complicated algorithms (into even helper functions) from the core domain
    • Generic Subdomain is like the modulestore, which is a generic domain that can be used by the core domain or multiple domains
  • Abstract Core
  • Re-read the Segregated Core
    • severing relationships
    • will impact many developers
    • end-goal is to have a module that is your core and nothing else
  • Discussions around tradeoffs between extracting the segregated core versus removing generic domains; whether we could use both tactics at once.

Chapter 16 Large Scale Structures

Quotes

Image Added

  • 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.
  • 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.
  • One key to keeping the cost down is to keep the structure simple and lightweight. Don’t attempt to be comprehensive.

Evolving Order

  • Let this conceptual large-scale structure evolve with the application, possibly changing to a completely different type of structure along the way.
  • Don’t overconstrain the detailed design and model decisions that must be made with detailed knowledge.

System Metaphor

  • 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.

  • But because all metaphors are inexact, continually reexamine the metaphor for overextension or inapt- ness, and be ready to drop it if it gets in the way.

Responsibility Layers

  • Look at the conceptual dependencies in your model and the varying rates and sources of change of different parts 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.

Knowledge Level

  • 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.
  • 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.
  • 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 reflect- ing rules and knowledge that a user or superuser is able to customize.

Pluggable Component Framework

  • 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.

Discussion

Expand
  • Layering
    • Do these things actually change at different rates?
    • What would these layers even be in the edX context?
    • Why is it easy for us to break up technical things into layers? But domain stuff is harder?
    • Possible layers
      • Potential - Course Content?
        • Do we have a potential layer?
  • Certificates could be it's own application (maybe an IDA)
    • It owns everything related to certs
      • Authoring
      • Viewing
      • Analytics
      • etc
  • Where do courses fit?
    • Different apps would have their own views of the course
    • Just the parts they need
  • We would probably want some kind of API gateway - like api.github.com
    • We can pull data without caring where it's coming from
  • Having course be a overloaded concept probably works to our detriment
    • We may want to have content not in courses
    • Our problem banks are courses
  • How would we do it if we did it again?
    • Maybe leaf nodes should be different from other blocks in our course
    • Having everything be generic might be holding us back
    • Limits us to traditional, fixed, course structures
    • We probably have an implicit concept around "leaf blocks" vs. our "structural blocks"
    • XBlocks and XModules were designed to be very flexible becuase we didn't know what people were going to want to do
    • If we had "leaf blocks" we could sandbox them more easily
  • We should use these structures when we are missing the forest for the trees
  • The structures span bounded contexts and domains
  • Feels premature for us to be thinking about the large-scale structure
  • The layering could be useful for us?
    • Particularly when there are multiple ways of organizing things... it could provide guidelines
    • The layering should reveal itself to you after you rigorously practice the domain and the bounded contexts


Chapter 17. Bringing the Strategy Together

Quotes

Image Added

Discussion

Expand