Microservices and the 12 Factor App

Gabriela Melo
5 min readJun 15, 2018

In our current cloud-based scenario, where we need our applications to quickly and easily scale, a few changes are required in the way that we develop them, as compared to how it used to be. There are some microservices best practices, methodologies and guidelines that help us in developing these kinds of cloud-based scalable applications, and I will try to highlight the most relevant aspects of these guidelines here. I used a few references for this article, which are listed at the end.

The motivation behind the writing of this article was that I recently studied these concepts, in order to be able to build more scalable and resilient applications, and thought this might be a good way of summarizing my learnings, with hopes that it might help others as well.

Microservices are a way of splitting your application, which would traditionally be developed as a single monolith into multiple services.

The main advantages of doing this are:

  • Each service is small and independent;
  • The services are built around business requirements, which facilitates the attribution of services across teams;
  • Each service has an automated and independent deploy, which makes it easier for having continuous integration and delivery, and also results in quicker deploys, making it feasible to have zero downtime deploys;
  • You are able to use different languages, databases, and tools for each service;
  • You are able to scale vertically (only scale what needs to be scaled, and kill instances for services that do not need that many instances on demand);
  • Productivity does not drop as much with the increase in code base complexity as it would in monolithic applications development.

There are controversies, however, on whether you should already start off with a microservice architecture or start off with a monolith and then start breaking it into services as your application starts to grow and you start to have a better understanding of it — there are arguments supporting both approaches.

Some things need to change or be added due to this architecture. The microservices architecture brings up the necessity of the services communicating with each other. This might be done either through HTTP requests or through a messaging system, for asynchronous messages.

You will want to facilitate the process of clients talking to your application, so it might be necessary to implement an API gateway, which takes care of all incoming traffic to your application and redirects the requests to the responsible services.

Another particularity of cloud-based microservices is that, as instances can be added or killed, you need a way of keeping track of this. There are different ways of accomplishing this, but some of them involve service registry and service discovery systems.

A collection of guidelines to help to build good microservice-based applications is the Twelve-Factor app. It is a collection of 12 tips for the development of horizontally scalable applications. Another work, available in a book called "Beyond the Twelve-Factor App" (link below), expanded these into 15 factors, which are:

  1. One codebase, one application

Each codebase belongs to one application and the codebase is the same across all execution environments (development, staging, production, etc), although they can be running on different versions.

2. API first

What you are building is an API, that will be consumed by other clients and services. Therefore, the API is the most important interface for your service and should be well documented.

3. Dependency management

You should use a dependency management system, and isolate your application dependencies. This gives you the certainty that your application is always being run with the same dependencies, no matter the environment in which it is running.

4. Design, build, release, and run

These states are strictly separated from each other.

5. Configuration, credentials, and code

All configuration and credentials are stored as environment variables. This removes any vulnerability that could come from exposing sensitive credentials in your code and also allows you to control all configuration from the command line, making it possible to automate deploys.

6. Logs

Logs should be output to stdout and stderr and you should use some external tool for handling logs.

7. Disposability

All instances running services must be able to initiate execution quickly and stop gracefully, as they can be started or killed at any moment (either by some external issue or due to changes in demand).

8. Backing services

All backing services are treated as bound resources. Each service declares the services that it utilizes and the connections between the service and the resources are done by external configurations.

9. Environment parity

The application should at all times work on all environments ( staging, production, etc ) and environments should be as similar as possible. The services should use the same types of resources across all environments. This reduces the time between code check-in and production deploy.

10. Administrative processes

These should run as one-off processes, in an environment identical to the one in which the application is running.

11. Port binding

Applications should always expose their services through port binding, and there should always be a 1:1 relation between applications and app servers.

12. Stateless processes

Given that processes can disappear at any moment (once again due to the transient nature of instances), all processes should be stateless. All long-term storage of data should happen on external services. Also, all processes that need to communicate with each other need to do so through external services.

13. Concurrency

Applications need to be able to scale horizontally, so there might be more than one instance of the service running at a time.

14. Telemetry

This is due to the need for monitoring your applications even though they are not physically near you, as they are running on the cloud, on ephemeral instances.

15. Authentication and authorization

This might seem obvious, but it is here as a reminder, given that each service and each part of your application need to have authentication and authorization concerns.

The main ideas behind these factors is the need for configuration automation, the maximization of the portability between execution environments, the suitability of this kind of development for the cloud, the decrease in difference between development and production environment, making it easier for continuous integration and delivery to happen, and the ability of scaling without the need for significant changes or refactors of code.

Lastly, I would like to mention that DevOps concepts and methodologies can bring very good results when working with a microservice architecture. It is a way of making it possible to have the speed and iterability that help for having good end results with a microservices architecture.

--

--