- I always see that microservices are supposed to communicate with one another. Currently 2 separate microservices might call the same backend service. Is this correct design, or should I make one microservice A that calls a backend service, and 2 other microservices, B and C, that call A?
Answer 1: Deciding to split or merge microservices, or alter their communication structure is really dependent upon what you want to accomplish in regard to performance, security, network and code overhead, and your operational limitations.
You can answer your question "should I make one microservice A that calls a backend service, and 2 other microservices, B and C, that call A?" by answering a few questions such as:
- How is performance impacted for all services when you make either decision?
- How is security impacted for all services when you make either decision?
- Which decision is easier for developers to reason about, or helps to simplify the code structure?
- Are there any restrictions that would limit either decision (cost overrun with new servers/containers, external api rate-limits from third-party services, etc.)?
Once you answer the questions that matter you can find reasons why you would or wouldn't split a specific service.
Side Note: You are very clear that your organization designates the difference between a microservice and a backend service. Sometimes organizations use the wrong domain-specific language and group things in a way that is incompatible with the mental flexibility you need as a developer to do your job. To be clear: everything is a microservice. You shouldn't be afraid to open a REST interface on a "backend" service if the performance, security, overhead, and limitations matrix are in favor of this decision... because "it's just another service".
IF your definition of backend services are shared databases or queue services, then you're not doing microservices the right way. Split all of those tables off into database instances attached to their respective services. Services should not share the same database schema, but should share data with their defined (REST / websocket / network) interfaces. The answer in this scenario would be "make one microservice A that calls a backend service, and 2 other microservices, B and C, that call A".
- We want to push some formatting from the UI to the microservice. For instance, we always want to format a phone number from backend service A to have dashes. 5552223333 to 555-222-3333. Should I have a formatting microservice I pass through, or is it best to do it on each microservice that calls backend service A?
Answer 2 Shared formatting (or algorithms) should be placed in a shared module and installed in the code closest to the transformation. I would suggest the code necessary for parsing, formatting, and validating phone numbers be moved to a shared module that can be installed on each microservice that must handle phone numbers.
Side Note: If you disagree with the shared module idea and opt for a "phone number formatting service", then let's explore how that scales. What happens when you need an "address formatting service"? Is this a separate service with all of the code, network, and maintenance overhead? Do we open up new REST endpoints on the "phone number formatting service" and blur the lines of single responsibility? The easier solution would be to create a new shared module (which has a low code, network, and maintenance overhead), isolate all of the address logic in that module, then include it in any service that must handle that logic.
- Each web app only communicates with it's specific microservice. Should web apps communicate to multiple services rather than just the one? This would get rid of the duplication I see throughout the microservices.
Answer 3: This is a tricky question. In an absolute and ideal world; using one microservice as the facade for each web app is the right decision. This buffers erratic user behavior and performance issues from your core services. It also ensures clean separation of the client-specific logic from the core logic.
However, the real world answer is more organic. Start developing the web app and make requests directly to the services. If the capability of the web app grows beyond what is manageable with point-to-point communication to each service then build a facade.
Most likely the first people to speak up will be the mobile devs asking for a single aggregate endpoint/service they can call instead of many endpoints/services.
Side Note: You should get rid of the code duplication in your services independent of the answer you choose here. If there is code duplication across your services then move that into a shared module with a simplified interface, then include that module in your services and remove the duplicate code. You will still have some code duplication, but it will be code that uses the public interface you designed (stable), instead of specific business logic on how to handle a problem (less stable).