Should you happen to be researching ‘Service-Oriented Architecture’ (SOA) on the Internet today, the most recent articles you are likely to find will often be titled: SOA vs microservices. Complicating the picture a little further is that you will also find respected industry experts, such as Martin Fowler, stating that some “consider microservices to be one form of SOA, perhaps service orientation done right”.
Things will become even murkier when you stumble upon very recent tweets declaring that the Uber ‘Payments Experience Platform’ is “moving many of our microservices to … macroservices (well-sized services). Exactly b/c testing and maintaining thousands of microservices is not only hard – it can cause more trouble long-term than it solves the short-term”. This tweet by @GergelyOrosz of Uber on 6 April 2020, triggered some near-violent responses arguing that Macroservices are nothing more than ‘SOA-again’.
As such, it seems it is time to return to the ever-sage Martin Fowler: “The problem ... is that SOA means too many different things, and that most of the time that we come across something called ‘SOA’ [there is] ... a focus on [‘Enterprise Service Bus’ middleware,] ESBs used to integrate monolithic applications. This common manifestation of SOA has led some microservice advocates to reject the SOA label entirely”. In the SAP world, given that SOA is equally encouraged upon the foundation of SAP XI/PI/PO as the appropriate ESB, I shall standardize upon the use of an ESB as a fundamental component of ‘SOA’. Furthermore, it is difficult to imagine an ERP-centric enterprise that would not have an ESB at the heart of its Service-Oriented Architecture.
As ESBs work via message-passing, those messages are typically asynchronous, and are always passed from one fixed source to one or more fixed receivers; communication is always point-to-point. If the version of a called Service API is to be changed, it can be reasonably expected that – coordinated – changes will also be required in the ESB; most typically in transformations. This is because point-to-point communication requires significant coordination between source and receiver; the API name is known, but which version of the API is to be used and what is its corresponding ‘Interface’/signature?
Given all of this, if ‘Macroservices’ are to describe an architectural pattern other than ‘SOA-again’ – and there is clearly no need for a new term if this is not to be the case – then this new term should be applied to architectural patterns that do not depend upon point-to-point communication, or rigid API signatures. That’s a lucky coincidence, because exactly such a term is needed today for a rapidly growing new paradigm: ‘Event-Driven Architecture’ (EDA). EDA not only makes no use whatsoever of point-to-point communication, in this Architecture, the Publisher doesn’t even know whether or not there is a Subscriber(s); the Publisher has no chance whatsoever of guessing at the particular API signature that might be used for the (event-triggered) API calls that could follow on the Subscriber systems (each of which might support different API versions). For those who claimed in the past that API-versioning is a difficult problem to coordinate in the tightly-bound point-to-point communication paths of SOA – and far more so in the (tech-savvy) world of microservices – I suspect that tears may already be beginning to form when they consider the far greater API-versioning complexity – across disparate, unknown Subscriber systems – now appearing in the new world of Event-Driven Architectures.
Fortunately, in ERP-centric contexts, microservices never made sense; there is not at all the same need for Continuous Integration/Continuous Delivery, so the added complexity never made sense – microservices apparently don’t even make sense for the far more complex solutions needed by Uber today. Conversely, in this newly dawning era of EDA, it is necessary to co-opt and claim ownership of the recently coined term – ‘Macroservices’ – to describe the services of those decoupled and distributed architectures that absolutely cannot be founded upon rigid API signatures (and which as such represent the antithesis of SOA services).
Like SOA, (well-sized) Macroservices should typically be at Entity-Level: eg SalesOrder (.Create/.Change/.Delete); this is exactly where the ‘Macro’ becomes important. If these new services are to pass the ACID test, in the example just given, the SalesOrder must be either fully Created/Changed/Deleted (in the same LUW), or left completely unchanged (at which point in time the Entity must again be unlocked by its host) – compare this to microservices. As all Macroservices will be asynchronous, it is also true that all exposed entities should be resident on a single node: if an Entity Diagram suggests that the same Entity Type is hosted across multiple systems, you have a problem – not necessarily the case with synchronous-SOA. Such a ‘Macroservices’ pattern should therefore also lead to greater consolidation of back-end systems.
As already stated, the Macroservices pattern will need to be ‘Version-Flexible’. That’s worrying, because anyone that looks at the state of today’s public event schemas will immediately recognize that we are already headed for chaos. Below is an example event payload using the very latest ‘cloudevents’ schema (although it appears that every vendor makes exactly the same mistake today):
What you will hopefully notice, is that every event payload is (currently) tied to a specific ‘payload version’; and you can probably guess what would happen if multiple – unknown and unknowable – Subscribers don’t all support the same payload version at the same moment in time? Coordination chaos. Rather than just pointing out future problems, I shall instead propose a simple solution to accommodate the needed Macroservice ‘Version-Flexibility’; a solution not available to the Interface-rigid SOA and microservice patterns. I call it ‘Version-Stacking’, although you are free to call it whatever you like. Using this new pattern, event payloads will be ‘Version-Stacked’, and it will be for the Subscriber(s) alone to decide upon their – version-specific – reaction to each individual Event they receive: Hello CI/CD.
Here’s a re-worked example of the earlier cloudevents payload:
In this Version-Stacking example, we see the Event Payload attribute "makeAndModel" of version ‘1.0’ split into two new attributes in version ‘1.1’: "make" and "model". It is of course for each individual Subscriber to perform the necessary ‘folding’ of received events in line with the payload version it currently supports: in the world of EDA, Subscribers manage themselves. In version ‘1.2’, we see the new attributes "recommendedPrice" and "standardColor" have been added to the Payload. These become immediately available to any Subscriber that chooses to support version ‘1.2’; all other Subscribers will simply ignore these attributes.