An API-first approach for cloud-native app development
Kevin Hoffman adds the concept of API first to the original 12 factors of app development.
In Beyond the Twelve-Factor App, I present a new set of guidelines that builds on Heroku’s original 12 factors and reflects today’s best practices for building cloud-native applications. I have changed the order of some to indicate a deliberate sense of priority, and added factors such as telemetry, security, and the concept of “API first” that should be considerations for any application that will be running in the cloud. These new 15-factor guidelines are:
- One codebase, one application
- API first
- Dependency management
- Design, build, release, and run
- Configuration, credentials, and code
- Logs
- Disposability
- Backing services
- Environment parity
- Administrative processes
- Port binding
- Stateless processes
- Concurrency
- Telemetry
- Authentication and authorization
Regardless of the type of application you’re developing, chances are if you’re developing it for the cloud, then your ultimate goal is to have that application be a participant in an ecosystem of services. Let’s take a look at the concept of API first, and why I’ve added it to this list.
Why API first?
Assume for a moment that you have fully embraced the original 12 factors for app development. You are building cloud-native applications, and after code gets checked in to your repository, tests are automatically run, and you have release candidates running in a lab environment within minutes. The world is a beautiful place, and your test environment is populated by rainbows and unicorns.
Now another team in your organization starts building services with which your code interacts. Then, another team sees how much fun you’re all having, and they get on board and bring their services. Soon you have multiple teams all building services with horizontal dependencies[1] that are all on a different release cadence.
What can happen if no discipline is applied to this is a nightmare of integration failures. To avoid these integration failures, and to formally recognize your API as a first-class artifact of the development process, API first gives teams the ability to work against each other’s public contracts without interfering with internal development processes.
Even if you’re not planning on building a service as part of a larger ecosystem, the discipline of starting all of your development at the API level still pays enough dividends to make it worth your time.
Building services API first
These days, the concept of mobile first is gaining a lot of traction. It refers to the notion that from the very beginning of your project, everything you do revolves around the idea that what you are building is a product to be consumed by mobile devices. Similarly, API first means that what you are building is an API to be consumed by client applications and services.
Cloud native is more than just a list of rules or guidelines. It is a philosophy and, for some of us, a way of life. As such, there are guidelines for cloud native that might not necessarily map to specific physical requirements imposed by the cloud but that are vitally important to the habits of people and organizations building modern applications that will be ready for future changes to the cloud landscape.
Built into every decision you make and every line of code you write is the notion that every functional requirement of your application will be met through the consumption of an API. Even a user interface, be it web or mobile, is really nothing more than a consumer of an API.
By designing your API first, you are able to facilitate discussion with your stakeholders (your internal team, customers, or possibly other teams within your organization who want to consume your API) well before you might have coded yourself past the point of no return. This collaboration then allows you to build user stories, mock your API, and generate documentation that can be used to further socialize the intent and functionality of the service you’re building.
All of this can be done to vet (and test!) your direction and plans without investing too much in the plumbing that supports a given API.
These days, you’ll find that there are myriad tools and standards to support API-first development. There is a standard format for API specification that uses a markdown-like syntax called API Blueprint. This format is far more human readable than JSON (or WSDL, a relic that belongs in a museum) and can be used by code to generate documentation and even server mocks, which are invaluable in testing service ecosystems. Tool suites like Apiary provide things like GitHub integration and server mocks. If someone wants to build a client to your API, all you have to do is give her a link to your application on Apiary, where she can read your API Blueprint, see example code for consuming your service, and even execute requests against a running server mock.
In other words, there is absolutely no excuse for claiming that API first is a difficult or unsupported path. This is a pattern that can be applied to non-cloud software development, but it is particularly well suited to cloud development in its ability to allow rapid prototyping, support a services ecosystem, and facilitate the automated deployment testing and continuous delivery pipelines that are some of the hallmarks of modern cloud-native application development.
This pattern is an extension of the contract-first development pattern, where developers concentrate on building the edges or seams of their application first. With the integration points tested continuously via CI servers[2], teams can work on their own services and still maintain reasonable assurances that everything will work together properly.
API first frees organizations from the waterfall, deliberately-engineered system that follows a pre-planned orchestration pattern, and allows products to evolve into organic, self-organizing ecosystems that can grow to handle new and unforeseen demands.
If you’ve built a monolith, or even an ecosystem of monoliths, that all interact in tightly coupled ways, then your ability to adapt to new needs or create new consumers of existing functionality is hindered. On the other hand, if you adopt the mentality that all applications are just backing services, and that they should be designed API first, then your system is free to grow, adapt to new load and demand, and accommodate new consumers of existing services without having to stop the world to re-architect yet another closed system.
Live, eat, and breathe the API-first[3] lifestyle, and your investment will pay off exponentially.