prelude

The 12-Factor-App is a set of 12 principles developed by Heroku development team based on the experience of Soft as a Service (SaaS). These 12 guidelines provide best practices and an organized approach to developing modern and complex applications, and are not limited to any development language. Following these guidelines will improve the stability and extensibility of your application and reduce the gap between development and production.

An application created by the 12 elements needs to achieve:

  • Configure automated processes through declarative syntax to minimize the time and cost of new developers joining the project;
  • Decoupled from the operating system to provide maximum portability between different execution environments;
  • Suitable for deployment on modern cloud platforms, eliminating the need for server and system management;
  • Support continuous deployment to maximize agility and minimize differences between development and production;
  • It can be extended without major changes

The next step is to embody these goals in 12 specific elements.

⚠️ Note: this article is mostly written, so there will be more text, but I hope you can keep reading and add your thoughts as you read, and trust that you will get something in the end.

Codebase

Track a code base in version control and do multiple deployments

** code bases are always managed by version control systems (VCS) ** such as Git and SVN. Tracing and versioning of code is a critical part of development, and it also simplifies the collaborative development of applications. There is no development team that doesn’t use VCS today. If so, I can only send a capital “fu”!

2. Always maintain a one-to-one relationship between the code base and the application

If there are multiple code bases, then this is not an application, but a distributed system, where each component is an application, and each application can comply with the 12 elements.

Code bases should not share code between applications

Code that is common throughout the application should be created as libraries that can be included through the dependency manager.

4. Different environments share the same code base

As mentioned above, there should be a one-to-one relationship between the code base and the application. If you need to deploy the application to different environments, such as development, staging, production, you should not create different code bases. You can use the Subversion control system for implementation. Github, GitLab, etc., to create different branches, it is also good to see the progress of team members and monitor the quality of their code. If you want to know how to better manage multiple versions of your code base, you are advised to check out Git-flow.

Dependence (Dependecies)

Explicitly declare and isolate dependencies.

For any application, no dependencies should be copied into the code base, and dependency management tools should be used to obtain the required dependencies.

For example, use NPM or YARN and package.json to manage the dependencies of the front-end project or Node project.

For example, use Maven and POM.xml to manage Java project dependencies.

In this way, all third party dependencies are clearly defined and managed in a unified way, which also helps developers who are new to a project to install dependency management tools into their environment at any time, and there are no conflicts on any platform.

You will use the CI/CD process to automate this later, as discussed later.

Configuration (Config)

Store the configuration in the environment.

Modern application development requires some form of configuration, usually including port numbers, service account credentials, database connection information, and so on. There are also different configurations for different environments, such as development, staging, and production.

⚠️ Note: It is not desirable to store configurations as constants in code! Deployment configurations vary widely from environment to environment, but the code does not. And it risks exposing your app’s private credentials.

One test to check that an application is properly separating all configuration from the code is to think about whether the code base can be made open source at any time without exposing any private credentials.

The best approach is to store the configuration in environment variables, which can be easily modified at run time for a particular environment.

The following specific methods are suggested:

  • Use version-free.envFiles are developed locally and Docker supports loading these files at runtime;
  • All of the.envFiles are stored on secure storage systems (e.gVault) for developers to use, do not commit to Git;
  • Use environment variables for anything that can be changed at run time and for any private credentials that should not be submitted to the shared repository;
  • After deploying your application to a delivery platform (for example, AWS, Alibaba Cloud, Tencent Cloud), use the mechanisms of the delivery platform to manage environment variables.

Anyone who has experience with front-end engineering and Node projects will know how the Dotenv library behaves in a Node.js environment. As mentioned in Dotenv’s README, storing the configuration separately from the code base in the environment is based on the “12-factor application” approach.

Consider support services as additional resources

A supporting service is any service that the application accesses over the network during operation. For example, databases, SMTP, data apis, caching systems, and the like should all be accessed as services. Local services and third-party services should be treated as additional resources. When switching services, the code base should not be changed, but the URL, account password and other connection information should be changed. For example, to switch Mysql from local to AWS, you only need to change the connection information. These are delivered through configuration information, which is managed in accordance with the previous rule.

Build, Release and Run (Build, Release, Run)

Strictly separate build and run phases

It is important to break application deployment into three phases:

1. The build phase compiles and packages the code base and its dependent packages, giving the developer complete control over this phase, marking new versions and fixing any bugs. It is best to change code only during the construction phase and not during other phases.

2. Release takes the package built in the previous phase, combines it with the configuration on the specific environment, and is ready for immediate execution in the execution environment. Each distribution has a specific unique identification number (software version number) that allows for quick rollback to previous versions in case of problems.

3. Start execution in a specific environment for a specific release. This is the final stage of running the application and should not be interfered with by any other stage.

In order to support strict separation of build, release, and run phases, it is recommended to automate builds using continuous integration/continuous delivery (CI/CD) tools. Docker also makes it easy to separate build and run phases.

Process

Executes applications in one or more stateless processes

Applications should be stateless and share-free, and any data that needs to be retained must be stored in a stateful support service, usually a database.

For example, if a Web system relies on “sticky sessions” that cache user session data in the application’s process memory in the expectation that future requests from the same visitor will be routed to the same process, it is not desirable. Session state data is well suited to providing time-expired data stores, such as Memcached or Redis.

Port Binding

External services are provided through ports

It is an architectural best practice for application services to expose PORT numbers specified by the PORT environment variable through urls. This way, your application service can act as a resource for other services as needed. This facilitates self-organizing applications.

For example, if you want to develop some of the Web application function is available for other service access, you can provide them with the API URL (e.g. https://www.web/api/module:5000) and some request data access token to each other.

Concurrent (Concurrency)

Processes can scale horizontally

In an application that meets the twelve elements, processes are first-class citizens, and the application processes are primarily borrowed from the Unix daemon model, which can be used to design application architectures that allocate different work to different process types and build their applications to handle various workloads.

For example, HTTP requests can be handled by Web processes, while long-running background tasks can be handled by worker processes.

Each process in the application should be able to scale horizontally as needed, without relying too much on threads in the application, as vertical scaling can limit the processes running on the server. Do not daemon or write Pids for applications, but rely on the operating system’s process management tools.

Easy to handle (Disposability)

The word Disposability means disposable or disposable, but it’s better to take advantage of convenience or ease of disposal.

Application processes should be started and stopped as soon as possible to reduce time consumption. This facilitates rapid elastic scaling, rapid deployment of code or configuration changes, and robust production deployments.

The process should be gracefully shut down when it receives the SIGTERM signal. For the termination of the worker process, the unfinished tasks should be returned to the queue and handled in case of system failure to maintain the robustness of the program, such as Beanstalkd.

The environment is similar to

Ensure that the environments are as consistent as possible

There is a big difference between traditional application development environment (DEV) and production environment, which is mainly reflected in:

  • Time difference: It takes a long time to get from development to production, sometimes weeks or even months before a new release is released;
  • Personnel differences: developers write the code and operations engineers deploy it;
  • Tool differences: May be used during developmentNginx.SQLiteandwindowsSuch technology stack, while production deployment is usedApache.MySQLandLinux;

Twelve-factor applications are designed for continuous deployment by narrowing the gap between development and production as much as possible, in terms of the differences above:

  • Time difference: The time interval from development to production can be hours or even minutes;
  • Personnel differences: The deployment and release of the new version is carried out by developers, not by operation and maintenance engineers;
  • Tool differentials: Making development and production tools as similar as possible;

If you use different services and tools between development and production, you can run into situations where code that runs successfully and passes testing during development has unforeseen problems in production. If you want to ensure the stability of continuous deployments, try to use the same tools or back-end services in each environment as in production. Using modern tools and services makes this easier and cheaper. For example, using Docker and Docker Compose ensures that your application remains consistent across your environment.

Log Processing (Log)

Process the log as a stream of events

A log is a continuous record of what the developer considers important until the application terminates, such as error messages or data that can be analyzed in the future. Logs can see the behavior of a running application, usually written to a file on disk, but only as an output format.

It is important to separate the collection, processing, and analysis of logs from the core logic of your application. Decoupling logging is especially useful when your application needs to scale dynamically and run on a public cloud, because you don’t have to worry about where the management logs are stored and the overhead of aggregation from distributed (often AD hoc) VMS, and just print accordingly to check your application flow. For example, if your application is running on multiple hosts, the record file is likely to be in a discontinuous state, so additional services are needed to consolidate the record, which requires decoupling of the log. In addition, some data can be displayed in a visual analysis way (such as Elasticsearch and Kinbana), and some alarm thresholds can be set to trigger alarm operation automatically.

Admin Processes

Run administrative tasks as a one-time process

** Management processes typically consist of one-off tasks or timed repeatable tasks, such as database migration, generating reports, executing batch scripts, and so on. These management processes should correspond to the application environment, such as executing development management processes in Development, production management processes in production, Moreover, the code of these management processes should be released together with the code of the application itself to the same environment in the same version and executed with the config items in the environment to avoid synchronization problems.

Additional considerations

API

Applications use apis to communicate, and when building an application, think a lot about how the application’s ecosystem will use it, starting with designing an API strategy. Good API design makes the API easy to use by application developers or other external stakeholders, and it is best to use OpenAPI to specification your API before implementing the code.

API abstracts underlying functionality. A well-designed API should decouple the application being used from the application infrastructure providing the services. This decoupling allows you to change the underlying services and infrastructure independently without using the users of the application.

It’s also important to catalog, document, and publish your apis so that users of your apis can better use and discover them.

security

The area of security is very broad, including operating systems, networks, firewalls, database security, application security, and identity and access management.

A foreign developer had circumvented GitHub’s OAuth process and reported it to GitHub. After the fix, GitHub rewarded the developer with a $25,000 bounty. For more information click here.

From an application perspective, apis provide access to applications in the ecosystem, so you should ensure that the building blocks address security issues during the design and construction of your applications. There are a few that can help protect access to your application:

  • Transport Layer Security (TLS)Use:TLSHelps protect data in transit, in some use cases, based onIPIt is also common for addresses to create permit and deny lists as an additional layer of security. Transport security is also about protecting your services fromDDos 和 BotAttack.
  • Application and user security: Transport security helps provide security and build trust for data in transit, but it is a best practice to add application-level security to control access to applications based on who is using them. Users can be other applications, employees, partners, or users. You can useAPIKeys (for consumer applications), certificate-based authentication and authorization,JWT(JSON Web Token)Exchange orSAML(Security Declaration Markup Language) to ensure security.

The last

See how these twelve elements can make your application build and release less fraught and more scalable and predictable. The additional time spent understanding and implementing these guidelines can save us significant software costs. In some cases, deviating from some elements (such as the Backing Service and the log) is also desirable, but it is best to adhere to all twelve elements as much as possible.

If you are designing and building your application, consider these 12 elements and take them seriously.

When you’re running multiple services in multiple different environments, what seems trivial now can become very important later on. Check to see if there’s something missing that might help you solve a problem you weren’t aware of before.

Taken together, these elements provide a good foundation for building your applications and services, an approach that will help you scale and maintain your applications smoothly in the long run.

Finally, I hope you can benefit from it or get some thinking and inspiration.

Citation and Reference: