With references to Vaughn Vernon @ http://vaughnvernon.co/ and his DDD book
In relation with DDD following patterns form execution framework via which:
- External world communicate with Domain Model
- Aggregates structure internal communication
- Upstream domain context execute saga’s and scenarios
- Domain Events propagated and replayed
digraph G {
size="20"
# ratio=expand
edge[style=dotted]
Service -> Request_Reply [label="two-way communication"]
Customer -> Service [label="request service"]
Request_Reply -> Return_Address [label="to whom"]
Return_Address -> Customer [label="make explicit"]
Envelope_Wrapper
Content_Enricher -> Claim_Check [label="retreive"]
Content_Filter -> Content_Enricher [label="bypas to"]
Splitter -> Resequencer [label="reassemblly messages with"]
Scatter_Gather -> Splitter [label="meke flow transparent"]
Content_Based_Router -> Dynamic_Router [label="add awarenes"]
Dynamic_Router
Routing_Slip -> Content_Based_Router [label="direct"]
Recipient_List -> Aggregat [label="forward to"]
Aggregat -> Scatter_Gather [label="reduce from"]
Scatter_Gather -> Recipient_List [label="map to"]
Resequencer
Claim_Check -> Content_Filter [label="store extra data from"]
Message_Expiration -> Aggregat [label="limit by timeout"]
Message_Bus -> Envelope_Wrapper [label="unify by"]
Message_Bus -> Service [label="broadcast"]
Message_Bus -> Message_Channel [label="implements"]
Message_Channel -> Content_Based_Router [label="run by"]
}
- http://www.eaipatterns.com/RequestReply.html
- When two applications communicate via Messaging, the communication is one-way. The applications may want a two-way conversation.
- When an application sends a message, how can it get a response from the receiver?
- Send a pair of Request-Reply messages, each on its own channel.
- Request-Reply has two participants
- ex: RequestReplySpec.scala
- http://www.eaipatterns.com/ReturnAddress.html
- My application is using Messaging to perform a Request-Reply.
- How does a replier know where to send the reply?
- The request message should contain a Return Address that indicates where to send the reply message.
- Server create a child Worker to handle a specific kind of complex message, but Worker to reply to the original Client sender, not to the parent Server.
title ReturnAddress
hide footbox
Client -> Server: Request(client.pid)
Server -> Worker: forward(Request(client.pid))
...
Worker --> Client: Reply
- The request message should contain a Return Address that indicates where to send the reply message.
- This way, the replier does not need to know where to send the reply, it can just ask the request.
- http://www.eaipatterns.com/EnvelopeWrapper.html
- How can existing systems participate in a messaging exchange that places specific requirements on the message format, such as message header fields or encryption?
- Use a Envelope Wrapper to wrap application data inside an envelope that is compliant with the messaging infrastructure. Unwrap the message when it arrives at the destination.
- http://www.eaipatterns.com/DataEnricher.html
- When sending messages from one system to another it is common for the target system to require more information than the source system can provide.
- How do we communicate with another system if the message originator does not have all the required data items available?
- Use a specialized transformer, a Content Enricher, to access an external data source in order to augment a message with missing information.
- ex: ContentEnricherSpec.scala
title content_enricher_spec
hide footbox
create reception
create SheduledDoctorVisit
reception -> SheduledDoctorVisit: new("Joe")
reception -> SheduledDoctorVisit: CompleteVisit(accountEnricher)
SheduledDoctorVisit -> AccountEnricherDispatcher: DoctorVisitCompleted
AccountEnricherDispatcher -> AccountEnricherDispatcher: query("Joe")
AccountEnricherDispatcher -> AccountSystemDispatcher: forward(DoctorVisitCompleted("Joe, Doe"))
reception <- AccountSystemDispatcher :DoctorVisitCompleted("Joe, Doe")
- http://www.eaipatterns.com/ContentFilter.html
- The Content Enricher helps us in situations where a message receiver requires more - or different - data elements than the message creator provides.
- Use a Content Filter to remove unimportant data items from a message leaving only important items.
- Enricher deals with outgoing messages, MessageFilter with incoming
- ex: ContentFilterSpec.scala
- How can we process a message if it contains multiple elements, each of which may have to be processed in a different way?
- Use a Splitter to break out the composite message into a series of individual messages, each containing data related to one item.
- ex: ContentFilterSpec.scala
- http://www.eaipatterns.com/ContentBasedRouter.html
- How do we handle a situation where the implementation of a single logical function (e.g., inventory check) is spread across multiple physical systems?
- Use a Content-Based Router to route each message to the correct recipient based on message content.
- ex: ContentBasedRouter.scala
- http://www.eaipatterns.com/DynamicRouter.html
- How can you avoid the dependency of the router on all possible destinations while maintaining its efficiency?
- Use a Dynamic Router, a Router that can self-configure based on special configuration messages from participating destinations.
- Besides the usual input and output channels the Dynamic Router uses an additional control channel. During system start-up, each potential recipient sends a special message to the Dynamic Router on this control channel, announcing its presence and listing the conditions under which it can handle a message. The Dynamic Router stores the ‘preferences’ for each participant in a rule base.
- ex: DynamicRouterRouter.scala
- http://www.eaipatterns.com/RoutingTable.html
- How do we route a message consecutively through a series of processing steps when the sequence of steps is not known at design-time and may vary for each message?
- Attach a Routing Slip to each message, specifying the sequence of processing steps. Wrap each component with a special message router that reads the Routing Slip and routes the message to the next component in the list.
- ec: RoutingSlipSpec.scala
- rem: good start for Sequencer
- http://www.eaipatterns.com/RecipientList.html
- How do we route a message to a list of dynamically specified recipients?
- Define a channel for each recipient. Then use a Recipient List to inspect an incoming message, determine the list of desired recipients, and forward the message to all channels associated with the recipients in the list.
- ex: RecipientListSpec.scala
- http://www.eaipatterns.com/Aggregator.html
- How do we combine the results of individual, but related messages so that they can be processed as a whole?
- Use a stateful filter, an Aggregator, to collect and store individual messages until a complete set of related messages has been received. Then, the Aggregator publishes a single message distilled from the individual messages.
- The Aggregator is a special Filter that receives a stream of messages and identifies messages that are correlated.
- termination criteria:
- Wait for All
- Timeout
- First Best
- Timeout with Override
- External Event
- ex: RecipientListSpec.scala + Aggregator
- https://vaughnvernon.co/?p=561
- How do you maintain the overall message flow when a message needs to be sent to multiple recipients, each of which may send a reply?
- Use a Scatter-Gather that broadcasts a message to multiple recipients and re-aggregates the responses back into a single message.
- When using Publishes-Subscriber and feeding result to Aggregator termination creteria might not terminate (no pun intended). There for we must use timeout on ‘gather pass.
- ex: ScatterGatherSpec.scala
- http://www.eaipatterns.com/Resequencer.html
- How can we get a stream of related but out-of-sequence messages back into the correct order?
- Use a stateful filter, a Resequencer, to collect and re-order messages so that they can be published to the output channel in a specified order.
- ex: ResequencerSpec.scala
- http://www.eaipatterns.com/StoreInLibrary.html
- How can we reduce the data volume of message sent across the system without sacrificing information content?
- Store message data in a persistent store and pass a Claim Check to subsequent components. These components can use the Claim Check to retrieve the stored information.
- ex: ClaimCheckSpec.scala
- http://www.eaipatterns.com/MessageExpiration.html
- How can a sender indicate when a message should be considered stale and thus shouldn’t be processed?
- Set the Message Expiration to specify a time limit how long the message is viable.
- Most messaging system implementations reroute expired messages to the Dead Letter Channel
- use System.currentTimeMillis to avoid TZ issue
- ex: MessageExpirationSpec.scala
- http://www.eaipatterns.com/MessageBus.html
- What is an architecture that enables separate applications to work together, but in a decoupled fashion such that applications can be easily added or removed without affecting the others?
- Structure the connecting middleware between these applications as a Message Bus that enables them to work together using messaging.
- Canonical Data Model that is independent from any specific application. Require each application to produce and consume messages in this common format.
- ex: MessageBusSpec.scala
- http://www.eaipatterns.com/MessageChannel.html
- How does one application communicate with another using messaging?
- Connect the applications using a Message Channel, where one application writes information to the channel and the other one reads that information from the channel.
- Events cannot fail when being replayed to a processor, in contrast to commands
The current Aggregate state can be defined as a left fold of all past Events that are passed to the mutating functions.
Here be dragons - Event Sourcing origins.
Implementing Domain-Driven Design / Appendix A. Aggregates and Event Sourcing: A+ES
- http://doc.akka.io/docs/akka/2.3-M1/scala/persistence.html
- persistency processor: ProcessorSpec.scala
- channel with delivery guaranty persistency processor: PersistentOnChannelSpec.scala
- write-ahead-log for whatever Persistent messages a processor receives
- command sourcing
- event sourcing EventSourcingSpec.scala
- http://www.theerlangelist.com/2013/07/immutable-programming-fp-style.html
- When needed to combine Entity behavior with Entity update
- Use Value as conceptual whole to replace properties.
- Use Validator to trigger action on new whole value.
- ex: monad.sc
- Dale Schumacher paper on subject.
- Actor calculus in blog
- Basic Plumbing
- Service (DDD Service)
- Customer
- Sink
- Forward
- Label (EAI Envelop)
- Tag
- Sync-Signal
- State
- State-Machine
- One-Shot (Idempotence)
- Race (EAI Recipient List)
- Work-Order (EAI Routing Slip)
- Coordination
- Capability (The Object-Capability Model)
- Authorization-Token
- Future (akka.Future)
- Lazy-Result
- Fork-Join (Scatter-Gather)
- Serializer
- Configuration
- Stem-Cell
- Upgrade
sbt test