12 Factor App Example In Spring Boot
Building web applications deploy on a modern cloud environment and delivered as a service called software-as-a-service. It is important to find methodology to architect web apps that fit on cloud computing and deliver software on time. In 2011, Adam Wiggins, developer at heroku, drafted the twelve-factor app methodology. He defined and separated 12 factors helping maximum portability, clean contract, scale up, continuous deployment.
1 - Codebase
One codebase tracked in revision control, many deploys.
12 factor app methodology strongly defines that an application on many different deploy environments must have only a single codebase, tracked in a version control system such as git, or subvision. Codebase is a set of instructions of your application on any single repository.
In order to comply with this principle, we keep our one codebase per app in the git version control system and share many deploys of the app. If we have multiple codebases, it is called a distributed system. 12 Factor App recommended us to apply a single codebase per component. If we have a multi app that has shared the same codebase, we must wrap it into libraries which are included through the dependency manager.
In the real example practice with our spring boot application, we keep our source code in the git repository and share them to our collaborations. This code will be compiled and packaged then deployed to one or many environments. For specific running applications in different environments like development, production, it depends on configuration. We store those configurations using spring profiles and environment specific properties rather than duplicate our code base into different repositories. Test, staging, prod must have one source code base in one repository.
2 - Dependencies
Explicitly declare and isolate dependencies.
Many programming languages offer a packaging system installer for using and sharing the code across the application. Eg, node ecosystems offer NPM or Yarn, Ruby offers RubyGem, Java offers Maven or Grandle, Python offers pip etc.
Dependencies of an application are open source libraries built and distributed by developers or a team or an organization. 12 Factor App said “A twelve-factor app never relies on the implicit existence of system-wide packages”, it means all dependencies declared specific versions which application work in external files call manifest and use dependencies isolation tools for execution. dependencies isolation tool is a tool bundler that bundles dependencies with an application.
Advantages of explicit dependency declaration is helping in reusable and maintainable code base for multiplapp. New developers will be able to quickly set up everything that prerequisites for applications need.
The twelve Factor app has decouple two dependencies explicitly, it help our application do not reply on implicit existence system package and system tool:
Example spring boot, we explicitly declare dependencies in a pom.xml
file of manifest format:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
The spring-boot-starter-data-rest
is declared for
spring boot starter projects with restful data. It
will be built by a maven tool that shares class paths across an application.
3 - Config
Store config in the environment.
App config is everything as constants that running applications need on any specific environment stages including database, memcached properties, third party credentials like amazon S3, firebase, onesignal,..etc.
In bad practice or traditional applications, developers stored all app config variables in their code. When they want to change those config, it’s hard to maintain, changing the environment and it also compromises any credentials of external applications. Those are the mistakes and violence the twelve-factor apps in the modern cloud for implementing the SaaS application model. So how do we store config? In the config file? Yes, It’s possible but still a weakness because those config files will check in to the repo.
The methodology of the twelve-factor app requires strict separation of config from code, and stores config in environment variables. Environment variable (env) is convenient to change and deploy to different stages without breaking the code.
The spring boot application used java system properties mechanism and offered to code in runtime by configuration properties.
application.properties
service.mail.enable=true
@ConfugurationProperties(prefix = “service.mail”)
class MailConfigProperty {
private Boolean enabled = Boolean.TRUE;
}
4 - Backing Services
Treat backing services as attached resources.
Backing service is any service that supports network operation for applications such as database, messaging event, Asset service, Mail service, caching system, metrics-gathering service, …etc . Most modern applications depend on backing services to operate their business.
In twelve-factor app methodology, The code for a twelve factor app makes no distinction between local and third party services. It means both local and third party services will be attached as resources, and accessible via a URL. Service locator or credentials need to be stored in config to comply with the config rule of twelve-factor app. Each backing service is a resource that can be attached to and detached from deploy, Codebase is flexible to change local backing service to a third party backing service without code changes. Example, we use local mysql in our development on a local machine. When deployed we might swap to Amazon RDS third party service.
Backing service principle helps us loose coupling between app deployment and the resource. It will make our application scalable and disposable. Spring boot can be achieved by Spring data JPA over RDBMS data source that offers abstract implementation of data access layers by configuration properties (JDBC URL) to make database connection. With JPA, we can swap out databases by changing configuration.
application.properties
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://${MYSQL_HOST:localhost}:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=ThePassword
spring.datasource.driver-class-name =com.mysql.jdbc.Driver
#spring.jpa.show-sql: true
5 - Build, release and run
Strictly separate build and run stages.
“The twelve-factor app uses strict separation between the build, release, and run stages”. Single codebase is separated three stages for deploy workflow :
In the practice, we use any deployment tools for release management. eg, docker, capistrano, ..etc. Those tools offer the ability to roll back previous releases. Example docker:
6 - Processes
Execute the app as one or more stateless process.
The app is executed in the deployment environment as one or more processes. “Twelve-factor processes are stateless and share-nothing”. It means we must not store data as stateless. If the process needs the data to serve the next request we must persist data outside the application in a stateful backing service, stored in a database. Why do twelve-factor apps define that ? when running only one process, our application might be restarted for up deployment, changing configuration, it will destroy all local state.
Some traditional web applications rely on sticky sessions that persist user data in memory to serve future requests. With this scenario, it is violence of twelve-factor. Absolutely, session state should be stored in a datastore with time expiration such as hazelcast or redis.
Spring boot applications execute java processes on JVM or inside containers like docker. Any data that the application needs, should be stored in the database.
7 - Port Binding
Export service vai port binding.
The twelve-factor app is completely self-contained. It means the application should be binding itself to a particular port and listening to all the requests from the incoming client on that port in the execution environment. If you setup a web application from scratch you can use dependency declaration to add a web server library to the app. In some cases, you build your web application using any framework such as laravel, expressjs, or spring, it comes along with a self-contained web server. The port binding methodology makes your application as the backing service for other apps to consume also. It provides the URL and as attached the resource in config.
Application using spring boot embedded apache tomcat and export HTTP as a service by binding to a
port. We can configure the port in the config variable (.properties, yalm) server.port
configuration
property. By default spring boot serves on port 8080.
8 - Concurrency
Scale out vai the process model.
One application can be running as one or more processes. The twelve-factor app processes should be scale out as horizontal scaling by process model. Process model is a modern approach that uses the unix process model for running web app service daeon. It gives us a unique way to manage our workload and scale up overtime. In monolithic applications, it is running in a larger single process that makes vertical scaling (increase CPU or RAM capacity). Best practice of the methodology, If we have many processes, we should handle those processes as workloads and assign a process type. For example , an application has a model assigned two process types, one process is a web process that handles HTTP requests. The second, worker process is a long-running background task for the job handler. Both processes are running service daemon workloads. Each of the processes should be shared-nothing that makes our app easily scale faster.
Spring boot applications do not help much with this factor. Our application should be stateless and managed stateful by an outside application. If we want to scale a specific process, we will split our application into smaller. Microservice architecture is independent service, focus and small service, including scale out processes of the nature of twelve-factor apps.
9 - Disposability
Maximize robustness with fast startup and graceful shutdown.
Disposability factor means that an application is able to start and stop rapidly without interrupting any processes. A few second startup service offers a release stage of deployment easily and quickly. Processes should be shut down gracefully to allow current requests to finish and exit. In case of hard shutdown, worker processes by returning the current job to the work queue.
Spring boot applications should be run inside containers that can start and stop at a minimum at a moment's time. Docker image should be optimized with the lazy initialization of dependencies to be a disposable process.
10 - Dev/prod parity
Keep development, staging, and production as similar as possible.
Traditionally, development software applications slow down because of the divergence between dev and prod infrastructure or environment.
The twelve-factor app is designed for continuous deployment by keeping the gap between development and production small and similar. It helps developers continue to write code and continue to deploy in hours or minutes. Besides, in the same environment, backing service is encouraged to be compatible between local and production. Differences between backing services mean that they violate the twelve-factor app because codebase will work on test or staging and fail in production.
The container is possible to build and ship codebase packages to run everywhere and portable OS. Spring boot applications are packaged in docker image and pushed to docker registry. Docker includes provisioning tools of alternatives to packaging systems such as homebrew or apt-get.
11 - Logs
Treat logs as event streams.
Log is a file that records data of all input, data output, processes or results in a program. A twelve-factor app never concerns itself with routing or storage of its output stream. All the logs shouldn't be written and stored into a log file in application. Any running process is written as an event stream into the standard output stdout.
Spring boot application, log only the console by default. It doesn't store log records in tmp files on disk. Best practice console logs, we use SLF4J acts as a facade for different logging frameworks. In a cloud environment, we can integrate any logs aggregator and management tool to analyze or monitor application health such as new relics, papertrail, sentry, datadog.
12 - Admin processes
Run admin/management tasks as one-off processes.
Most applications have one-off administrative or maintenance tasks such as database migration, script fix bad record, console inspect application running. Those tasks should be run in isolated processes. One-off admin code must be shipped with application code to be portable in the execution environment. Twelve-factor app empsized run one-off script with REPL shell out of the box. In local, we run shell commands inside the application. In a production environment, we can remote command execution to run such a process.
For spring boot applications, we add one-off admin functions and expose endpoints for invocation.
Summary
The twelve-factor app methodology is successful for developers building web applications and ops engineers who deploy or manage running applications. The principle can be applied to apps, not specific programming languages and ideally attach the backing service. Each of factors strongly define following:
- Codebase : one single code base target deploy many environments.
- Dependency : All dependencies should be declared explicitly in manifest
- Config : store all configuration properties in environment variables
- Backing Service : Treat backing service as attached resource, flexible swap out by execution environment.
- Build, Release, Run : Delivery pipeline, build, package and run.
- Processes : run applications as stateless processes and store application data in backing service.
- Port binding : Self-contained and made available to other services by binding itself with specified port.
- Concurrency : scale out process as horizontal scaling by process model.
- Disposability : Fast startup and graceful shutdown service.
- Dev/prod parity : All environments should be as similar as possible.
- Logs : Produce logs as event stream rather than store in file inside application.
- Admin Process : Admin tasks must ship with application code.