What is a microservice?
Many have given thought to formalize a definition for microservices. Martin Fowler and James Lewis have their opinion, and their article is very close to my own opinion. I would encourage anyone to read through it before continuing here.
I believe many already have formulated their own mental model, and I don’t think I need to completely rehash the past few years.
However, my opinion is that a microservice is; a unit of functionality, that fulfills a need and can reliably deploy and live in isolation.
This doesn’t really speak to size though, and my microservice might be my macroservice or monolith. I also concede that “unit of functionality” is vague. If we are talking DDD concepts, we might be talking about one to few bounded contexts. Existing applications might find it easier to progress towards microservices at a feature level.
Plan to change things
Ultimately you will need to plan for refactoring the boundaries of your services. My experience has shown, that like many things, you will often encounter the need to remodel boundaries well into your project.
Grok asynchronous actions
“Understanding”of asynchronous actions will not be enough.
Microservices typically lead to distributed services.
Distributed services will often require asynchronous patterns to be applied.
If your background is mostly client/server applications built around request/response communications, this might be very difficult at first.
However, keep in mind that the real world is asynchronous.
Plan for failure early
Even if your system is a simple Proof of Concept, you should familiarize yourself with the fallacies of distributed computing. Failure happens, and if your are working on a highly distributed system, failures will happen often. Networks go down, disks die, 3rd party services go down in the middle of the day.
The earlier you at least acknowledge these exist, the better off you will be.
Understand that small tutorials are not production examples
Isolation is not easy
Having a service that can be deployed and live in isolation starts off very easy. Once you have multiple services, and perhaps multiple versions of those services, you will find dependencies and dependencies will make isolation more difficult.
Integration is not easy
Standing up REST based web services is very simple, regardless of server/client technology. Moving from explicit request/response patterns into more and more asynchronous patterns will complicate your design.
Furthermore, planning for failure here is tricky, you must be able to plan for failure early on, and once you have services calling services, you need to be building in retry logic and logging and monitoring capable of alerting you to failures.
Time marches on, complexity goes up
Eventually one of your services will go down, so you will need to plan for that..
Do you turn to retry logic? How many times? How often?
Do you need to inform the user that the request eventually succeeded?
What do you do while you wait for the service to respond? What if the user has moved on, or left the application entirely?
How do you coordinate long running operations across multiple services?
Can you deal with partial success? Can you roll back to a known state after failure? Without distributed transactions?
These are the issues we will start tackling next, as we move towards some example implementations.