This post is just my notes about Twelve-Factor Applications. You can consider it my extended version of the original website.
“Twelve-factor applications” is a methodology that focus mainly on developing software-as-a-service applications (or SAAS for short). Although that’s was the main concern, factors in this methodology can be used or inspire engineering practices in other types of software development.
Facor 1 - Codebase
One codebase tracked in revision control, many deploys.
- The App need to be tracked in a version controled system [e.g Git] generally refered to as code repo or repo for short.
- It is one-to-one mapping between the codebase and the app.
- If there is multiple codebases, then each one is an app. Collectively they may form a distributed system.
- Multiple apps can’t share the same codebase.
- If there is shared code that need to be used in multiple apps, the shared code should be refactored out into libraries and consumed in these applications using a dependency manager (Factor 2).
- If an app needs another repo as a subdirectory in it and you are using Git you may check Git Submodules. This is not recommended unless it is absoultely necessary.
- Using the same repo and application can be deployed (run) as many as we want (Dev, QA, Staging, Production).
- Usually different versions run on these enviroments.
- Different enviroments usually used to check different things with the aim to promote the code version to the next enviroment (until it reach production).
Facor 2 - Dependencies
Explicitly declare and isolate dependencies
- Most programming languages have a packing system to distribute libraries.
- The explicit dependencies declaration is to ensur that dependencies are uniformally installed on different enviroments.
- Application shouldn’t depend on the implicit existence of any system tools.
- Some programming language have different tools to install dependencies and to isolate their scope (Pip vs virtualenv). Others isolate dependencies’ scope to the current application (C# and Nuget)
Facor 3 - Config
Store config in the environment.
- Configurations are the only thing that change between deploys (Dev, QA, Staging, Production).
- examples : credentials, database location, proxy,..
- Configurations can’t be part of the application code. They need to be separate.
- Same code version deployed many times, configs may vary for each deployment.
- Configs can be stored in environment variables.
- Advantages:
- can’t mistakenly be checked into code repo.
- language and OS agnostic standard.
Facor 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 (e.g. database server, queuing system,..).
- Code shouldn’t local or 3rd party services.
- Application should be able to switch services based on configs without code change (Dev deploy uses on-premises database, where Production deploy uses AWS database).
- Services can be attached and detached from deploys at will without code change.
- Restoring a database backup or switching to another SMTP server at run-time.
Facor 5 - Build, release, run
Strictly separate build and run stages
- Code base is transformed to a deploy through three stages:
- Build : compile and build the code and its dependencies into executable and assets needed during runtime .
- Release : takes the build stage output and combine it with specific configs to be ready for immediate execution in an execution environment.
- Run : runs the application release in the intended execution environment.
- Each build, release, run should have a unique ID that link the three stages together for tracebility.
- Some applications use internal version ID to refer to that ID and distinguish it from the public version number.
- Some applications use the commit ID as the internal ID.
- Usually builds intiated by developer commits but subsequent stages maybe manual trigger.
Facor 6 - Processes
Execute the app as one or more stateless processes
- These processes are stateless and share-nothing
- Anything that needs to persist must be stored in a stateful backing service [database or shared files]
- Stateless means that app must not assume that anything is cached in memory or on disk while serving requests or jobs
Facor 7 - Port binding
Export services via port binding
- This is usually done using dependency declaration to add a webserver library to the app (Jetty for Java).
- 12 factors apps doesn’t depend on execution enviroments like web servers
- All services should be exposed by port binding, not only HTTP services
- This enables one app to become the backing service to another app.
Facor 8 - Concurrency
Scale out via the process model
- Processes are first class citizens
- Each workload type get assigned to a different process type (web process, worker process,…).
- App must be able to span multiple processes on multiple physical machines.
Facor 9 - Disposability
Maximize robustness with fast startup and graceful shutdown
Facor 10 - Dev/prod parity
Keep development, staging, and production as similar as possible
Facor 11 - Logs
Treat logs as event streams
Facor 12 - Admin processes
Run admin/management tasks as one-off processes
Related Posts