Agile coding in enterprise IT: Code small and local

 

Microservices: The resurgence of SOA principles and an alternative to the monolith

Big SOA was overkill. In its place, a more agile form of services is taking hold.

 

By Galen Gruman and Alan Morrison

Moving away from the monolith

Companies such as Netflix, Gilt, PayPal, and Condé Nast are known for their ability to scale high-volume websites. Yet even they have recently performed major surgery on their systems. Their older, more monolithic architectures would not allow them to add new or change old functionality rapidly enough. So they’re now adopting a more modular and loosely coupled approach based on microservices architecture (MSA). Their goal is to eliminate dependencies and enable quick testing and deployment of code changes. Greater modularity, loose coupling, and reduced dependencies all hold promise in simplifying the integration task.

If MSA had a T-shirt, it would read: “Code small. Code local.”

Early signs indicate this approach to code management and deployment is helping companies become more responsive to shifting customer demands. Yet adopters might encounter a challenge when adjusting the traditional software development mindset to the MSA way—a less elegant, less comprehensive but more nimble approach. PwC believes MSA is worth considering as a complement to traditional methods when speed and flexibility are paramount—typically in web-facing and mobile apps.

Microservices also provide the services layer in what PwC views as an emerging cloud-inspired enterprise integration fabric, which companies are starting to adopt for greater business model agility.

Why microservices?

Greater modularity, loose coupling, and reduced dependencies all hold promise in simplifying the integration task.

In the software development community, it is an article of faith that apps should be written with standard application programming interfaces (APIs), using common services when possible, and managed through one or more orchestration technologies. Often, there’s a superstructure of middleware, integration methods, and management tools. That’s great for software designed to handle complex tasks for long-term, core enterprise functions—it’s how transaction systems and other systems of record need to be designed.

But these methods hinder what Silicon Valley companies call web-scale development: software that must evolve quickly, whose functionality is subject to change or obsolescence in a couple of years—even months—and where the level of effort must fit a compressed and reactive schedule. It’s more like web page design than developing traditional enterprise software.

Dependencies from a developer’s perspective

Dependencies from a developer’s perspective

Some of the leading web properties use MSA because it comes from a mindset similar to other technologies and development approaches popular in web-scale companies: agile software development, DevOps, and the use of Node.js and Not only SQL (NoSQL). These approaches all strive for simplicity, tight scope, and the ability to take action without calling an all-hands meeting or working through a tedious change management process. Managing code in the MSA context is often ad hoc and something one developer or a small team can handle without complex superstructure and management. In practice, the actual code in any specific module is quite small—a few dozen lines, typically—is designed to address a narrow function, and can be conceived and managed by one person or a small group.

It is important to understand that MSA is still evolving and unproven over the long term. But like the now common agile methods, Node.js coding framework, and NoSQL data management approaches before it, MSA is an experiment many hope will prove to be a strong arrow in software development quivers.

MSA: A think-small approach for rapid development

Simply put, MSA breaks an application into very small components that perform discrete functions, and no more. The definition of “very small” is inexact, but think of functional calls or low-level library modules, not applets or complete services. For example, a microservice could be an address-based or geolocation-based zip-code lookup, not a full mapping module.

The fine-grained, stateless, self-contained nature of microservices creates decoupling between different parts of a code base and is what makes them easy to update, replace, remove, or augment.

In MSA, you want simple parts with clean, messaging-style interfaces; the less elaborate the better. And you don’t want elaborate middleware, service buses, or other orchestration brokers, but rather simpler messaging systems such as Apache Kafka.

MSA proponents tend to code in web-oriented languages such as Node.js that favor small components with direct interfaces, and in functional languages like Scala or the Clojure Lisp library that favor “immutable” approaches to data and functions, says Richard Rodger, a Node.js expert and founder of nearForm, a development consultancy.

This fine-grained approach lets you update, add, replace, or remove services—in short, to integrate code changes— from your application easily, with minimal effect on anything else. For example, you could change the zip-code lookup to a UK postal-code lookup by changing or adding a microservice. Or you could change the communication protocol from HTTP to AMQP, the emerging standard associated with RabbitMQ. Or you could pull data from a NoSQL database like MongoDB at one stage of an application’s lifecycle and from a relational product like MySQL at another. In each case, you would change or add a service.

MSA lets you move from quick-and-dirty to quick-and-clean changes to applications or their components that are able to function by themselves. You would use other techniques—conventional service-oriented architecture (SOA), service brokers, and platform as a service (PaaS)—to handle federated application requirements. In other words, MSA is one technique among many that you might use in any application.

The fine-grained, stateless, self-contained nature of microservices creates decoupling between different parts of a code base and is what makes them easy to update, replace, remove, or augment. Rather than rewrite a module for a new capability or version and then coordinate the propagation of changes the rewrite causes across a monolithic code base, you add a microservice. Other services that want this new functionality can choose to direct their messages to this new service, but the old service remains for parts of the code you want to leave alone. That’s a significant difference from the way traditional enterprise software development works.

Evolution of services orientation

Evolution of services orientation

Thinking the MSA way: Minimalism is a must

The MSA approach is the opposite of the traditional “let’s scope out all the possibilities and design in the framework, APIs, and data structures to handle them all so the application is complete.”

Issue overview: Integration fabric

Think of MSA as almost-plug-and-play in-app integration of discrete services both local and external. These services are expected to change, and some eventually will become disposable. When services have a small focus, they become simple to develop, understand, manage, and integrate. They do only what’s necessary, and they can be removed or ignored when no longer needed.

Mobile apps and web apps are natural venues for MSA.

There’s an important benefit to this minimalist approach, says Gregg Caines, a freelance web developer and co-author of programming books: “When a package doesn’t do more than is absolutely necessary, it’s easy to understand and to integrate into other applications.” In many ways, MSA is a return to some of the original SOA principles of independence and composition—without the complexity and superstructure that become common when SOA is used to implement enterprise software.

The use of multiple, specific services with short lifetimes might sound sloppy, but remember that MSA is for applications, or their components, that are likely to change frequently. It makes no sense to design and develop software over an 18-month process to accommodate all possible use cases when those use cases can change unexpectedly and the life span of code modules might be less than 18 months.

The pace at which new code creation and changes happen in mobile applications and websites simply doesn’t support the traditional application development model. In such cases, the code is likely to change  due to rapidly evolving social media services, or because it runs in iOS, Android, or some other environment where new capabilities are available annually, or because it needs to search a frequently updated product inventory.

For such mutable activities, you want to avoid—not build in—legacy management requirements. You live with what nearForm’s Rodger considers a form of technical debt, because it is an easier price to pay for functional flexibility than a full-blown architecture that tries to anticipate all needs. It’s the difference between a two-week update and a two-year project.

Traditional SOA versus microservices

  Traditional SOA Microservices
Messaging type Smart, but dependency-laden ESB Dumb, fast messaging (as with Apache Kafka)
Programming style Imperative model Reactive actor programming model that echoes agent-based systems
Lines of code per service Hundreds or thousands of lines of code 100 or fewer lines of code
State Stateful Stateless
Messaging type Synchronous: wait to connect Asynchronous: publish and subscribe
Databases Large relational databases NoSQL or micro-SQL databases blended with conventional databases
Code type Procedural Functional
Means of evolution Each big service evolves Each small service is immutable and can be abandoned or ignored
Means of systemic change Modify the monolith Create a new service
Means of scaling Optimize the monolith Add more powerful services and cluster by activity
System-level awareness Less aware and event driven More aware and event driven

This mentality is different from that required in traditional enterprise software, which assumes complex, multivariate systems are being integrated, requiring many-to-many interactions that demand some sort of intelligent interpretation and complex framework. You invest a lot up front to create a platform, framework, and architecture that can handle a wide range of needs that might be extensive but change only at the edges.

MSA assumes you’re building for the short term; that the needs, opportunities, and context will change; and that you will handle them as they occur. That’s why a small team of developers familiar with their own microservices are the services’ primary users. And the clean, easily understood nature lets developers even more quickly add, remove, update, and replace their services and better ensure interoperation with other services.

In MSA, governance, data architecture, and the microservices are decentralized, which minimizes the dependencies. As a result of this independence, you can use the right language for the microservice in question, as well as the right database or other related service, rather than use a single language or back-end service to accomplish all your application’s needs, says David Morgantini, a developer at ThoughtWorks.

Where MSA makes sense

MSA is most appropriate for applications whose functions may need to change frequently; that may need to run on multiple, changing platforms whose local services and capabilities differ; or whose life spans are not long enough to warrant a heavily architected framework. MSA is great for disposable services.

Mobile apps and web apps are natural venues for MSA. But whatever platform the application runs on, some key attributes favor MSA:

  • Fast is more important than elegant.
  • Change in the application’s functionality and usage is frequent.
  • Change occurs at different rates within the application, so functional isolation and simple integration are more important than module cohesiveness.
  • Functionality is easily separated into simple, isolatable components.

For example, an app that draws data from social networks might use separate microservices for each network’s data extraction and data normalization. As social networks wax and wane in popularity, they can be added to the app without changing anything else. And as APIs evolve, the app can support several versions concurrently but independently.

Microservices can make media distribution platforms, for example, easier to update and faster than before, says Adrian Cockcroft, a technology fellow at Battery Ventures, a venture capital firm.The key is to separate concerns along these dimensions:

  • Each single-function microservice has one action.
  • A small set of data and UI elements is involved.
  • One developer, or a small team, independently produces a microservice.
  • Each microservice is its own build, to avoid trunk conflict.
  • The business logic is stateless.
  • The data access layer is statefully cached.
  • New functions are added swiftly, but old ones are retired slowly.1

These dimensions create the independence needed for the microservices to achieve the goals of fast development and easy integration of discrete services limited in scope.

MSA is not entirely without structure. There is a discipline and framework for developing and managing code the MSA way, says nearForm’s Rodger. The more experienced a team is with other methods—such as agile development and DevOps—that rely on small, focused, individually responsible approaches, the easier it is to learn to use MSA. It does require a certain groupthink. The danger of approaching MSA without such a culture or operational framework is the chaos of individual developers acting without regard to each other.

In MSA, integration is the problem, not the solution

Many enterprise developers shake their heads and ask how microservices can possibly integrate with other microservices and with other applications, data sets, and services. MSA sounds like an integration nightmare, a morass of individual connections causing a rat’s nest that looks like spaghetti code.

Ironically, integration is almost a byproduct of MSA, because the functionality, data, and interface aspects are so constrained in number and role. (Rodger says Node.js developers will understand this implicit integration, which is a principle of the language.) In other words, your integration connections are local, so you’re building more of a chain than a web of connections.

When you have fine-grained components, you do have more integration points. Wouldn’t that make the development more difficult and changes within the application more likely to cause breakage? Not necessarily, but it is a risk, says Morgantini. They key is to create small teams focused on business-relevant tasks and to conceive of the microservices they create as neighbors living together in a small neighborhood, so the relationships are easily apparent and proximate. In this model, an application can be viewed as a city of neighborhoods assigned to specific business functions, with each neighborhood composedof microservices. You might have “planned community” neighborhoods made from coarser-grained services or even monolithic modules that interact with more organic MSA-style neighborhoods.2

It’s important to remember that by keeping services specific, there’s little to integrate. You typically deal with a handful of data, so rather than work through a complex API, you directly pull the specific data you want in a RESTful way. You keep your own state, again to reduce dependencies. You bind data and functions late for the same reasons.

Integration is a problem MSA tries to avoid by reducing dependencies and keeping them local. If you need complex integration, you shouldn’t use MSA for that part of your software development. Instead, use MSA where broad integration is not a key need.

Conclusion

MSA is not a cure-all, nor is it meant to be the only or even dominant approach for developing applications. But it’s an emerging approach  that bucks the trend of elaborate, elegant, complete frameworks where that doesn’t work well. Sometimes, doing just what you need to do is a better answer than figuring out all the things you might need and constructing an environment to handle it all. MSA serves the “do just what you need to do” scenario.

This approach has proven effective in contexts already familiar with agile development, DevOps, and loosely coupled, event-driven technologies such as Node.js. MSA applies the same mentality to the code itself, which may be why early adopters are those who are using the other techniques and technologies. They already have an innate culture that makes it easier to think and act in the MSA way.

Any enterprise looking to serve users and partners via the web, mobile, and other fast-evolving venues should explore MSA.

1. Adrian Cockcroft, “Migrating to Microservices,” (presentation, QCon London, March 6, 2014), http://qconlondon.com/london-2014/presentation/Migrating%20to%20Microservices, accessed May 12, 2014.

2. David Morgantini, “Micro-services—Why shouldn’t you use micro-services?” Dare to dream (blog), August 27, 2013, http://davidmorgantini.blogspot.com/2013/08/micro-services-why-shouldnt-you-use.html, accessed May 12, 2014.