12-factor app is a methodology for building the scalable and most resilient enterprise applications. It establishes the general principles and guidelines for creating robust enterprise applications. 12-factor app principles got very popular as it aligns with Microservice principles.
Below are the 12 factor principles
- Codebase (One codebase tracked in revision control, many deploys)
- Dependencies (Explicitly declare and isolate the dependencies)
- Config (Store configurations in an environment)
- Backing Services (treat backing resources as attached resources)
- Build, release, and Run (Strictly separate build and run stages)
- Processes (execute the app as one or more stateless processes)
- Port Binding (Export services via port binding)
- Concurrency (Scale out via the process model)
- Disposability (maximize the robustness with fast startup and graceful shutdown)
- Dev/prod parity (Keep development, staging, and production as similar as possible)
- Logs (Treat logs as event streams)
- Admin processes (Run admin/management tasks as one-off processes)
Codebase (One codebase tracked in revision control, many deploys)
12 factor app advocates that the every application should have their own code base (repos). Multiple code bases for multiple versions must be avoided. Please do note that having branches would be fine. I.e. For all the deployment environments there should be only one repo but not multiple.
Multiple apps sharing the same code is a violation of twelve-factor. Here you should opt-in for a shared libraries.
From the 12 factor app perspective app, deploy meaning the running instance of an app like production, staging, QA etc. Additionally, every developer has a copy of the app running in their local development environment, each of which also qualifies as a deploy.
Different versions (version is like a code change that is available in one environment but not in other) may be active in multiple deploys.
Microservices: In Microservices, every service should have their own code base. Having an independent code base helps you to easy CI/CD process for your applications.
Twelve factor app advocates of not sharing the code between the application. If you need to share you need to build a library and make it as dependency and manage through package repository like maven.
Dependencies (Explicitly declare and isolate the dependencies)
It talks about managing the dependencies externally using dependency management tools instead of adding them to your codebase.
From the perspective the java, you can think of gradle as dependency manager. You will mention all the dependencies in build.gradle file and your application will download all the mentioned dependencies from maven reporitory or various other repositories.
You also need to consider the dependencies from the operating system/ execution environment perspective as well.
Microservices: All the application packages will be managed through package managers like sbt, maven.
In non-containerized environments you can go for configuration management tools like chef, ansible etc. to install system level dependencies.
For containerized environment, you can go for dockerfile.
Config (Store configurations in an environment)
Anything that varies between the deployment environments is considered as configuration. This includes:
- Database connections and credentials, system integration endpoints
- Credentials to external services such as Amazon S3 or Twitter or any other external apps
- Application specific information like IP Addresses, PORTs and hostnames etc.
You should not hardcode any configuration values as constants in the code base. This is a direct violation of 12 factor app principles.
12 factor app principles suggest to save the configuration values in the environment variables.
It advocates the strict separation between the code and configurations. Code must be same irrespective of where the application being deployed.
As per “config”, what varies for environment to environment must be moved to configurations and managed via environment variables.
Microservices: Externalize the configurations from the application. In a microservice service environment, you can manage the configurations for your applications from a source control like git (spring-cloud-config) and use the environment variables to not to maintain the sensitive information in the source control.
Backing Services (treat backing resources as attached resources)
As per 12 factor app principles, a backing service is an application/service the app consumes over the network as part of its normal operation.
Database, Message Brokers, any other external systems that the app communicates is treated as Backing service.
12 factor app can automatically swap the application from one provider to other without making any further modifications to the code base. Let us say, you would like to change the database server from MySQL to Aurora. To do so, you should not make any code changes to your application. Only configuration change should be able to take care of it.
Microservices: In a microservice ecosystem, anything external to a service is treated as attached resource. The resource can be swapped at any given point of time without impacting the service.
By following the interfaced based programming allow to swap the provider dynamically without impact on the system. Plug-in based implementation also helps you to support multiple providers.
Build, release, and Run (Strictly separate build and run stages)
Application must have a strict separation between the build, release and run stages. Let us understand the each stage with more detail.
Build stage: transform the code into executable bundle/ build package.
Release stage: get the build package from the build stage and combines with the configurations of the deployment environment and makes your application ready to run.
Run stage: It is like running your app in the execution environment.
You can use CI/CD tools to automate the builds and deployment process. Docker images makes it easy to separate the build, release and run stages more efficiently.
Processes (execute the app as one or more stateless processes)
The app is executed inside the execution environment as a process. An app can have one or more instances/processes to meet the user/customer demands.
As per 12 factor principles, application should not store the data in in-memory and it must be saved to a store and use from there. As far as state concern, your application should store the state in database instead of in-memory of the process.
Avoid using sticky sessions, using sticky sessions are a violation of 12 factor app principles. If you would to store the session information, you can choose redis or memcached or any other cache provider based on your requirements.
By following these, your app can be highly scalable without any impact on the system
Microservices: By adopting the stateless nature of REST, your services can be horizontally scaled as per the needs with zero impact. If your system still require to maintain the state use the attached resources (redis, memcached or datastore) to store the state instead of in-memory.
Port binding (Export services via port binding)
The twelve-factor app is completely self-contained and doesn’t rely on runtime injection of a webserver into the execution environment to create a web-facing service. The web app exports HTTP as a service by binding to a port, and listening to requests coming in on that port.
In short, this is all about having your application as a standalone instead of deploying them into any of the external web servers.
Microservices: Spring boot is one example for this one. Spring boot by default comes with embedded tomcat, jetty, or undertow.
Concurrency (Scale out via the process model)
This talks about scaling the application. Twele factor app principles suggests to consider running your application as a multiple processes/instances instead of running in one large system. You can still opt-in for threads to improve the concurrent handling of the requests.
In a nutshell, twelve factor app principles advocates to opt-in for horizontal scaling instead of vertical scaling.
(vertical scaling– Add additional hardware to the system
Horizontal scaling – Add additional instances of the application)
Microservices: By adopting the containerization, applications can be scaled horizontally as per the demands.
Disposability (maximize the robustness with fast startup and graceful shutdown)
The twelve-factor app’s processes are disposable, meaning they can be started or stopped at a moment’s notice. When application is shutting down or starting, an instance should not impact the application state.
Graceful shutdowns are very important. System must ensure the correct state.
System should not get impacted when new instances are added or takedown the existing instances as per need. This is also known as system disposability.
Systems do crash due to various reason. system should ensure that the impact would be minimal and application should be stored to valid state.
Microservices: By adopting the containerization into deployment process of microservices, your application implicitly follows this principle at maximum extent. Docker containers can be started or stopped instantly. Storing request, state or session data in queues or other backing services ensures that a request is handled seamlessly in the event of a container crash.
Dev/prod parity (Keep development, staging, and production as similar as possible)
The twelve-factor methodology suggests keeping the gap between development and production environment as minimal as possible. This reduces the risks of showing up bugs in specific environment.
The twelve-factor developer resists the urge to use different backing services between development and production.
Microservices: This is an inherent feature of the Microservices that is run using the containerization techniques.
Logs (Treat logs as event streams)
Logs become paramount in trouble shooting the production issues or understanding the user behavior. Logs provides visibility into the behavior of a running application.
Twelve factor app principles advocates the separating the log generation and processing the logs information. From the application logs will be written as a standard output and execution environment takes care of capture, storage, curation, and archival of such stream should be handled by the execution environment.
Microservices: In Microservices, observability is the first class citizen. Observability can be achieved through using APM tools (ELK, Newrelic and other tools) or log aggregations tools like splunk, logz etc.
By following the above mentioned guidelines all you need is to debug an issue is to go to the central dashboard of your tool and search for it.
Admin processes (Run admin/management tasks as one-off processes)
There are number of one-off processes as part of the application deployment like data migration, executing one-off scripts in specific environment.
Twelve factor principles advocates to keeping such administrative tasks as part of application code base in the repository. By doing so, one-off scripts follow the same process defined for your code base.
Ensure one-off scripts are automated so that you don’t need to worry executing them manually before releasing the build.
Twelve factor principles also suggest to use the built-in tool of the execution environment to run those scripts on production servers.
Microservices: Containerization also helps here to run the one-off processes as a task and shutdown automatically one done with the implementation.
That’s all for today. Hope you have enjoyed the article. Please share your thoughts in below comments box.