When building loosely coupled cloud apps, microservices are today’s preferred pattern. James Lewis and Martin Fowler wrote the seminal introduction, and the concept has been disseminated widely since. While Lewis and Fowler’s entire post is a fantastic read, one specific requirement stands out: microservices must favor “smart endpoints and dumb pipes.”
Essentially, the smarts should be in the app components, and the communication between those components must be as simple as possible. Without that requirement, architectures will bloat and become monolithic. When asked, “How does your PaaS support microservices?” most enterprise PaaS vendors offer little more than deployment agility. While agility is an important piece of the puzzle, application bootstrap policies directly support both the smart-endpoints / dumb-pipes vision and the implementation of microservices.
With smart pipes, the danger of increased complexity is high. Smart pipes often lead to a monolithic architecture. Lewis and Fowler, in a sidebar to their write-up, state that they have seen “many botched implementations of service orientation” including the tendency to hide complexity away in enterprise service buses (ESBs).
Why is that bad? Smart pipes create an unintended tight coupling between endpoints and the pipes themselves. That is, an application becomes dependent on expectations in the communications protocols for proper function, and the general systems behavior is now defined in the pipes. A system leveraging a smart ESB ends up more often than not functionally dependent on that ESB (carrying around an ESB is quite the dependency!). As soon as pipes start to become too smart, they force monolithic creep. What’s worse is that endpoints may become co-dependent through the smart pipe with each expecting an implicit finessing of RPC and payloads to work properly.
Unfortunately, the temptation to make pipes smarter is high. In the names of abstraction, architecture standardization, and re-usability, adding logic to communication pathways between services is commonplace. What starts as a microservices architecture quickly bloats to a monolithic architecture. However, a system does need a common, orthogonal offering to keep redundant functionality low.
Does it make sense to embed authentication logic into every endpoint or to script monitoring hooks into a web service or to write code for any other non-business function in a microservice? It does, if it’s the only way to keep “endpoints smart and pipes dumb.” Fortunately, that is not the only option.
Previous generations of developers introduced techniques like aspect-oriented programming to deal with the issue of separating cross-cutting concerns from application logic for better code modularity. Interestingly, similar techniques can be leveraged in cloud-computing and PaaS-based microservices. Jon Norton, a software engineer here at Apprenda, explains an Apprenda feature called “application bootstrap policies” that allows IT operators to instrument libraries and modify any guest application.
Interested in mixing APM into an app deployment? Write a bootstrap policy. Want to modify the IL or Java bytecode of any guest app to introduce some fancy byte-level instrumentation? Write a bootstrap policy.
Bootstrap policies are a modular vehicle for mixing cross-cutting concerns into endpoints on a PaaS. The power in this is huge and should not be underestimated. Endpoints can be smart while pipes remain dumb. Most importantly, bootstrap policies support Apprenda’s commitment that all developers avoid writing unnecessary code.