Nowadays everyone is building microservices. No matter where you work, either in a startup or a big company you will encounter microservices architecture. Heroku did a great job at defining what makes a solid baseline for standing up your architecture.
In 2011 Adam Wiggins [Heroku co-founder] published The Twelve-Factor App methodology for building software-as-a-service based on their own experiences. It is technology and language agnostic but successfully compatible with Microservices, Containers and CI/CD Pipelines with a focus on DevOps, hence, this topic is on my radar.
The 12-factor app is based on a few parameters for deployment of cloud-native applications:
Matt Ellis from Tibco said “the 12-factor apps check-list is really just a set of guidelines that dictate how a microservice should be built to properly support the concept of independently managed and iterated services. These factors are important when building decoupled, stateless microservices”. So what should the 12Factor app be? Watch the 28 sec. video: https://www.youtube.com/watch?v=7PH3AOePAXc
“Any developer building applications which run as a service. Ops engineers who deploy or manage such applications”, says the author.
The full content is out there, so there is no need to repeat it. I will only outline the core message of each of the following points:
Build on top of one codebase, fully tracked by a Version Control System (VCS). Deployments should be automatic, so everything can run in different environments without work. You should always have one repository for an individual application to ease CI/CD pipelines.
Do not copy any dependencies to the project codebase, instead use a package manager. Always remember to use the correct versions of dependencies so that all environments are in sync and reproduce the same behavior.
Store the config in Environment Variable. There should be a strict separation between config and code. The code should remain the same irrespective of where the application is being deployed, but configurations can vary.
Treat backing services as attached resources as your services should be easily interchangeable. You must be able to easily swap the backing service from one provider to another without code changes. This will ensure good portability and help maintain your system.
A twelve-factor application requires a strict separation between Build, Release and Run stages. Every release should always have a unique release ID and releases should allow rollback. Automation and maintaining the system should be as easy as possible. Then you put everything together in something that can be released and installed in the environment and then be able to run it.
You should not be introducing state into your services, applications should execute as a single, stateless process. The Twelve-factor processes are stateless and share-nothing. This factor lies at the core of microservices architecture.
Your service should be visible to others via port binding. If you built a service, make sure that other services can treat this as a resource if they wish. The twelve-factor app is completely self-contained.
Break your app into much smaller pieces rather than trying to make your application larger (by running a single instance on the most powerful machine available). Small, defined apps allow scaling out as needed to handle the varying loads. Each process should be individually scaled, with Factor 6 (Stateless), it is easy to scale the services.
Processes should be less time-consuming. Make sure you can run and stop fast. And that you can handle failure. Without this, automatic scaling and ease of deployment, development- are being diminished. You can achieve this with containers.
Keep development, staging, and production as similar as possible so anyone can understand it and release it. Continuous deployment needs continuous integration based on matching environments to limit deviation and errors. This also implicitly encourages a DevOps culture where Software Development and Operations are unified. Containerization is a huge help here.
Treat logs as event streams. Logging is important for debugging and checking up on the general health of your application. At the same time, your application shouldn’t concern itself with the storage of this information. Instead, these logs should be treated as a continuous stream that is captured and stored by a separate service.
Run admin/management tasks as one-off processes — tasks like database migration or executing one-off scripts in the environment. To avoid messing with the database, use the tooling you built alongside your app to go and check the database.
There are also two articles worth reading: “Why 12 Factor Application Patterns, Microservices, and CloudFoundry Matter” by Tim Spann and “How I Use the Twelve-Factor App Methodology for Building SaaS Applications with Java & Scala” by Jay Kapadnis.
Microservices are still relatively new architecture pattern, therefore I really recommend you to study the Twelve-Factor App methodology in details. Across my experience, most microservices projects failed at the start. It was not due to deep design issues, or coding difficulties, but in fact, because of getting the basic things wrong.
Some points in 12-Factor may seem trivial, but when running 20+ services via few environments they may be of great importance.
Let me finish with Tim Spann’s distinct explanation of why he decided to combine 12-factor application patterns, microservices, and Cloud Foundry:
“Good code fails when you don’t have good process and a platform to help you. Good teams fail when you don’t have a good culture that embraces DevOps, microservices and not giant monolith.”
also posted here