What is the twelve-factor app methodology?
The twelve-factor app is a methodology used to build software-as-a-service apps. It serves as a best practice guide to create apps with low time and cost for new developers joining a project and to make them scale up without significant changes to tooling or architecture.
The twelve-factor methodology can be applied to apps written in any programming language. These are the 12 factors to consider:
- Backing services
- Build, release and run
- Port binding
- Dev/Prod parity
- Admin Processes
1 - Codebase
The codebase terms refer to the version control system used to keep track of any changes to the application. Git or Subversion are common version control tools. In 12-factor apps, there should be a one to one correlation between the codebase and the app.
If there are multiple codebases, then there is not a single application but a distributed system. In that scenario, each codebase is treated as an independent component and they should comply with 12-factor app.
It is considered a violation for multiple applications to share a single codebase. To avoid that, we can externalise shared code into dependency libraries.
The deployment of an application is going target its particular codebase.
2 - Dependencies
Software dependencies are pieces of code that can be reused on multiple apps by publishing them as packages or libraries. In 12-Factor apps, all dependencies must be declared into a manifest and installed using a package manager.
An application must not rely on implicit existence of system packages but, instead, use the package manager to reference them. That prevents cross device issues, 'It works on my machine' error, and also ensures the app has all dependencies it needs to run on every type of system.
In addition to that, 12-Factor apps also use a dependency isolation tool during execution to ensure that no implicit dependencies 'leak in' from the surrounding system. For front-end web applications that can be achieved using a Docker container.
3 - Configurations
The app configs are values that are susceptible to change between environment and stages. We must separate those values from the code logic as the codebase does not change between deployments.
A config file is intended to store values such as: Connection strings to databases, credentials for external services like third party APIs or environment related settings such as the hostname of the application.
An application must never store those types of values in their code and worst add them to its version control. That is a violation of the 12-Factor app methodology. All apps following 12-factor should store the config values on environment variables and be language-agnostic.
The group of configs is also important. It is not recommended to group config variables as environment names
prod as this approach does not escalate smoothly. In a twelve-factor apps, config are like granular controls been fully orthogonal to other
env vars. The grouping should represent their independent use.
4 - Backing Services
Applications usually rely on external service in order to perform their actions. Examples of backing services are databases, caches or queues.
12-Factor apps tread all service as attached resources and do not make a distinction between local and third party services. For an application, all attached resources are going to be accessed via the details stored in the config.
Because backing services vary between deployments, there shouldn’t be hardcoded settings of external services on the application’s code.
5 - Build, release and run
There are usually three stages to convert a codebase intro a releasable build:
- Build stage is the process of compiling the source code into an executable bundle or build files. In this process third party libraries, assets and vendor dependencies are compiled together.
- Release stage, where the bundle and the config files are combined resulting in a release which is ready for runtime execution.
- Run stage is the execution environment where the application is going to run.
12-Factor applications are based on a strict separation between stages, preventing any kind of changes into a released bundle. This approach enforces that new changes after the compilation require a new release.
6 - Processes
Apps are treated as independent running processes. The crash of an application should not take down other services.
All data used by the application must be stored on backing services such as databases. Each process on a 12-factor app is stateless and shares nothing. While many developers are used to 'sticky sessions', storing information in the session expecting the next request will be from the same service contradicts this methodology.
7 - Port Binding
Unlike some web apps that are executed inside a webserver container, a Twelve-Factor acts as a standalone service. It must be a self-contained application which means it doesn’t rely on any existing/running application server to get executed.
In a traditional setup, applications assume web protocols such as HTTP, are always available on the environment they are deployed to.
In 12-factor methodology, applications are completely self-contained. They are required to add a web server library or similar to the core app in order to listed for requests on a defined port, whether requests are stablished via HTTP or a different protocol.
8 - Concurrency
Can be seen as a way towards the micro services architecture. The idea is to be able to scale up and out, meaning that the application should be able to rely on workers and delegate certain functionality to other apps.
For example, HTTP requests may be handled by a web process and long-running background tasks handled by a worker process.
The concept behind concurrency is to optimise CPU resources by running multiple processes on parallel threads. The 12-Factor methodology do not exclude multiplexing on individual processed (scale up) but dictates that applications must be able to span multiple processes running on multiple physical machines (scale out).
9 - Disposability
Applications that are disposable mean they can be started or stopped rapidly. An application cannot scale or recover rapidly if it cannot start rapidly and shut down gracefully.
12 factor apps should be quick to start up. Ideally they should start in less than 1 minute.
Application are graceful to shut down when they receive a terminal signal and within 10 seconds are able to release resources and clean up any connections.
When both of this principles apply to an app, we can consider this application to be resilience to failure.
10 - Environment parity
This principle states that environments where the app is deployed need to be identical or with only minor difference between them.
The most common place when this principle gets violated is at the database or container layer. If production environment is, for example, using PostgreSQL the development environment needs to also use that same manager.
Twelve-factor applications are designed for Continuous Deployment reducing the gap between environments where the application is deployed to. This principle allows to reduce time solving cross-environment issues and ensuring the app’s behaviour is the same on each deployment.
When the parity principle is used correctly, it can lead to other beneficial principles like reproducibility (scale up) or disposability (can easily be recreated).
11 - Logs
The behaviour of a running application can be reviewed thanks to its logs. Logs, which are usually stored as system files, record events that occurred while an application is running.
In 12-Factor methodology, applications do not handle the routing or storage of its output log streams. Instead, they write their streams into the standard output
stdout that is the default file descriptor where a process can write output.
12 - Admin processes
Administrative or maintenance tasks such as background one-off jobs or database migrations should be run as isolated processes.
Essentially we should not log into a production server which is handling requests and try to run a one-off job directly. The outcome of doing this may vary from using production resources from the main app to even crashing the production system.
The 12-Factor methodology states that these types of jobs need to be run as an isolated process which can be run in the same environment as the production application without affecting the main application.