Design Microservices using Domain Driven Design - vidyasekaran/current_learning GitHub Wiki

Spring Cloud Stream internally uses spring integration as per udemy course - Spring microservices indepth using domain driven design -

Lean Axon framework : https://docs.axoniq.io/reference-guide/v/3.3/#aggregate

you can download and run axon - its a jar in zip D:\Udemy_springms_domaindrivendesign\AxonServer\AxonServer-4.4.5>java -jar axonserver.jar

Section 4 : Domain Driven Design

Documentation

D:\Udemy_springms_domaindrivendesign\micro-2020-april\micro-2020-april\micro-lab-docs\ddd

Domain Driven Design

  1. Identify our Problem Space or Business Domains - example: AutoLoans
  2. Identify SubDomains based on biz capabilities for Autoloans - Orginations, servicing, collection

orginations - take care of new new autoloans servicing - generating monthly billing for loans etc collection subdomain - default in billing.

  1. come up with Bounded contxt - design solutions to identified Sub domains.

A monolith will have one bounded context for all our subdomains whereas microservices can have one bounded context per subdomain.

  1. Identify Domain Model - impl of the core business logic within a specific bounded context.

Biz to technical mapping of domain model

Business Entities - Aggregates/Entities/Value Objects Business Rules - Domain Rules Business Flows - Sagas Business Operations - Command/Queries Business Events - Events

Aggregate - which takes care of transaction boundaries..

Order - > multi OrderLineItem - u cannot directly update OrderLineItem (u validate biz rule etc so this ORder class takes care of txn boundaries so this is Aggregate. Refernces to other objects are through datbase primary key not object reference.

biz rule - we cannot add item from 2 different resutrants.

  1. Entities have idenfitier but cannot exist independ of agrregate

aggregate = principal identifier of our bounded context entity = secondary identifier of bounded context, dies when root aggregate dies.

Value - hae no identity and are easliy replicable within an instance of root aggregarte or an entity.

  1. Identify Domain Rules - pure biz rule - assist aggregate for any kind of biz logic execution within scope of bounded context.

  2. Identify commands and queires - represents any kind of operations within bounded context which either effect the state of aggregate/entity or query the state of the aggregate/entity.

Update or Select -

  1. when a state changes in our bounded context we need to notify other bounded contexts using Events..

sagas are biz process / workflows within our business domain.

Sagas react to multiple business events across bounded contexts and "orchestrate the business process" by coordinating interactions among these bounded contexts.

One Saga can go into more than one bounded context i.e

Saga go thru Orgination to service...

Example : Cargo Tracking

Refer Section 4 : Implementating Domain Driven design part 2

  1. Domain : Cargo Tracking

  2. Identify SubDomain :

Booking - cargo booking, assign routes to cargo (best route i.e bangalore to delhi), modify and cancel cargo.

Routing - cover all aspect of cargo iternary , optimal iternary allocation, voyage maintenance for the carriers that will carry cargos (e.g addtion of new routes)

Handling - as cargo progress along assigned route, it will need to be inspcted/handed at various ports of transit.

a. loaded in chennai and unloaded in pune..(info will be entered into our application) b.

This area covers all operations related to handling activty of cargo.

Tracking - Once cargo is booked a tracking id is generated and provided to customer.. customer can track handling detail.

  1. Identify bounded contexts

Map subdomains to each bounded context thats how we hae to do in microservices each having a database.

We have 4 Bonded Context

  1. Booking bounded context (Cargo)

  2. Routing bounded context (Voyage)

  3. HandlingActivity bounded context (handling activiy)

  4. TrackingActivity bounded context.

  5. Idenfity Domain model for each bounded context -that is impl of core biz logic within a specic bounded context...

Identify Core domain model - aggregates, aggregate identifier, entities and value objects Domain model operations - command , queries and Events

Identify Aggregates

  • Aggregates are responsible for capturing all state and business rules associated with bounded context.

we have identified 4 aggregates Booking, Handling, Voyage (Routing) and tracking.

Identify Aggregate Identifier

For each aggreagate come up with aggregate identifier

  1. Booking - Every cargo can be idenfied by BookingId (this is our aggregate identifier)
  2. Voyage - Every voyage has voyageNumber
  3. Handling - activityId
  4. TrackingActivity - trackingId

Identify Entities (Entity cannot exist without aggregate)

In Cargo Aggregate (Booking Bounded Context) as part of booking process, the booking clerk needs to specify the origin of the cargo. This is mapped as entity object, that is location which clearly has an identifier of its own but also cannot exist on its own without the cargo aggregate

Example of Entities : Location , Cargo,

Value Objects

Cargo Aggregate has following Value Objects

Book Amount

Route Specification - origin location, destination locatin, destination arrival deadline.

iternary - has legs - chenni to bangloare, bangloare - pune, pune - delhi delivery progress - of the cargo against its route specification and iternarnary assiged to it. delivery progress provides details on routing status, transport status, current voyage of the cargo, last known location of cargo, next expected activity and the last activy that occured on the cargo

Identify Domain model operations - command , queries and Events

Command - (state change ) perations performed on Aggregates

Commands are -

From Booking Service if below are performed...

Book cargo - does state change and generates bookingID - cargo booked event is published.

Assign route to cargo (Booking cargo service need to invoke Routing service for best route) - cargo routed event is published - an event handler in - Tracking service picks thie and invoke "assign tracker to cargo" generates trackingID

now we have bookingId, tracking in Tracking service.

whenever command are executed an event is published to an topic which is picked by other services.

Query - View cargo details

Queries - select

Event - notification

commands and queries in each

Booking - book cargo, assign route to cargo, cargo detail

Tracking - assign tracker to cargo, track cargo

Routing - get iternary for routing, maintain voyages

handling - register handling activity, hanling history details.

when ever register handling activity is done in handling service a message is published (cargo_handled) to topic which "tracking module" picks and stores tracking detail in DB.

Identify SAGAS in bounded contexts

Booking Saga -- cargo booking --> cargo routing --> cargo tracking (trackingID generated). (bookingId generated)

Handling Saga -- Cargo Handling ---Cargo Claims ---> Cargo Settlement. | | | Cargo Inspection

Identify Domain Model Services -- Part 3 (Rest controllers,

Domain model services are used for 2 primary reasons - Expose biz model or bounded context to external service (rest controller) bounded contexts domain model to be made available to external parties through well defined interfaces. 2ndly to interact with external parties..

3 types of domain model services

Inbound service -interface enables external parties to interact with domain model

Outbound Services- impl all interactions with external repo and other bounded contexts.

applicattion services - acts as facade layer between domain model and both inbound and outbound service.

Example : Cargo Tracking

Refer Section 4 : Implementating Domain Driven design part 2

  1. Domain : Cargo Tracking

  2. Identify SubDomain :

Booking - cargo booking, assign routes to cargo (best route i.e bangalore to delhi), modify and cancel cargo.

Routing - cover all aspect of cargo iternary , optimal iternary allocation, voyage maintenance for the carriers that will carry cargos (e.g addtion of new routes)

Handling - as cargo progress along assigned route, it will need to be inspcted/handed at various ports of transit.

a. loaded in chennai and unloaded in pune..(info will be entered into our application) b.

This area covers all operations related to handling activty of cargo.

Tracking - Once cargo is booked a tracking id is generated and provided to customer.. customer can track handling detail.

  1. Identify bounded contexts

Map subdomains to each bounded context thats how we hae to do in microservices each having a database.

We have 4 Bonded Context

  1. Booking bounded context (Cargo)

  2. Routing bounded context (Voyage)

  3. HandlingActivity bounded context (handling activiy)

  4. TrackingActivity bounded context.

  5. Idenfity Domain model for each bounded context -that is impl of core biz logic within a specic bounded context...

Identify Core domain model - aggregates, aggregate identifier, entities and value objects Domain model operations - command , queries and Events

Identify Aggregates

  • Aggregates are responsible for capturing all state and business rules associated with bounded context.

we have identified 4 aggregates Booking, Handling, Voyage (Routing) and tracking.

Identify Aggregate Identifier

For each aggreagate come up with aggregate identifier

  1. Booking - Every cargo can be idenfied by BookingId (this is our aggregate identifier)
  2. Voyage - Every voyage has voyageNumber
  3. Handling - activityId
  4. TrackingActivity - trackingId

Identify Entities (Entity cannot exist without aggregate)

In Cargo Aggregate (Booking Bounded Context) as part of booking process, the booking clerk needs to specify the origin of the cargo. This is mapped as entity object, that is location which clearly has an identifier of its own but also cannot exist on its own without the cargo aggregate

Example of Entities : Location , Cargo,

Value Objects

Cargo Aggregate has following Value Objects

Book Amount

Route Specification - origin location, destination locatin, destination arrival deadline.

iternary - has legs - chenni to bangloare, bangloare - pune, pune - delhi delivery progress - of the cargo against its route specification and iternarnary assiged to it. delivery progress provides details on routing status, transport status, current voyage of the cargo, last known location of cargo, next expected activity and the last activy that occured on the cargo

Identify Domain model operations - command , queries and Events

Command - (state change ) perations performed on Aggregates

Commands are -

From Booking Service if below are performed...

Book cargo - does state change and generates bookingID - cargo booked event is published.

Assign route to cargo (Booking cargo service need to invoke Routing service for best route) - cargo routed event is published - an event handler in - Tracking service picks thie and invoke "assign tracker to cargo" generates trackingID

now we have bookingId, tracking in Tracking service.

whenever command are executed an event is published to an topic which is picked by other services.

Query - View cargo details

Queries - select

Event - notification

commands and queries in each

Booking - book cargo, assign route to cargo, cargo detail

Tracking - assign tracker to cargo, track cargo

Routing - get iternary for routing, maintain voyages

handling - register handling activity, hanling history details.

when ever register handling activity is done in handling service a message is published (cargo_handled) to topic which "tracking module" picks and stores tracking detail in DB.

Identify SAGAS in bounded contexts

Booking Saga -- cargo booking --> cargo routing --> cargo tracking (trackingID generated). (bookingId generated)

Handling Saga -- Cargo Handling ---Cargo Claims ---> Cargo Settlement. | | | Cargo Inspection

Identify Domain Model Services -- Part 3 (Rest controllers,

Domain model services are used for 2 primary reasons - Expose biz model or bounded context to external service (rest controller) bounded contexts domain model to be made available to external parties through well defined interfaces. 2ndly to interact with external parties..

3 types of domain model services

Inbound service -interface enables external parties to interact with domain model

Outbound Services- impl all interactions with external repo and other bounded contexts.

applicattion services - acts as facade layer between domain model and both inbound and outbound service.

DDD Impl cargo booking

  1. Ist step in implementing domain model is to identify aggregates, entities and value objects.
  2. identify commands of an aggregate - book cargo rest controller - call "Book cargo command" which has command handler (state change of aggregate) that creates cargo object, since command handler changes state of aggrgate we write command handler inside aggregate only.
  3. here we have constructed the comandhandler in the constructor of Cargo, it takes BookCargoCommand as input argument extracting the input and updating the instance variables refer : Cargo. once status of cargo is modified we have to trigger an event

refer cargo extends AbstractAggregateRoot which exposes a registerEvent(Object) to capture domain events and expose them via domainEvents().

addDomainEvent(new CargoBookedEvent(new CargoBookedEventData(bookingId.getBookingId()));

public void addDomainEvent(Object event){ registerEvent(event); //Event is registered with super class AbstractAggregateRoot // there should be transaction listeners that should be configured which will listen to this event where we will fire actual event. }

when ever Cargo class is invoked and the database table records are inserted the below @TransactionEventListener will be invoked. Beacuse we have already registereedEvent. The listener below will publish the event to event broker.

Refer : CargoEventPublisherSerrvice {

@Service public class CargoEventPublisherService{

@TransactionalEventListener public void handleCargoBookedEvent(CargoBookedEvent cargoBookedEvent){ System.err.println("Publishing CargoBookedEvent with booking id *** " +cargoBookedEvent.getCargoBookedEventData().getBookingId()); cargoEventSource.cargoBooking().send(MessageBuilder.withPayload(cargoBookedEvent).build()); }

}

  1. Define message broker code and binding.

  2. Design application services such as Inbound Service, outbound Service and application services.

  3. whevever booking service want to assign a route is invokes ExternalCargoRoutingService fetchRouteForSpecification

From booking service ExternalCargoRoutingService am making a rest api call

From booking service ExternalCargoRoutingService am making a rest api call

CargoHandledEventHandler {

@StreamListener(target="cargoHandlingChannel") public void observeCargoHandledEvent(CargoHandledEvent event){ }

@EnableBinding(CargoEventSource.class)

RabbitMQ Producer - Consumer

Start RabbitMQ from Windows and then http://localhost:15672/#/ (guest/guest)

Producer

Publish in hellooutchannel which publishes message to helloexchange

Source - D:\Udemy_springms_ddd\micro-2020-april\micro-2020-april\microws2020\01-message-producer

application.xml

spring: cloud: stream: bindings: hellooutchannel: destination: helloexchange #group: order binder: rabbit1 binders: rabbit1: type: rabbit environment: spring: rabbitmq: host: localhost port: 5672 username: guest password: guest

Define interface

public interface MySource {

@Output("hellooutchannel")
MessageChannel myoutput();

}

@RestController public class GreetingsController {

@Autowired
private MySource source;

@GetMapping("/greet")
public Greeting createGreeting(String message) {
	
	Greeting greeting=new Greeting(message);
	System.err.println("Sending greeting!! ");
	
	source.myoutput().send(MessageBuilder.withPayload(greeting).build());
	
	return greeting;
	
}

}

http://localhost:2222/greet?message=HelloWorld

===========

Consumer

source - D:\Udemy_springms_ddd\micro-2020-april\micro-2020-april\microws2020\01-message-consumer

application.xml

spring: cloud: stream: bindings: helloinchannel: destination: helloexchange group: helloq binder: rabbit1

  binders:
    rabbit1:
      type: rabbit
      environment:
        spring:
          rabbitmq:
            host: localhost
            port: 5672
            username: guest
            password: guest

server:
port: ${PORT:2225}

Consumer receives message from **helloinchannel **binding

Define interface

public interface MySource {

@Output("hellooutchannel")
MessageChannel myoutput();

@Input("helloinchannel")
SubscribableChannel myinput();

}

Receive message:

@SpringBootApplication @EnableBinding(MySource.class) public class Application {

public static void main(String[] args) {
	SpringApplication.run(Application.class, args);
}

@StreamListener("helloinchannel")
public void processGreeting(Greeting greeting) {
	System.err.println("Recevied Greeting  with message ===="+greeting.getMessage());
		
}

}

⚠️ **GitHub.com Fallback** ⚠️