Skip to main content

Twelve Factor app development for Microservices

The Twelve (12) Factor app methodology is a list of principles for any Web Application or Software as a Service, and it is especially useful for microservices. This methodology can be applied to apps written in any programming language that use any combination of backing services(database, queue, memory cache, etc).


1. Code Base 

- There should a dedicated code base per app.

There should be a dedicated code base for each App, and multiple code bases can not use the same code base. If any code base is required by more than one application, separate that code into a separate repository, and inject that using dependency manager into the dependent apps. The same code base can be used to deploy the application to different environments like develop, stage, and production.

2.  Dependencies 

- Explicitly declare and isolate dependencies.

All the dependencies need to be explicitly declared, and should be available as part of the build process. The should not depend on any implicit dependencies, as they may or may not exist in other operating systems or environments, and may cause build, or deployment failures.

e.g., for a Maven project, if a third party library is required as part of the build process, that should be explicitly declared as part of dependency management, and the app should not expect the library to be available on the operating system environment.

3. Config 

- Store config in the environment, separate code and config.

Configuration information about resources such as payment gateway url, data base connection details etc., need to be stored as part of configuration files, and should be clearly separated out from the code, as code stays the same in dev, stage, and prod environments, only the configuration differs among the environments. Where as the configuration that stays the same among the environments such as how modules are connected is done best in the code.

The configuration should be available as environment variables, so that changing the environment variable loads the correct configuration details from the configuration files.

4. Backing Services 

- Treat backing services as attached resources.

A backing service a service that the app uses as part of it's normal operation like database, third party web service, message queue. The app makes no distinction between local and remote third party resources. In case of any swap is required from local service to remote service, the only thing that needs to be changed is the configuration files and no code should be changed for this. Each distinct backing service is a resource, eg., If there are two database resources and one message queue, they are three separate resources.

5. Build, Release, and Run 

- Strictly separate build and deploy stages.

The app has three phases called build, release, and run. 

Build - Builds the app, fetches different artifacts, compiles binaries, and assets.
Release - This phase fetches the build created from the build phase, and adds the configuration information, and makes the app ready for deployment.
Run - This phase runs the app in the target environment.

The app uses the clear separation between build, release, and run phases.

Builds can be  initiated by developer action like code check-in, or manual build. The deploy/run can be done many times without a build being required eg., when the application server is restarted or machine is rebooted.

Each release Id should be immutable, any change should generate a new release Id number.


6. Processes 

- Execute the App as one or more stateless processes.

The app is executed as a single or multiple processes in the execution environment. It runs as single process in the dev environment, where as in production environment it runs as multiple processes and in different machines.

Twelve factor processes are stateless, and share nothing. If any data needs to be persisted that should be persisted using a data store like Oracle, MySql, MongoDB.


7. Port Binding 

- Export services via port binding.

The App runs in a web container like Tomcat or WebLogic. The app should be available and tied to a port so that the app can be accessed as localhost:8080 on local development environment, and in production environment a proxy can do the routing from the public facing domain name to the application on this port.

8. Concurrency 

- Scale out via the process model.

In twelve-factor app processes are first class citizens. Developers can architect their processes to handle different type of work types e.g., http workload can be handled by web process and background job can be handled by a worker process.  The share-nothing, able to horizontally partition nature of twelve-factor app processes means that adding more concurrency is a simple and reliable operation.

9. Disposability 

- Maximize robustness with fast startup, and graceful shutdown.

The twelve-factor apps are disposable meaning that they can be started or stopped at a moment's notice.This facilitates fast elastic scaling, rapid deployment of code or config changes, and robustness of production deploys.

The startup time should be minimal, and the shutdown should be graceful, any shutdown signal should take care of the appropriate house clean up work like closing connections, and releasing locks, resources, or put the messages to retry queue etc., before the shutdown is completed. This can be achieved by wrapping the code with in a transaction boundary.

10. Dev/Prod Parity 

- Keep development, staging, and production as similar as possible.

The twelve-factor app is designed for continuous deployment by keeping the gap between development and production small. The developer writes the code, and have it deployed to production within hours or even in minutes.

The backing services such as MessageQueue, database need to be similar between development and production environments, so that the differences between environments are minimized. Provisioning tools such as Chef and Puppet combined with light-weight virtual environments such as Docker and Vagrant allow developers to use development environments which are close to production environments. The cost of installing and using these systems is low compared to the benefit of dev/prod parity and continuous deployment.

11. Logs 

- Treat logs as event streams.

Logs provide the visibility into the behavior of a running app.  The app should not be concerned about routing or storing the logs. The logs can be written to console in development environment, where as in stage, and production environments use a log aggregator to send the logs to a log indexing system such as sumo logic or splunk, where the logs can be analyzed for any specific events for a duration, and alerts can be configured based on the app specific requirements.

12. Admin Processes 

- Run admin/management tasks as one off process.

App needs to allow admin tasks to be executed from the same environment as the application. Admin scripts needs to be bundled as part of the application code or configuration to avoid synchronization issues in different environments.

Comments