2

In a microservice-based system, it exist some principles. Sam Newman often refers to them as these:

  1. You should always model your application around the domain
  2. A culture of automation. Automate whats possible to automate
  3. Hide your implementation details
  4. Decentralize everything
  5. Deploy indepentently
  6. Isolate your failures
  7. Highly observable

https://samnewman.io/talks/principles-of-microservices/

When building a system where you microservices reflects the domain, which basically means to me that you have one microservice for each defined bounded context, I find it quite difficult to deal with a servicebus architecture and events published.

An example:

Lets say you're creating a system for a foodstore chain where the customers can sign up for a bonus program, which gives them x % back for every purchase they make.

So you and your team sits down with the customer to identify the domain and you identified at least two bounded contexts. The contexts identified are: Customer and Loyalty. You start out by making two microservices based on these two contexts, CustomerService and LoyaltyService.

The business defines a rule that, whenever a customer signs up, a 5 % discount coupon shall be sent to the customer's email.

The CustomerService exposes an API to create the customer in the database and when the customer is created an event CustomerCreatedEvent is published on the servicebus. As the LoyaltyService is interested in this event to send the 5 % discount coupon, it has to subscribe to this message. In NServiceBus, which is my prefered servicebus, its done this way:

public class SomeClassName : IHandleMessage<CustomerCreatedEvent> 

You might already figured it out, but this is where I struggle to find a good solution to be "compatible" with the principles of microservices. How should the LoyaltyService be able to subscribe and deserialize this event without having a reference to CustomerService either over NuGet or direct reference? Should we duplicate our code so that the CustomerCreatedEvent are defined in both services?

Any suggestions, blog posts, books, pluralsight courses on how to create a domain driven microservice architecture application would be very helpful.

Thanks.

3 Answers 3

2

If both projects use .NET, nothing prevents you from having a common library which would define the base classes.

In a case where you cannot or don't want to have a common project, such as when two services use a different technical stack (say one is in Haskell, another one uses PHP), you can:

  • Either duplicate the class,
  • Or create the class automatically based on Swagger or whatever else you use to advertise the interface of a service,
  • Or create a separate class which only takes the properties you need, as opposed to every property available in the class of the consumed service.

In all three cases, you have the benefit of not being linked to the model of the class from the consumed service. As soon as the fields that you use stay unmodified (i.e. there are no breaking changes), you're good to go.

2
  • Thanks for your contribution, Arseni. Wouldnt having a common library create a coupled application? Commented Jul 12, 2019 at 8:00
  • 2
    It would, but as soon as two services share the same DTO, they are coupled anyway. Note that the common project should contain only the definitions of the exchanged entities, not an actual logic. Commented Jul 12, 2019 at 8:46
3

There will always be some level of dependency in any system which is unavoidable.

In the case of the LoyaltyService, imagine it existing with no dependencies to CustomerService. Conceptually then, you can have loyalty without having a customer, which doesn't make sense.

So the dependency on the CustomerCreatedEvent is perfectly acceptable. The details of the object can limit the involvement between LoyaltyService and CustomerService. The more lightweight the event object, the lower the level of coupling.

The aim for any system design is loose coupling, not zero coupling. Here is a definition of loose coupling that is useful:

Loose coupling is an approach to interconnecting the components in a system or network so that those components, also called elements, depend on each other to the least extent practicable. Coupling refers to the degree of direct knowledge that one element has of another.

https://searchnetworking.techtarget.com/definition/loose-coupling

4
  • Just a throw away comment: if there no dependencies between two components it means they are not meaningfully part of one system.
    – Tjaart
    Commented Jul 12, 2019 at 8:07
  • Thanks for your contribution! Very helpful Commented Jul 12, 2019 at 8:10
  • I think @Tjaart is in the right track, but I think what's being missed here is the problem that's trying to be solved. How can the OP avoid the LoyaltyService having a direct reference to the CustomerService? It turns out, there is a simple solution to this. One, "domain events" should not be published outside of the domain. Essentially, there should be an "integration event" (or application event" which is published. It may have the same schema/contract as the domain event, but they should be of different types to signify that they are not the same. (Cont'd in next comment)... Commented Apr 19, 2020 at 16:39
  • 1
    This would allow the domain event to potentially change at a different rate than the application event. It's conceivable that the application event may never need some of the internal domain changes to the same event. OK, so with that said, in your CustomerService, you may have an event handler which then publishes the integration event CustomerCreated. Also, it is recommended that these integration events be in their own package/component/assembly. This way, bounded contexts/serivces which want to use them only need to take a dependency on the "contracts", and not anything else. Commented Apr 19, 2020 at 16:42
1

Loosely coupling is the key for re-use. Create/Define an exchange format (preferably something open and established like XML Schema or use JSON) and send serialised messages to your messaging sub-system. Now you are open to read and process the message in all interested receivers (eg: your loyalty service). Use your messaging system to route the messages accordingly (eg: Publish-Subscribe or any other technique you like...)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.