11

I currently have two microservices. We'll call them A and B.

The database under microservice A has the following table:

A
|-- users

The database under microservice B has the following table:

B
|-- trackers

The requirements state that users and trackers have a many-to-many relationship.

I'm not sure how to properly handle this within a microservices architecture.

I could see this working one of three ways:

  1. A user_trackers table is added to microservice A. This acts similar to a join table containing "foreign keys" to users and trackers.
  2. A owners table is added to microservice B. This table acts similar to a polymorphic join table. This would allow any service to create an association with a tracker. This may look somewhat like this: B |-- trackers |-- owners |-- owner_id |-- owner_type |-- tracker_id
  3. Keep records for users and trackers in each microservice. Keep them in sync with some sort of pubsub system.

I was originally going to go with option 2 because I liked that it preserved transaction boundaries. I can create a tracker and associate it with something atomically. However, it seems out of scope for microservice B. Why should microservice B care that microservice A wants to create an association?

I feel like there's probably a good pattern here that I'm not aware of. Do any of the options I laid out make sense? Is there another option that may make more sense?

10

First of all, I'd start with domain description. You haven't mentioned what it is about (I can guess, but it'd be only a guess). After that I would try to decompose it using value-chain analysis or business-capability mapping. And only after that I would think about implementation.

Considering your problem, the first thing that goes to my mind is that you identified your service boundaries wrong, simply because they need each other's data. You don't want to end up with distributed monolith, do you?

The second thing is that you probably haven't worked through your domain good enough. What concept is represented with users table? Is it a registered user, with all the information and behavior required for registration? Are you sure it's the right concept for communicating with trackers (whatever it is)? So if I got it right, your option 2 is exactly about that: introducing the owner concept that's much closer to your domain. If it really is so, I'm for option 2 as well.

However, it seems out of scope for microservice B. Why should microservice B care that microservice A wants to create an association?

It's all about boundaries. I guess you want to form microservices around entities. That's where SOA failed with its layered service architecture. The better approach is to create services that represent some business function, so they encapsulate both data and behavior. From more practical point of view, it's about creating services around business-processes or use-cases. For example, you could have one service for user registration. It contains user's data and behavior required to register a user. Thus the concept of user is formed naturally, and it belongs only to service A. And this brings me to the next point: the other way to think about services is bounded context. It's a good practice to align services and bounded contexts.

When user is registered, UserCreated event could be emitted. Your second service I guess is interested in it. So upon receiving it a completely different entity could be created, say, Owner entity (whatever that is, either). I.m pretty sure there are a lot of interesting collaborations between it and tracker entity -- keep them in a single service.

Be extremely cautious with option 3. If you copy data, functionality follows. It results in tight coupling. And don't cover with CQRS term, it's not about data synchronization between services via events.

  • I love the term "distributed monolith" but the way it's defined in the link you give seems to be not directly related to the question here. The way I think you are using it is related to coupling between services and the article focuses on binary dependencies. I think the way you are using is superior but I'm struggling to find a reference that clearly defines it that way. – JimmyJames Dec 7 '17 at 18:04
  • I've always included chatty services in the "distributed monolith" category, which is not widely spread, common way. – Zapadlo Dec 7 '17 at 19:30
4

Zapadlo's answer has a lot of good information and reasoning in it. I'm going to add a little practical advice here that may make it easier to work through your issues and the advice in that answer.

The way you've framed your design question is around database structures and how to fit a new requirement for your structures into that. This implies that your are building the service design out from your data model. For example, what I don't see is how the relationship between users and trackers is to be accessed or used.

In service design, the structure of the interface is the most important thing about the design. In fact, the implementation is almost irrelevant in comparison particularly in the case of microservices. The reason is that once you put your service in place, all dependencies on your service should exist on the interface alone. If you get it right, you should be able to completely rewrite the implementation without any consumer. And that's the main benefit of autonomy. No one cares how you built it. They just need it to work the way you've communicated that it will.

Before anyone can determine how this looks in the database or where you want this, you really need to explain how this information is going to be used. Is this something that will be exposed through a service or is it some sort of data you want to shuffle off for analytics?

On a side note, I would avoid bi-directional dependencies at almost all costs. If you have dependencies, you really want only one side to know about the other. Once the dependencies are in both directions, they services become essentially an atomic unit.

0

A lot of it comes down to the domain itself. If a user with zero trackers doesn't make sense then the user service needs to know about trackers. If a tracker has to have a user then trackers need to know about users. If something like having a tracker with multiple owners or being able to transfer a tracker from one user to another makes sense then maybe this information belongs in yet another service.

0

Question: Why is your data separated along Datatables?

I would tend to go with option 3: the services are totally separate and can answer the respective questions they might need to answer. Furthermore, they are a lot more resilient. But be careful, your services could de-synchronize if they miss events, but that can be solved through eventual consistency.

Also, you could consider merging both services - if both are not able to answer without knowing about each other, I would just merge them since they are probably part of a single domain.

  • This is part of the religion of microservices, that each service needs full autonomy. Thomas Erl describes it as one of the principles of service orientation in "Princples of Service Design" c. 2008. – JimmyJames Dec 7 '17 at 15:02
  • @JimmyJames As somebody who writes a ms-architecture myself: There is a lot of debate on the question how big a ms should be. In this case, size might not even matter because the service(s) might not be separated correctly - e.g. don't cut along tables, cut along business domains. – Christian Sauer Dec 8 '17 at 6:13
  • Right. The problem is there's a major cargo cult around microservices right now. I see a lot of people implementing microservices because that's what the cool kids are doing and not considering or understanding the tradeoffs. For example, I get the sense that a lot of people think MS autonomy is a about technology and 'the cloud'. I see it as more of a solution to an organizational issue. Trading pointer dereferencing for network IO is extremely costly. You can't just apply this thoughtlessly and expect things to go well. – JimmyJames Dec 8 '17 at 15:01
  • @JimmyJames I think it can be about technology, too - especially when certian technologies are well suited for some domains, but not for others. We use C# and Python for our MSs. Some of that is due to organizational problems ("I have programmed c# for 20 year, I don't need to learn newfangled untyped languages!"). - but also due to the nature of our system. The data science parts are best made in python, while some infrastructure and web tasks are best done in C#. – Christian Sauer Dec 8 '17 at 15:40
  • Sure, that's a pretty valid reason to do it. The problem I see is that people will want to split every service into a separate node simply because "we're doing microservices" even if everything is written with the same code on the same platform and there's a ton of dependencies between services. There's really not much benefit to microservices in that case and you've added a whole set of new issues. – JimmyJames Dec 8 '17 at 16:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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