microservicesdomain-driven-designseparation-of-concerns

Proper separation of concerns between microservices


Let's assume I would like to create a blogging platform that would allow managing user accounts, therefore I came up with 2 microservices:

It's clear to me that Post contains the ID of the author (User) and User contains IDs of the Posts he wrote.

The problem is that when a client requests a Post, I would also like to return the name of the author and send it together to the client in a DTO (view model). I see 2 possible solutions for that:

  1. Introduce the concept of the User (only ID and name) in a domain of the Blogging service. Every time a client requests a Post, all relevant data is fetched only from this microservice. Every time a user's name is modified in a Users microservice, this service is notified and updated author's names.
  2. Keep the concerns completely separated. Every time a client asks for a Post, Blogging microservice is called to fetch Post and then Users microservice is called to fetch the author's name based on the ID.

So far I was leaning towards solution #1 as it would require only 1 call to the 1 microservice when Post is requested, but then let's say if the number of functions (microservices) starts growing and I keep adding small concepts from each of them only to limit the number of calls, I'm afraid I would end up in a spaghetti Blogging microservice... But then I also don't think the number of microservices will grow significantly ;)

Which way do you find better and why? Does any of the approaches break the microservices architecture principles and my concerns are justified?


Solution

  • It really depends on the way your program is going to develop.

    Solution #1 (editing the Blogging model)

    Here you edit your model for the sake of the performance. Most of the time I don't think altering the model itself for the sake of performance is the right way. If you don't think the concept of an User inside the Blogging context is right, you shouldn't put it there. Another problem is that you would have to deal with eventual consistency between you bounded contexts (BC). If you think the concept of User inside Blogging is not a bad idea, it might be probably the way to go.

    Solution #2 (querying the data separately)

    Although this might not be performance friendly, I think this would be the easiest way at the beginning. You won't have to deal with eventual consistency (+dealing with synchronizing the data between BC) and you don't have to alter your model. But if you really care about performance and keeping your model clean, you might be interested in read model.

    Another solution - read model

    The concept of read model is about having at least two separate models: one for reading the data and for writing/editing the data. If we want to implement this concept for your problem, we would create a read model for the Blogging BC where Posts and Users could be merged together (something like in solution #1) and then queried. We can synchronize this data with the help of events, so when the Post or User changes, it would raise an event and save the changed data into your read model. This way you can merge/alter any data you want for better performance. It might be very similar to solution #1, but the main difference is that you don't edit your main model. You create new one just for the reading. It is probably the hardest solution, but if your project is large and performance heavy, this might be a way.

    I wouldn't say any solution is the best or the worst for solving your problem. It always depends on the context.