12 Factor App

image.png

With the advent of microservices, there is a constant need to think about how to manage a huge number of apps, repository management, DevSecOps, independent deployments, resiliency, scaling, tracking, and monitoring.

12-factor app is a set of guiding principles that helps in creating applications that are scalable, resilient, independent, and performant. These principles were first used while developing the Heroku platform.

Following are the principles :

image.png

1. Codebase :

One codebase tracked in revision control, many deploys

image.png

There should be a single codebase that can be deployed, tested independently. The codebase should be checked-in into a source control system like git, svn, etc. There could be multiple developers working on the same codebase at a time, source control feature branches could be used for this. Different versions could be deployed on testing environments.

2. Dependencies :

Explicitly declare and isolate dependencies

image.png

All external dependencies of the application should be tracked and managed externally. There should be a dependency management tool that should list down all the dependencies required by your system. Dependency management tools like Maven and Gradle can help to define these.

3. Config

Store config in the environment

image.png

Applications would depend on lots of properties that can be environment-specific. These properties should never be part of the codebase and should not be hardcoded in the code itself.

As these can verify as per the environment, these should be injected into the code from outside. It could be configured in the environment properties and a config server like spring config server could be used for this purpose. It also helps to change the properties without changing the codebase and would not require a rebuild.

4. Backing Services

Treat backing services as attached resources

image.png

There are multitude of services that are required by your application, it could a database, any messaging system, etc. These resources should be treated as attached resources.

The desired state is when these services can be swapped easily with other providers’ services without making changes in the code. It should be the configuration where the change should be limited to.

5. Build, release and run.

Strictly separate build and run stages

image.png

The three stages of build, release, and run should be separate from each other.

  • The build stage is when the code is built and executable created

  • The release is when the executable is combined with the environment-specific configuration and is ready to run

  • The run stage is when the app is running and executing some tasks.

CI/CD tools can be used to achieve continuous build, quality checks, and deployment.

6. Processes

Execute the app as one or more stateless processes

image.png

The application can be executed in an environment as a process. It may have more than one instance and should not save the state within the application. It should typically be saved in underlying attached services like a database. This helps the application to scale on demand without losing the information.

Shared and distributed caching techniques like Redis can be used to store information if required. Sticky sessions which help the request land on the same instance after the initial request is against the principles of the 12-factor app.

7. Port Binding

Export services via port binding

image.png

The twelve-factor app is completely self-contained and doesn’t rely on the 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.

Spring Boot is an excellent example of this principle. It can help to embed application servers like tomcat in the application and does not need an external server injection to run on any environment. The dependency is mentioned via dependency management tools like Maven.

8. Concurrency

Scale out via the process model

image.png

This principle states that the application should be able to scale horizontally ( i.e add more instances of application ) as the load increases on the applications. This also helps to scale down an application when the load decreases hence saving cost.

This should also be done at multiple layers so that each layer can scale independently. The load distribution on multiple instances can be managed using the load balancers.

9. Disposability

Maximize robustness with fast startup and graceful shutdown

The applications should be designed in a way to minimize startup time. This enables the application to scale up and down quickly.

The 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.

10. Dev/Prod parity

Keep development, staging, and production as similar as possible

image.png

This principle states that the difference between the non-production and production environment should be minimized. This can be achieved by reducing the time of the release cycle.

The intent is to have frequent releases so that the codebase remains in sync for different branches. The backing services should be kept similar in all environments. This saves us from having environment-specific defects.

Continuous integration and deployment are the way to achieve this. Testing stages should be automated as much as possible which enables to ship product much quicker.

11. Logs

Treat logs as event streams

image.png

Logs principle advocates sending log data in a stream. This stream of data can be subscribed to by consumers who may be interested in such data. It could be a log aggregation system, alert system, or an audit system. The consumers may act based on the log of their agenda.

12. Admin processes

Run admin/management tasks as one-off processes

There are a lot of processes that are required to be run once. These could be database migration from one provider to another, loading of data for the first time.

Such scripts should be part of the codebase itself. These should also run against similar environments as any other processes in the system. Execution of such processes should be automated using similar tools as main processes and should follow CI/CD.

if you liked this article, please follow me to read more such content. You can also follow me on Twitter Follow me