DEV Community

CodingBlocks

Episode 62 – Software Architecture – Strategic Design and Domain Events

We’re not saying that Michael is Carmen Sandiego. We’re just saying that nobody has ever seen them in a room together. And this week, we don’t know where in the world either are, as Allen and Joe continue the Domain Driven Design discussion without Michael. Nor Carmen.

Sponsors

Become a Part of the Slack Community

If you haven’t already, you should check out http://www.codingblocks.net/slack to become a part of the Slack community and join in on the conversation today.

Survey says …

This episode we ask: At what speed do you listen to podcasts?

#yop-poll-container-39_yp595070b2659d1 { width: 1000; background:#fff; padding:10px; color:#555; overflow:hidden; font-size:12px; } #yop-poll-container-39_yp595070b2659d1 input[type='text'] { margin:0px 0px 5px 0px; padding:2%; width:96%; text-indent:2%; font-size:12px; } .yop-poll-name-39_yp595070b2659d1 { font-weight:bold; background:#327BD6; color:#fff; padding:5px; text-align:center; font-size:12px; } #yop-poll-questions-container-39_yp595070b2659d1 { font-size:14px; margin:5px 0px; } .yop-poll-question-container-39_yp595070b2659d1 { padding: 2px; } .yop-poll-question-39_yp595070b2659d1 { background:#327BD6; color:#fff; margin-bottom: 21px; margin-top: -10px; font-style: italic; text-align: center; width: 100%; padding:5px; } .yop-poll-answers-39_yp595070b2659d1 { } .yop-poll-answers-39_yp595070b2659d1 ul { list-style: none outside none; margin: 0; padding: 0; } .yop-poll-li-answer-39_yp595070b2659d1 { font-style:normal; margin:0px 0px 10px 0px; padding:0px; font-size:12px; margin-bottom:20px; } .yop-poll-li-answer-39_yp595070b2659d1 input { margin:0px; float:none; } .yop-poll-li-answer-39_yp595070b2659d1 label { margin:0px; font-style:normal; font-weight:normal; font-size:12px; float:none; } .yop-poll-results-39_yp595070b2659d1 { font-size: 12px; font-style: italic; font-weight: normal; margin-left: 15px; } .yop-poll-customs-39_yp595070b2659d1 { } .yop-poll-customs-39_yp595070b2659d1 ul { list-style: none outside none; margin: 0; padding: 0; } .yop-poll-li-custom-39_yp595070b2659d1 { padding:0px; margin:0px; font-size:14px; } /* Start CAPTCHA div style*/ #yop-poll-captcha-input-div-39_yp595070b2659d1 { margin-top:5px; } #yop-poll-captcha-helpers-div-39_yp595070b2659d1 { width:30px; float:left; margin-left:5px; height:0px; } #yop-poll-captcha-helpers-div-39_yp595070b2659d1 img { margin-bottom:2px; } #yop-poll-captcha-image-div-39_yp595070b2659d1 { margin-bottom:5px; } #yop_poll_captcha_image_39_yp595070b2659d1 { float:left; } /* End CAPTCHA div style*/ .yop-poll-clear-39_yp595070b2659d1 { clear:both; } #yop-poll-vote-39_yp595070b2659d1 { } /* Start Result bar*/ .yop-poll-results-bar-39_yp595070b2659d1 { background:#f5f5f5; height:10px; } .yop-poll-results-bar-39_yp595070b2659d1 div { background:#555; height:10px; } /* End Result bar*/ /* Start Vote Button*/ #yop-poll-vote-39_yp595070b2659d1 div#yop-poll-vote-39_yp595070b2659d1 button { float:left; } #yop-poll-vote-39_yp595070b2659d1 div#yop-poll-results-39_yp595070b2659d1 { float: right; margin-bottom: 20px; margin-top: -20px; width: auto; } #yop-poll-vote-39_yp595070b2659d1 div#yop-poll-results-39_yp595070b2659d1 a { color:#fff; text-decoration:underline; font-size:12px; } #yop-poll-vote-39_yp595070b2659d1 div#yop-poll-back-39_yp595070b2659d1 a { color:#555; text-decoration:underline; font-size:12px; } #yop-poll-vote-39_yp595070b2659d1 div#yop-poll-archive-39_yp595070b2659d1 a { color:#555; text-decoration:underline; font-size:12px; } #yop-poll-vote-39_yp595070b2659d1 div { float:left; width:100%; } /* End Vote Button*/ /* Start Messages*/ #yop-poll-container-error-39_yp595070b2659d1 { font-size:12px; font-style:italic; color:red; text-transform:lowercase; margin-bottom:20px; text-align:center; } #yop-poll-container-success-39_yp595070b2659d1 { font-size:12px; font-style:italic; color:green; margin-bottom:20px; text-align:center; } /* End Messages*/#yop-poll-container-39_yp595070b2659d1 img { max-width: 1000; } .yop-poll-forms-display{}
At what speed do you listen to podcasts?
  • .5x
  • 1x
  • 1.5x
  • 2x

News

All Things Coding Blocks

You need some Coding Blocks gear in your life. Head to http://www.codingblocks.net/swag to learn more about how you can get the things you need.

Strategic Design

  • The pie in the sky goal for an organization is one tightly integrated system that spans the entire business
  • Imagine if Amazon ran off one website … the customer site, the vendors, accounting, the warehouses, marketting, the buyers…
    • Yeah, right – so we look at modularizing parts – dealing w/ it in pieces
    • The trick is to modularize things, w/out losing the benfits of integration
  • Need to find the balance between a monolithic app, and small subsystems that are hastily thrown together – and don’t help solve enterprise-wide problems
  • We need systematic, evolving design strategy

3 principles

  1. Context – What we’re focusing on right now
    • The most fundamental. Deals w/ how we divide things up into bounded context.
    • How we draw lines between applications, and parts of applications
  2. Distillation reduces the clutter and focuses attention appropriately
  3. Large scale structure (slicing things up into Responsibility Layers)
    • As systems grow complex, we need to deal w/ things at a higher level of abstraction

Techniques for maintaining Model Integrity

  • What does integrity mean?
  • Different programmers may interpret and write code around how they interpret the model
  • Integrity is a measure of how similar these conceptual models are, and therefor how similar the code is
  • For example: Programmer A writes some code to remove a customer – They change a status column, and create a record in a history table, Programmer B has a task to remove customers based on a batch process – they update the bitfield but miss the history. Programmer C is cleaning up some corrupt data, and deletes the records
  • If there had been a foreign key on the history table and created the history record via trigger, we would have enforced data integrity

But is that really 100% feasible for a large enterprise?

And if it was, first consider the risks of an over ambitious unification – aka “the new system”

  1. Too many legacy replacements attempted at once
  2. Large projects bog down because the coordination exceeds the abilities
  3. Applications w/ specialized requirements may have to “cheat” when shared models don’t satisfy their needs
  4. The additional complexity required to do _everything_ might not be worth the gain

So…what do we do?

  • We need to conciously decide on our strategies and be consistent about enforcing them
  • Start by taking inventory – and mapping our bounded contexts

Bounded Context

Before we can really do anything, we need to recognize our existing bounded contexts

What are bounded contexts?
  • Meaningful “things” with boundaries
  • Example might be a corporate website, or in the e-commerce app you might have a customer portal, and an administrative portal – these probably bounded contexts. Have a shared library between the two – that’s probably one too
  • Example: Cell in your body is composed of various parts that have different responsibilities – but cells also have outer membranes/walls that determine what may pass through
The book gives us some managerial AND code advice:
  • 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.
2 types of problems arise in bounded contexts: “splits”
  1. Duplicate Concepts – two entities that represent the same concept (copy/paste)
  2. False cognates – ambiguities or disagreements in the model terms (for example, a “customer” table that contains people that have never purchased – somebody says they want a report of customers)

Strategy: Continuous integreation

  • Reviewing, Merging, Testing
  • Ideally splinters will be caught and fixed quickly

Strategy: Context Map

  • Overlap between project management and software design
  • Managers and team members need a clear view into the ongoing conceptual subdivision of the software model
  • Prevent situations where (for example) 2 programmers on different teams solve the same problem differently
  • Map the terrain as it is – rather than how you want it to be
  • Find something dirty? Draw a dragon on the map and move on
  • Context maps help define important areas for testing
  • Choose good names, and enforce those boundaries!

Strategy: Shared Kernel

  • An appropriate strategy for smaller domains – literally a shared library, schema
  • Make sure you consult the other teams!

Strategy: Customer/Supplier teams

  • Can be a problem if the teams are moving at different speeds
  • Emphasize the roles – call them Customers and Suppliers instead of upstream/downstream
  • Make the suppliers accountable to the customers
  • Write tests!

Strategy: Conformist!

If you can’t beat them – uh…then

  1. Abandon?
  2. Take responsibility for the translation
  3. Join them, adopt their model

Strategy: AntiCorruption Layer

  • Even greenfield systems have to be integrated w/ legacy systems
  • Difficulty of relating two models can overwhelm the intent – ad hoc – ew!
  • Don’t avoid it – push it to the boundaries!
  • If you don’t, then the conceptual models from the other system can leak into your code – “poison”
  • Sometimes this can be subtle
  • Credit Card processing example (vs PayPal / Stripe / etc)

What to do?

  • Create an isolating layer than handles the translation in both ways
  • This can look like a service…but isn’t always
  • Can be implemented as a combination of facades, adapters, and translators
    • Facade: An alternative / simplified interface – written strictly in accordance with the other systems model
      • Facade belongs in the bounded context of the other system??
    • Adapter: Wrapper that allows client to use a different protocol than the implementer
      • Example might be some code that abstracts away a web-service
    • Translator: Specialized class that is used by adapters…but should be kept separately
      • Used just for mapping (for example, converting state codes to state ID, or fname to firstname)

Couple rules for consideration

  • Can be bidirectional
  • Can include the facade w/ the other subsystem
  • Refactoring the other system might make your life easier
  • Consider modifying your model to fit better with theirs…might be a necessary evil
  • Be careful to only add functionality if it is specific to the relationship of the two systems (for example, history / logging)
  • There is always a cost to integration, and creating an anti-corruption layer can be time consuming and expensive – considerations should be made before jumping in head first

Separate Ways

  • Give up!
  • Example: Mint.com pulls data in from thousands of financial institutions – Supporting 80% of their customers might be exponentially easier than 100%
  • But what about those 20%? Well – they have to log into more than one website

Strategy: Open Host Service

  • Do a lot of systems need to interop w/ you? Consider publishing an API

Strategy: Published Language

  • Consider developing an intermediary language (lol – XML) if you need to (but you probably won’t )

Domain Events

  • Domain events are used to capture that something happened in the domain.
  • Domain events happened in the past
  • Good practice to include a DateTime to indicate when the event occurred
  • Good idea to include the aggregate entity ids
  • Each domain event is it’s own class (similar to writing Exception classes for specific needs)
  • Raising the event should have no side effects or behaviors

“one of the final patterns needed to create a fully encapsulated domain model – one that fully enforces a consistency boundary and invariants.” – https://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/

In the article from Jimmy Bogard above, one of the things Allen likes is the idea of taking domain events and adding them to an event collection on an entity rather than raising the event immediately in some chunk of code – specifically breaking raising events out of static methods

  • Reduces unexpected side effects
  • Easier to bundle in a logical transaction
  • More testable

Why is this important to Domain Driven Design?

  • Decouples domain logic from service side effects

If you have an order aggregate…and you process a payment on your order, after that’s done, part of your order needs to be allocated from inventory, and then the line item on the order needs to be updated to show that it’s shipped…if you don’t have this domain event, then typically what you’ll see is something like…

void processPayment() {
   allocateInventory();
   shipLineItems();
}

Wouldn’t it be nicer to have…

void processPayment() {
   Events.Add(new PaymentProcessedSuccessfully);
}

Now anywhere that cares about the PaymentProcessSuccessfully domain event can respond and do what they need to do all decoupled…that way if in the future you need to add another step to the process, it’s as simple as hooking up another handler

  • Publisher / Subscriber pattern

Resources We Like

Tip of the Week

Tell a Friend

Do you know someone that doesn’t know about Coding Blocks? Well, here’s your chance to help them and us at the same time. Just share Coding Blocks with your friend. Easy peasy lemon squeezy.

And if you haven’t already, you can also help us out by leaving us a review. Stop by http://www.codingblocks.net/review to find links to your favorite podcast aggregators and let us know how we’re doing.

Episode source