Part Two: Breaking up the Jigsaw
Part one identified that object behaviour coupling is similar to a jigsaw puzzle. This is a highly coupled jigsaw of varying shaped objects. These different shaped objects makes their re-use and refactoring difficult within monolithic applications.So, you may be asking how are microservices helping this problem?
For me, I see the evolution of microservices to be an evolution to break down the rigid behavioural coupling imposed by object methods.
We had applications grow to become monoliths:
This became unmanageable to enhance or re-use, as everything was tightly coupled together in a rigid jigsaw.
Our first attempts was to try re-using parts of the jigsaw with Service-Orientated Architectures. This looked like the following:
The service-oriented architecture was, in my opinion, a doomed to failure attempt to the expose method connectors outside the system for re-use. Yay, we can now call into our monoliths to re-use aspects of them. Oh, wait there was too much coupling to that method that it was just too hard to separate it from the rest of the monolith.
Ok, we could put in governance and some great coding practices to avoid this. However:
- deadlines
- shortcuts
- new team members
- occasional bad design decisions
- etc
We needed to break things down and keep them isolated.
So we split the jigsaw up into smaller puzzles. The result is the following smaller puzzles joined by HTTP requests / Queues:
And for me, microservices were born.
At first glance, this looks very similar to the original EJB 1.0 specification of only remote calls. Now one might argue that microservices are not single objects like EJBs typically were. This, however, is not why I see microservices an improvement over remote EJBs.
EJBs use remote procedure calls that allow multiple parameters and varying exceptions to be thrown. This does nothing to decouple you from the varying shape of the method call. EJBs only enable methods to be called remotely. These remote method calls continue to have all the jigsaw coupling issues of method calls. Except, now they are less reliable due to network failures. Hence, EJBs suffer the method coupling problems that leads you to a distributed monolithic jigsaw.
Microservices on the other hand, standardised calls to other microservices via HTTP requests / queue messages. Looking at the five coupling aspects of the method call (Inversion of Coupling Control), HTTP requests / queue messages remove most of the method call coupling:
Method Coupling Aspect | HTTP Request | Queue |
Method Name | URL Though, can be decoupled indirection via lookup in service directory/registry | Outbound queue Provides decoupled indirection to target consumer (via message routing) |
Return Type | May provide return entity. However, typically this is only for front-ends with users waiting. Note: be careful of synchronous returns between microservices, as they can create synchronous coupling that can lead to distributed monoliths | N/A, as decoupled from any synchronous return values |
Parameters | Only single payload Typically JSON/XML serialised object. | Only single payload Typically JSON/XML serialised object. |
Exceptions | Standardised REST status codes. Note: be careful of relying on error response payloads, as they may be indications of cohesiveness problems in the microservice | N/A, as decoupled from any synchronous processing |
Threading | Decoupled as separate process Any threading model enabling synchronous response | Decoupled as separate process No restriction on threading model |
Therefore, using HTTP requests / queues, the microservice calling shape is effectively standardised. Given the payload is typically a serialised object (e.g. JSON/XML), this removes the ability to pass multiple parameters. Standardising the HTTP status codes disallows varying exceptions. Plus, my preferred microservice communication of queues is decoupled by its very nature.
So by making the communication HTTP requests / queue messages, microservices are removing the method coupling problems. It makes it easier to call different microservices, as the shape is only a name (HTTP URL / Queue name) and a single parameter (payload).
This, actually, is similar to the object reference shape of type and reference discussed in part one. However, now type is parameter type (payload serialised object) and reference is name (URL / Queue name). This allows microservice behaviour to somewhat be represented like the idealised object graph at the start of part one - lines to standard shaped microservice call connectors.
Stay tuned for part three where we look at further isolating the microservice container to the servicing method to effectively enable local microservices.
No comments:
Post a Comment