16

I've been reading a lot about micro-services lately, and here are some of the conclusions I got so far (please correct me if I'm wrong at any point).

  1. Micro-services architecture goes well with domain driven design. Usually one MS represents one bounded context.
  2. If micro-service A requires functionality which resides in the micro-service B, my model is probably wrong and A and B should actually be one micro-service / BC.
  3. Synchronous communication between micro-services (direct HTTP requests) is bad, cause it defies the purpose of micro-services, and introduces coupling between components.
  4. Asynchronous communication between services is desirable. Services should publish events to message queues, so other services can subscribe and process their part of the event, or use it to replicate a portion of data needed for their context. This way, services can process requests even other services are down, which would not be the case in the synchronous communication.
  5. If micro-service A publishes event, micro-service B subscribes to that event and produces a new event as outcome, micro-service A should not be the one processing newly created event, cause that would be a circular dependency. In this case, we should introduce third micro-service, or combine A and B in to AB micro-service.
  6. Micro-service is actually a misleading term. We should strive for small contexts, but that does not need to be the case. Term should not be "micro-service", but "big enough to do the job service".
  7. Micro-services allows us to introduce new functionalities with more ease and without fear that we will break entire system. It can be done by introducing a new service, or refactoring one of the existing.
  8. Each micro-service should have it's own data-storage. Data replication/duplication is desirable behavior in this architecture.

Other than confirming my understanding of this architecture, my other part of the question is mostly related to service discovery. If the services are communicating asynchronously, and using central event queue like amazon SQS, does that mean that service discovery does not have its place in architecture like that?

Services should not have any knowledge about other services in the system. They are only aware of their context and events they should publish or subscribe to?

6 Answers 6

4
+50

Your conclusions seem mostly founded and sum up very nicely the way to go for microservices.

I'd however not fully support 2, 5 and 8:

  • 2) A simple dependency should not automatically lead to a merger. You have to consider the frequency of such dependent calls and also the frequency of calls from other services.

    So if a microservice A requires functionality in microservice B very frequently, and microservice B is seldomly needed by other microservices, you should challenge the envisaged structure and ask if it wouldn't be more appropriate to group both microservices.

  • 5) of course, you need to avoid endless cycling in the message handling.

    But adding an intermediary will not prevent it: A could launch a message handled by C who launches a message handled by B, who launches a message handled by A and here you are trapped in a loop.

    The problem can't be assessed only by considering microservice level: the question is really about message type and content which could lead to cycle. The graph that models the distribution and processing of messages across the services has therefore to be analyzed as a whole (in fact this can be complex, so you could imagine a monitoring microservice that detects such cycles and break them).

  • 8) yes, each microservice shall have its dedicated storage/database.

    A minimum of replication is required in order to allow services to be independent. However I wouldn't go so far to tell that replication is desired: it has to be kept to the minimum in order to avoid hidden coupling via replication processes.

    Microservices are about loose coupling. This may sometimes be more effectively achieved by calling another microservice to retrieve related data, instead of replicating data.

The two last unnumbered affirmations are too broad to be answered firmly here. I think your suggestion is a good starting point, but that it really depends on architectural requirements and constraints.

2
3

Micro-services are about decoupling different functionality domains. Each service can be developed at a different pace, by a different team, using a different technology stack. This creates organizational flexibility. The trade-off is operational complexity, where each extra service creates one more thing that must be managed in an operational environment. So, the fundamental trade-off of monolith vs micro-service is not about avoiding dependencies, it is about avoiding lock-step development and deployment where everything must ship all at once, but at the cost of having to ship more often because there are more moving parts.

Services should not have any knowledge about other services in the system. They are only aware of their context and events they should publish or subscribe to?

The dependency avoidance issue is a red herring. You will always have dependencies between pieces of your product, and whether they are in a separate service or part of the same code does not alter the fact that dependencies can break. They can break at the operational level, because a key server goes down, and you manage that through operational redundancy and fail-over practices. They can also break at the integration level, because parts change in incompatible ways, which you detect through integration testing. Shuffling code between services does not solve the problem of potentially broken dependencies. The solutions for avoiding broken dependencies are operational redundancy and integration testing, which have nothing to do with the size of your services.

If the services are communicating asynchronously, and using central event queue like amazon SQS, does that mean that service discovery does not have its place in architecture like that?

To answer that question, first answer this one: why do you wish to communicate asynchronously? Is it to ease independent development of separate components? Is it to improve operational availability for a 24/7 system? Let's say it is the latter and you wish to use queues to replicate data to local databases. Well, now your data can be stale. At some point it will be too stale. How do you cope with that? More over, how do you ensure the operational availability of the queue, which is another runtime component? And how do you ensure the availability of those local databases? Instead of managing one database cluster, now you have several. Can your ops team handle this workload? And really, is the complexity worth it, when maybe your users would be happier with more features and a few hours of downtime each month if you built a simple monolith?

I think you see my point. System design is not about right and wrong, it is about choosing from a wide variety of trade-offs. Everything that is wrong can be right, and vice versa, if you but only see it in the right context. Your context is unique to you, so while we can give you an answer, it won't be the answer. Remember who your audience is, what their needs are, and the right design will reveal itself.

2
  1. Micro-services architecture goes well with domain driven design. Usually one MS represents one bounded context.

Disagree. DDD tends to be very OO. an order is delivered? Order.Deliver() whereas Micro-services would have DeliveryService.Deliver(order)

  1. If micro-service A requires functionality which resides in the micro-service B, my model is probably wrong and A and B should actually be one micro-service / BC.

Disagree, you should try and keep you micro services micro. split them up even smaller!

  1. Synchronous communication between micro-services (direct HTTP requests) is bad, cause it defies the purpose of micro-services, and introduces coupling between components.

Disagree. services shouldn't care about who is calling them and callers shouldn't care that the logic is implemented in a microservice.

  1. Asynchronous communication between services is desirable. Services should publish events to message queues, so other services can subscribe and process their part of the event, or use it to replicate a portion of data needed for their context. This way, services can process requests even other services are down, which would not be the case in the synchronous communication.

Queues are good. But your reasoning is wrong. the only difference between sync responses and async is that you wait for the sync one. You can implement RPC style calls with queues and multiple workers no prob.

  1. If micro-service A publishes event, micro-service B subscribes to that event and produces a new event as outcome, micro-service A should not be the one processing newly created event, cause that would be a circular dependency. In this case, we should introduce third micro-service, or combine A and B in to AB micro-service.

Disagree. Its not a circular dependency because your micro-services are not coupled. Also you want to cater for resend senarios, SendEmail, EmailFailed, SendAgain does not need 3 micro-services

  1. Micro-service is actually a misleading term. We should strive for small contexts, but that does not need to be the case. Term should not be "micro-service", but "big enough to do the job service".

Disagree. Check out nano-services.

  1. Micro-services allows us to introduce new functionalities with more ease and without fear that we will break entire system. It can be done by introducing a new service, or refactoring one of the existing.

Disagree. Yes you get decoupling, but the orchestration of micro-services can be as daunting as any monolith project

  1. Each micro-service should have it's own data-storage. Data replication/duplication is desirable behavior in this architecture.

Disagree. Although you shouldn't share storage your micro-services should try to be stateless where possible. don't duplicate data unless its inflight

1

Your conclusions are nice rules of thumb, but not universal. There will be cases when the best option is to break these rules, even in a greenfield project. In some cases synchronous communication is the best option. In some cases it is not good to merge two services into one even if they are coupled by synchronous communication.

And to your other question, service discovery is not required for queue based communication.

0

Um, you're just talking about object-oriented programming. Or at least, what it was originally conceived to be: independent pieces of running code communicating with each other using messages.

Alan Kay conceived of OOP as modeled after biological systems, where cells are relatively independent from each other and just communicate through messages that plug into external interfaces on other cells.

So why do we stop thinking of it as OOP just because all the objects are not running on the same computer? If anything, that's even more object-oriented than if they're on the same computer and part of the same application, because if all the objects are in the same app, then developers often break OOP by using global variables shared by all classes and including the same headers in each file, etc. When all objects depend on the same stuff, they're not as encapsulated as if they're completely independent from each other, and encapsulation is the whole point of OOP.

For example, just about everything said in the other answers are a textbook statements about OOP.

0

Since I often encounter wrong understanding of such an important concept as Bounded Context and Core Domain, I'd like to elaborate a bit on it.

I found it extremely profitable to think of sub-domains as of business-capabilities. Business-capability is something that your organization does. It is one of its business-functions. Since our goal is business-IT alignment, I definitely want them to have 1:1 relation with my technical services.

So this process comes down to the following. First, I define higher-level business-capabilities. It should take the form of noun and verb (or some derivative form). There are usually less than 10 business-capabilities. Then I immense deeper, identifying nested capabilities. And so on, until there is nothing to split. The capabilities that you came to using this approach reflect the real domain, real way your organization works. These capabilities will be innately loosely coupled, so if you map your technical services to this capabilities, they will be autonomous and event-driven. This process is called Business-capability mapping, but there are other ways to find your services, the most prominent of which is probably Value-Chain Analysis.

Here is an example of identifying service boundaries using this approach.

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.