How To Understand Twelve-Factor App In Spring Boot Applications

Oleksii Dushenin
5 min readFeb 15, 2022

The Twelve-Factor App is a set of principles required to build modern scalable application architecture. In this post, these principles will be reviewed from the perspective of Spring Boot Applications.

I. Codebase

An application is tracked in a version control system e.g. Git.

The codebase and the application have a one-to-one relationship. As a result, a single Spring Boot application has its own codebase. These applications constitute a distributed system. The code is the same for multiple deployments e.g. test, stage, production, etc.

II. Dependencies

In twelve-factor applications, system dependencies are explicitly declared.

In Spring Boot, Maven or Gradle can be used for these purposes. These tools can be used to specify required application dependencies. Furthermore, the possible issues with transitive dependencies are resolved.

III. Config

As was pointed out previously, there is one codebase per application. However, the same code is used for multiple deployments. As a result, these deployments require some configuration capabilities.

In Spring Boot, properties can be used to resolve this issue. Properties can be specified in multiple ways. E.g. defaults can be specified in application.yml file. Each deployment can override required properties with the help of environment variables. More details can be found in Spring Boot Documentation.

IV. Backing services

Each application can work with multiple external or third-party services.

It can be databases (e.g. MySQL), message brokers (e.g. Kafka), third-party API, etc. Each service should behave as a resource. It means that your code should run both on MySQL in Docker and MySQL in AWS without any changes.

In Spring Boot, it can be achieved with Spring Boot Properties, special interfaces, and classes (e.g. Spring Data Repository ).

V. Build, release, run

A twelve-factor methodology requires three different stages for transforming source code into a running application.

Build

To begin with, the source code is transformed into an executable. Maven or Gradle can be used to build a target jar file.

Release

In the second step, an executable is combined with the specific configuration. For instance, a Docker image can be created to combine a jar file with the required configuration.

Run

In this step, a Docker container can be created to run an application based on the image from the previous step. It means, that when necessary, we can quickly switch between versions of the application. If the current version has some bugs, a previous docker image can be used to run an application.

VI. Processes

Twelve-factor applications are stateless and share no data. However, data can be saved in a stateful backing service like a database.

Let’s review an example. Imagine, that we have an application with a MySQL database. Some requests to the database are slow. Consequently, an in-memory Caffeine cache is used. When data are updated, the cache is invalidated. Everything is fine when we have only one node deployment.

After some time, the load on the system is growing. We want to scale our application by adding the second node. The cache is located on each node. As a result, a user can see different results for two subsequent requests. The user updates the record. The first node invalidates its in-memory cache. On the one hand, a user can see new data. The user reads data again. The second node (with an old cache) responds with old data.

To overcome this problem, applications are stateless. This cache could reside in a distributed cache e.g. Redis.

VII. Port binding

In previously used typical Java applications, an executable is presented as a war file. This file is executed in a container e.g. Tomcat.

In twelve-factor applications, an executable is self-contained. A Spring Boot application has a Tomcat dependency inside of it. As a result, a jar is self-contained and only a java environment is required to run an application. The only thing you should specify is a target port that should be used by an application. It is done with configuration properties.

VIII. Concurrency

Twelve-factor applications are designed to scale out. A Java application runs as a single process that is bound to the JVM. In order to scale out a Spring Boot application, a new instance of it has to be started. In Build, release, run section, the Docker container was described as a way to run the Spring Boot application. Consequently, in order to scale out, Kubernetes can be used.

IX. Disposability

A twelve-factor application should be characterized by fast startup and graceful shutdown.

It means, that instances of the same applications can start or stop at any moment. It should not affect the application. To achieve it, when the instance of the application is stopped, this instance should stop listening for the incoming requests, finish processing of all current requests, and stop gracefully.

In Spring Boot, it is achieved with application events.

X. Dev/prod parity

In a typical application development process, there is a substantial gap between development and production. An application is developed in a local environment, a developer is not involved in deployment procedure, a developer can use different tools from the production ones.

Twelve-factor applications are designed for continuous deployment in order to minimize this gap. Spring Boot and Docker make it possible. An application can be written quickly using the same tools that are used in production.

XI. Logs

Logging is an important part of software applications that provides visibility into the running application.

In twelve-factor applications, logs are written into the standard output. The execution environment should be responsible for processing the logs. Fluentd can be used to collect such logs that are faded into the tools for logs indexing. Elasticseach and Kibana is a common example for these purposes.

XII. Admin processes

It is often required to run one-off tasks or routine procedures on the application. Twelve-factor application methodology suggests that these tasks should be incorporated into the application code.

For instance, a typical task is database migration. It is achieved with Flyway or Liquibase.

More articles can be found in the Architecture section.

Originally published at https://datamify.com on February 15, 2022.

--

--