Traditionally, developing deploying applications on a single/handful of servers was not a difficult task for an average team of developers. However, with the rise of cloud computing, managing the application on a large number of servers, load distribution, and meeting the needs of clients has became complicated. With the progress of technology, developing apps and SaaS(Software as a Service) became more daunting.
To solve this time-consuming and strenuous complication,
Twelve Factors are not the
One codebase tracked in revision control, many deploys.
Whenever a team of developers is making a SaaS, people work on different parts (e.g., development, staging, and deployment), but it would be bad practice to create a separate repository for each environment setup. So, it is better to make one codebase that is shared among all the different members of the team. Sharing codebase helps to maintain state across all the stages.
Explicitly declare and isolate dependencies.
Developers should never assume that the system on which the codebase will be deployed will already contain all the dependencies and libraries. It is highly likely that when a codebase, developed on Windows, is deployed on either Linux or macOS, it might not have the required set of packages preinstalled.
To avoid the hassle, you should always explicitly declare dependencies with their correct version.
Store config in the environment.
It is frowned upon to store configuration with the codebase. Doing so increases security risks as it might expose sensitive database credentials. Moreover, if you want to make amends to the configuration, you will have to edit the code every time.
It is better to keep the configuration separate from the codebase as environment variables.
Treat backing services as attached resources.
Resources that are consumed by an app over a network connection are called backing services. Backing services are databases like MySQL or Message queuing services like RabbitMQ. The problem arises when the network or any other service details change. So, do you go and edit the code?
No, it is advisable to keep the network connection as a variable in the configuration. Then, when need be, you can use that variable to make changes.
Strictly separate build and run stages.
You need to be mindful of three key stages when making a SaaS: build, release, and run.
Keeping all these stages separate isolates problems that may occur in development, and makes it easy to track and solve them.
Execute the app as one or more stateless processes.
Imagine that the processes are not stateless. If a single process fails in the application stack, it will kill the application.
To counter this, you should always maintain stateless processes. The state should be stored in a storage or database rather than an application process.
Export services via port binding.
Say you want to use the app you developed as a service to the other app, but you need a way to access your app and, by doing so, you would make that particular app self-contained.
To make a self-contained app, you need to make sure that your application is accessible through the URL. Your app should be able to entertain HTTP requests at a pre-defined port.
Scale out via the process model.
Sometimes applications will have to support heftier data than its current processes can support.
A good developer will make all the services top-notch so that they are self-sustainable and self-scalable. This way, if the load to the application increases, the developer can easily scale the entire app.
Maximize robustness with fast startup and graceful shutdown.
It is imperative to make your application failure tolerant. Your app should be able to shut down gracefully. In the case that it crashes or restarts, it should no longer than several minutes to restart.
Maintain the states and user data in a separate database or cache that can be used to fetch and restore data whenever the application reboots.
Keep development, staging, and production as similar as possible.
People from the developer team who work in different environments might bring forth unnecessary compatibility issues and bugs.
Development and production environments should be kept as similar as possible. They should use the same backing services to minimize disparity.
Treat logs as event streams.
To monitor the health of the application and diagnose the problem when the app crashes, it is essential to record logs.
Data should always be logged to a separate location instead of storing it with the application.
Run admin/management tasks as one-off processes.
After the final deployment of the application, when the application is up and running, there will be some tasks that will need to be managed by the admin (e.g., inspecting records or migrating databases).
To do this, the admin code should be shipped with the application, which contains all the relevant actions an admin can take. This makes the interaction between the admin and the application more seamless.
Free Resources