The Talent500 Blog
Twelve-factor

The Twelve-Factor App: Best Practices for Cloud-Native Applications

Introduction

In the modern era, software is commonly delivered as a service: called web apps, or software-as-a-service. The twelve-factor app is a methodology for building software-as-a-service apps.

It was introduced in a seminal 2012 blog post titled “The Twelve-Factor App: Best Practices for Cloud-Native Applications” by Heroku co-founder Adam Wiggins. The methodology originated from the experiences and insights gained from deploying and operating cloud-based applications.

The main goal of the Twelve-Factor App is to provide a standardized approach for developing applications that can run in a cloud-native environment while remaining flexible, robust, and easy to manage.
The twelve-factor app methodology provides us with a set of best practices for building a modern cloud-native application that meets these requirements:

Codebase
:-One codebase is tracked in version control.
:-Multiple deployments share the same codebase.

Dependencies
:-Explicitly declare and isolate dependencies.
:-Avoid relying on system-wide packages.

Config
:-Store configuration in the environment.
:-Separate configuration from code

Backing Services
:-Treat backing services (databases, caches) as attached resources.
:-Access them via environment variables.

Build, Release, Run
:-Strictly separate build, release, and run stages.
:-Keep builds and releases immutable

Processes
:-Execute the app as stateless processes.
:-Store shared state in databases or external services

Port Binding
:-Export services via port binding.
:-Keep the app self-contained.

Concurrency
:-Scale out via the process model.
:-Enable horizontal scaling.

Disposability
:-Maximize robustness with fast startup and graceful shutdown.
:-Aim for quick startup and graceful handling of process failures.

Dev/Prod Parity
:-Keep development, staging, and production environments as similar as possible.
:-Minimize differences to reduce bugs.

Logs
:-Treat logs as event streams.
:-Stream logs to a centralized location for analysis.

Admin Processes
:-Run admin/management tasks as one-off processes.
:-Avoid mixing them with the main application code

Why Twelve-Factor App?

To understand why we need a Twelve-Factor App, first understand what happens traditionally to build an application.

Suppose you are building an application to get your idea out to the world. Traditionally you have to go through hopes and hurdles to get your idea out to the world because it will take you days, weeks, or even months to order and receive a server to host your application on. And eventually, once you get to the server to host your application. you are dependent on that server for the rest of your life.
you wrote code that could only live on that server, it could not live on other servers, and if you had to scale, you would scale resources on that server. where you even store sessions of users on the server.
if the user was in the middle of something and your server crashes, everything that user did until that point was lost and they had to do all of that all over again. your app was tied to the server for life.

But, in today’s time we are living in a world of high growth-fast startups that see user growth from zero to millions in a matter of few months.
If you are going from an idea to execution, only take as much time as you need to develop the code for it. provisioning and hosting can be achieved in a matter of hours. most cloud platforms today can provision servers and other resources in a matter of minutes. today’s platforms are expected to be up 99.99% of the time meaning there is no downtime to take down the applications.

For this  to happen your application needs to break free from the underlying infrastructure. this way you can host your application anywhere you want, be it On-premises, GCP, AWS, AZURE and that’s known as portability.

Portability means its able to run the same app on different environments without having to change the source code of the application.

This means your application needs to be portable first.
And when it comes to scaling,  in the past you had to take down your application for addition of resources to your servers and that was refers to as Vertical Scaling. Today you provision and run more servers and run more instances of your application that refers to as Horizontal Scaling.

To Summarize,
Modern applications need to be portable and such must not be tightly coupled with the underlying Infrastructure.  They should have minimal divergence when deploy between the dev, test, and prod environment to enable continuous deployment.

And must be easily scalable by spinning many instances at once and its suitable for modern cloud platforms.
In order to achieve this your application needs to be developed keeping certain principles in mind.
About a decade ago engineering from Heroku put together Twelve-Factors that need to be considered when building modern applications and these are known as Twelve-Factor apps.

Let’s dive into each of the Twelve-Factor App principles.

1. Codebase

One codebase tracked in revision control, many deploys
The first rule is about having a single code base for your application.
Suppose your application can have multiple services like order or payment instead of having all relative services in the single codebase it should have a separate codebase that achieve distribute system.

And each codebase will have to deploy on different environments like dev, stage, and prod and the tool to maintain single and multiple codebases is git.
Git is an underlying technology that maintains version control of your repository and provides nice collaboration between the team members. and GitHub is a web-based platform that provides hosting for version control repositories.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 1

2. Dependencies

Explicitly declares and isolates dependencies.
Most programming languages offer a packaging system for installing or distributing supported libraries. for example pip for Python, or CPAN for Perl.
And these libraries installed throw a packaging system and can be installed system-wide or scoped into the directory containing the app (Known as bundling).
System-wide installation means making it available for all projects and applications on that computer.
And Scope into a directory means installing the library specifically for your project within the project’s own directory structure.
A Twelve-factor app never relies on the implicit existence of system-wide packages.
So, it declares all dependencies, completely, and exactly, via a dependencies declaration manifest file like requirments.txt in Python that can be installed by the pip packaging system. furthermore, it uses dependency isolation tools during execution to ensure that no implicit dependencies “leak in ” from the surrounding system. Different programming language ecosystems provide different approaches to isolation. For example, Python has a concept of a virtual environment(venv).
So, with the dependencies declaration manifest file and dependency isolation tools like venv are used in Python, we are able to define requirements and can isolate dependencies.
However, what about tools that the application relies on that are outside of programming language dependencies?
let’s say, the “curl” command and any other tools that are dependent on the system. Keep in mind that “curl” must be installed on the host operating system to work with your application. In a virtual isolated environment like Python “venv” won’t provide the “curl” binary itself; it relies on the host system “curl”.
This is where a more Universal approach that works across all the different programming languages can help such as Docker container.
Docker allows us to run applications in a self-contained environment that is isolated from the host system. it is a more efficient and reliable way to manage dependencies.
By using docker we are able to completely follow the second rule “Explicitly declare and isolate dependencies”.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 2

3. Config

Store config in the environment
config refers to the configuration setting that an application requires to run in different environments such as development, testing, staging, and production.
configuration settings like database connection string, API keys, and other parameters that can vary depending on the deployment environments.
So, instead of storing configuration settings in traditional config files or hardcoded within the code, A Twelve-factor App stores its configuration in environment variables (env vars).
Environment variables are a way to pass information to applications at runtime without changing the code itself. Environment variables are easy to change between deploys(development, testing, staging, and production) without changing any code.
So, in the Twelve-factor App, the configuration should be strictly separated from the code and stored in environment variables. This means that only one application build needs to be created which can be tested, deployed, and run in multiple environments.
The Twelve-factor App doesn’t say how to store Secrets, such as passwords and API Tokens for that we recommended managing these using secret management tools, such as HashiCorp Vault, AWS Secrets Manager, or any other valid tools in this category.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 3

4. Backing Services

Treat backing services as attached resources
A backing service is any service the app consumes over the network as part of its normal operation. for example database (Mysql), Redis, SMTP services for outbound email such as POSTFIX, etc.
Backing services can be locally-managed services or any third parties like AWS, S3, or AWS RDS to the app, both are attached resources, accessed via URL or other locator/credentials stored in the config.
Deployment of the Twelve-factor app should be able to swap out a local MYSQL database with one managed by a third party (such as AWS RDS) without any changes to the app’s code.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 4

5. Build, Release, Run

Strictly separate build and run stages
The Twelve-factor App uses strict separation between the build, release and run stages.
Taking a codebase and turning it into a running application in a particular environment involves the following stages.

1. Build stage

The build stage uses the code and its dependencies to produce a build.
The build stage is the initial phase in the software development process where the application source code is compiled, tested, and transformed into deployable artifacts this phase typically involves actions such as compiling code, running unit tests, and packaging the application into container images or other deployable formats.

2. Release stage

The release stage uses the build and its configuration to produce a release.
Once the build stage is completed, the Release stage takes over, in this stage you define how many replicas of the application should be running which containers and images to use and how the application should be exposed to outside world and other configurations necessary for the application to function correctly, Deployment tools typically offer release management tools, most notably the ability to roll back to a previous release.

3. Run stage

The run stage runs one or more instances of the release
The run stage involves running the application as a live workload, handling multiple concurrent requests, and managing its lifecycle, These process enables a clear separation of concern and should be automated using CI/CD pipelines.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 5

6. Processes

Execute the app as one or more stateless processes
Twelve-factor App processes are stateless and share-nothing, Any data that needs to persist must be stored in a stateful backing service, typically a database this approach provides important operation benefits, making it easier to scale and recover from failures.
Stateless processes means each instance of the application should be independent and not store any state or data specific to single users or requests.
This factor is an important prerequisite for other Twelve-factor guidelines, such as Concurrency and Disposability.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 6

7. Port Binding

Export services via port binding
Twelve-factor Apps are self-contained and independent process that do not run under the control of a parent process, they expose their services by listening on a port.  This also means that they can act as backing services for other apps.
The concept of port binding is crucial for web-facing services or any network-based services that need to be accessed over the internet by binding the application to a specific port, the application becomes reachable through that ports network addresses, allowing client(such as web browser or other application) to communicate with the application.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 7

8. Concurrency

Scale out via the process model
Concurrency refers to how an application scales and handles multiple concurrent requests or tasks. Twelve-factor App promotes stateless processes, meaning each instance of the application should be independent and not store any state or data specific to a single users or request this enables easy horizontal scaling.
Twelve-factor App advocates using load-balancers to handle increasing concurrency that distributes incoming requests across multiple instances of the application.  Twelve-factor App ensures that the application is designed to handle multiple concurrent requests and can scale easily without compromising responsiveness or resource utilization.
This approach is well-suited for modern web applications and services that need to handle a large number of users and requests simultaneously.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 8

9. Disposability

Maximize robustness with fast startup and graceful shutdown
The Twelve-factor app processes are disposable meaning they can be started and stopped quickly and seamlessly this allows for easy scaling and rapid deployment of updates without disrupting the system.
Processes should aim to have short startup times, ideally, just a few seconds, to be agile and easily move between machines.
When these processes need to shut down, they do so gracefully by finishing ongoing tasks and exiting when signaled, for web processes, this means refusing new requests, allowing current once to complete, and then shutting down.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 9

10. Dev/Prod Parity

Keep development, staging, and production as similar as possible
Traditionally, there have been substantial gaps between the development and production environment, these gaps manifest in three areas:
The time gap: A developer may work on code that takes days, weeks, or even months to go into production.
The personnel gap: Developers write code, and ops engineers deploy it.
The tools gap: Developers may be using a stack like Nginx, SQLite, and OS X, while the production deployment uses Apache, MySQL, and Linux.
The twelve-factor app is designed for continuous deployment by keeping the gap between development and production small.
Make the time gap small: a developer may write code and have it deployed hours or even just minutes later, deploying frequently to minimize the gap between code in different environments.
Make the personnel gap small: developers who wrote code are closely involved in deploying it and watching its behavior in production, giving developers the responsibility to deploy and monitor their own applications, rather than having separate operations team take care of this.
Make the tools gap small: keep development and production as similar as possible.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 10

11. Logs

Treat logs as event streams
The twelve-factor app is very clear that logs should be written to understand output and treated like an even stream instead of writing logs in a file that is stored on the computer’s disk.
The app doesn’t have to worry about where the logs go or how they are stored, instead, each part of the app writes logs or messages to special output called stdout.
During development, we can see these messages directly on the screen or terminal. In staging or production, the execution environment collects all the messages or logs and sends them to the final destination using tools like Logplex or Fluentd. These destinations can be files or logs and analysis systems like Hadoop and ELK.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 11

12. Admin Processes

Run admin/management tasks as one-off processes
The admin processes principle of the Twelve-factor App methodology recommends that administrative tasks should be kept separate from the application process and that they should be run in an identical setup and be automated, scalable and reproducible.
So, these administrative tasks such as:
Running database migrations.
Running a console or in some cases having separate commands.
Running one-time scripts committed into the app’s repo.
One-off admin processes should be run in an identical environment and they run against a release. Admin code must ship with application code to avoid synchronization issues.

The Twelve-Factor App: Best Practices for Cloud-Native Applications 12

Conclusion

The Twelve-Factor App methodology offers a comprehensive set of best practices for building modern cloud-native applications. In today’s era, where software is commonly delivered as a service, adhering to these principles becomes crucial to achieve scalability, portability, and maintainability.

By following the Twelve-Factor App, developers can overcome the challenges of traditional application development, where deployments were cumbersome and tied to specific servers. With a focus on codebase management, explicit dependency declarations, and environment-based configuration, applications become more flexible and can easily adapt to different deployment environments.
The separation of build, release, and run stages ensures a clear distinction between development and production, allowing developers to rapidly iterate and deploy changes with minimal disruption. Stateless processes enable horizontal scaling, while the use of port binding ensures that applications can easily expose their services for external access.

The Twelve-Factor App emphasizes Disposability, promoting fast startup and graceful shutdown, which enhances resilience and scalability. By treating logs as event streams and running administrative tasks as one-off processes, developers gain better insight into application behavior and maintain cleaner codebases.
By following the Twelve-factor guidelines, developers can create modern cloud-native software-as-a-service applications that are portable, resilient, and designed for the cloud era.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0
Avatar

Priyam Vaidya

A certified cloud architect (Azure and AWS) with over 15 years of experience in IT. Currently working as Sr Cloud Infrastructure Engineer. Love to explore and train others on new technology

Add comment