Any “modern” IT organization is a collection of dozens, if not hundreds, of information systems, painstakingly built over the course of decades.These systems are brittle, heavily integrated with each other, require aging skills to work on them and follow a release cycle that is just too slow to support the innovation process.
Even the imminent threat of a Unicorn would not be enough to find the resources to rebuild them or deal with the political minefield of realigning their ownership along key innovation lines.
There is literally no other option than putting some lipstick on the pig (aka APIs). Some have suggested that there will be light at the end of these shiny new pipes, but who could think that you’ll ever be in the position to “strangle” even one core product or support systems? My best guess is that applying the strangler pattern at scale will most likely strangle your organization, not your systems:
If you don’t completely kill off the old system, you’ll end up in a worse mess because your system now has two ways of doing everything with an awkward interface between the two. Later, another wave of developers will probably decide to strangle what’s there, writing yet another strangler application, and again a lack of will might leave the system in an even worse state, with three ways of doing things.
With that in mind, you might consider the argument that the structure of your underlying information systems does not really matter (that much), and, to innovate, it is more effective to focus your energy on being able to stand up applications quickly and sustainably. That’s actually, in essence, what unicorns are doing:
Instead of a relying on a single API with a flat set of endpoints, Etsy created a two-layer API using meta-endpoints. Similar to a pattern used by Netflix and eBay’s ql.io, each of Etsy’s meta-endpoints aggregates several other endpoints. This enables server-side composition of low-level, general purpose resources into device- or view-specific resources.
When Subbu started ql.io, he noted that no matter how your information system is structured:
- Most use cases require accessing multiple APIs – which involves making several network round trips.
- Often those API requests have interdependencies – which requires programmatic orchestration of HTTP requests – making some requests in parallel and some in sequence to satisfy the dependencies and yet keep the overall latency low.
- APIs are not always consistent as they evolve based on the API producers’ needs – which makes code noisier in order to normalize inconsistencies.
And for all these reasons, as we have seen in part 1 of this series, Systems of Record need to expose microservices, i.e. integration points, while one need a proper service layer manages the consistency of the information system and the APIs deliver activity centric interfaces to the applications:
Anyone would probably choke a bit at the number of end-points between microservices, services and APIs, but once an organization jumps on the innovation mill, endpoints tend to sprawl out of control. The EDA camp would probably claim that events are better, but I sincerely doubt it, events would sprawl just as well, and the reality is that you still need interfaces to consume these events. The fun starts when you start emitting events in response to other events, and I am not even talking about exception handling.
There are however two things you can have control over:
- Limit the number of API variants (per application and per channel)
- Make it easy to build build APIs from Services
One way to limit the number of API variants is to use a functional front-end architecture. Functional Front-End Architectures promote a model where the view is expressed as a function of the model: the view and the view components publish events and wait for either a new view to render or the view component properties to update. The view itself no longer calls a single API, which limits the number of variants that would be required when APIs are strictly bound views. Frameworks like ELM, React+Redux, MobX, Cycle.js and the SAM Pattern (State-Action-Model) all promote a Front-End Architecture where the view no longer need a one-to-one binding to the APIs.
But the SAM pattern goes one step further, it allows aligning (some) actions with APIs and (parts of) the Model with Services, enabling some APIs/Actions to be truly reusable across applications as well reusing some of the consistency logic. It even supports running the state function in the server to handle complex device specific scenarios when it’s not sensible to return the new application state to the client. SAM no longer requires a rigid delineation between Front-End and Back-End materialized by a sprawling API layer. On the contrary, SAM fosters a natural alignment between the Front-End and Back-End business logic, without compromising reusability.
We’ll explore the last point “making it easy to build APIs from services” in part 3 of this series.