Skip to main content
Tweeted twitter.com/StackSoftEng/status/1457362203452006402
the problem explained
Source Link
Barney
  • 241
  • 2
  • 7

Consider two services (bounded contexts by DDD):

  • Sales
  • Billing

Sales is responsible for creating orders and Billing for handling payments.

Sales tracks orders and Billing holds payments:

 Sales DB                 Billing DB
+----------+-------+     +------------+----------+-------+
| order_id | paid  |     | payment_id | order_id | total |
+----------+-------+     +------------+----------+-------+
| 123      | true  |     | 456        | 123      | 789.5 |
+----------+-------+     +------------+----------+-------+

When an action is finished an event is published:

  • Sales
    • OrderPlaced
  • Billing
    • PaymentReceived

Billing collects a payment after OrderPlaced is received and Sales updates the order state when PaymentReceived comes.

This creates a cyclic dependency between Sales and Billing.

Sales(OrderPlaced) <---> Billing(PaymentReceived)

Which makesit impossible to build the services in separate artifacts (eg JARs).

The idea behind this is to have independently deployable artifacts, which can be later brought together in an application:

Application.jar (-> Sales.jar, -> Billing.jar)
WebApp.jar (-> Sales.jar, -> Billing.jar)
StandaloneApp.jar (-> Sales.jar)

A possible solution would be to create a technical cut package Events:

  • Sales
  • Billing
  • Events
    • OrderPlaced
    • PaymentReceived

Put both event classes into it and make the services depend on it:

Sales ---> Events(OrderPlaced,PaymentReceived) <--- Billing

But then I see some drawbacks:

  1. The domain events leave the domain contexts.
  2. The package Events can easily explode.
  3. Additional services depending on Events have a dependency on more than what they potentially need.

Is there a better way?

Consider two services (bounded contexts by DDD):

  • Sales
  • Billing

Sales is responsible for creating orders and Billing for handling payments.

Sales tracks orders and Billing holds payments:

 Sales DB                 Billing DB
+----------+-------+     +------------+----------+-------+
| order_id | paid  |     | payment_id | order_id | total |
+----------+-------+     +------------+----------+-------+
| 123      | true  |     | 456        | 123      | 789.5 |
+----------+-------+     +------------+----------+-------+

When an action is finished an event is published:

  • Sales
    • OrderPlaced
  • Billing
    • PaymentReceived

Billing collects a payment after OrderPlaced is received and Sales updates the order state when PaymentReceived comes.

This creates a cyclic dependency between Sales and Billing.

Sales(OrderPlaced) <---> Billing(PaymentReceived)

A possible solution would be to create a technical cut package Events:

  • Sales
  • Billing
  • Events
    • OrderPlaced
    • PaymentReceived

Put both event classes into it and make the services depend on it:

Sales ---> Events(OrderPlaced,PaymentReceived) <--- Billing

But then I see some drawbacks:

  1. The domain events leave the domain contexts.
  2. The package Events can easily explode.
  3. Additional services depending on Events have a dependency on more than what they potentially need.

Is there a better way?

Consider two services (bounded contexts by DDD):

  • Sales
  • Billing

Sales is responsible for creating orders and Billing for handling payments.

Sales tracks orders and Billing holds payments:

 Sales DB                 Billing DB
+----------+-------+     +------------+----------+-------+
| order_id | paid  |     | payment_id | order_id | total |
+----------+-------+     +------------+----------+-------+
| 123      | true  |     | 456        | 123      | 789.5 |
+----------+-------+     +------------+----------+-------+

When an action is finished an event is published:

  • Sales
    • OrderPlaced
  • Billing
    • PaymentReceived

Billing collects a payment after OrderPlaced is received and Sales updates the order state when PaymentReceived comes.

This creates a cyclic dependency between Sales and Billing.

Sales(OrderPlaced) <---> Billing(PaymentReceived)

Which makesit impossible to build the services in separate artifacts (eg JARs).

The idea behind this is to have independently deployable artifacts, which can be later brought together in an application:

Application.jar (-> Sales.jar, -> Billing.jar)
WebApp.jar (-> Sales.jar, -> Billing.jar)
StandaloneApp.jar (-> Sales.jar)

A possible solution would be to create a technical cut package Events:

  • Sales
  • Billing
  • Events
    • OrderPlaced
    • PaymentReceived

Put both event classes into it and make the services depend on it:

Sales ---> Events(OrderPlaced,PaymentReceived) <--- Billing

But then I see some drawbacks:

  1. The domain events leave the domain contexts.
  2. The package Events can easily explode.
  3. Additional services depending on Events have a dependency on more than what they potentially need.

Is there a better way?

Source Link
Barney
  • 241
  • 2
  • 7

How to resolve cyclic dependencies in Event-driven systems?

Consider two services (bounded contexts by DDD):

  • Sales
  • Billing

Sales is responsible for creating orders and Billing for handling payments.

Sales tracks orders and Billing holds payments:

 Sales DB                 Billing DB
+----------+-------+     +------------+----------+-------+
| order_id | paid  |     | payment_id | order_id | total |
+----------+-------+     +------------+----------+-------+
| 123      | true  |     | 456        | 123      | 789.5 |
+----------+-------+     +------------+----------+-------+

When an action is finished an event is published:

  • Sales
    • OrderPlaced
  • Billing
    • PaymentReceived

Billing collects a payment after OrderPlaced is received and Sales updates the order state when PaymentReceived comes.

This creates a cyclic dependency between Sales and Billing.

Sales(OrderPlaced) <---> Billing(PaymentReceived)

A possible solution would be to create a technical cut package Events:

  • Sales
  • Billing
  • Events
    • OrderPlaced
    • PaymentReceived

Put both event classes into it and make the services depend on it:

Sales ---> Events(OrderPlaced,PaymentReceived) <--- Billing

But then I see some drawbacks:

  1. The domain events leave the domain contexts.
  2. The package Events can easily explode.
  3. Additional services depending on Events have a dependency on more than what they potentially need.

Is there a better way?