12Factor
Main website of some architectural wisdom that came out of Heroku, back in the day (2011).
Beyond the Twelve Factor expands it a few points, with a summary:
1. Codebase
- A version control system like Git always tracks the fifteen-factor app.
- If we have multiple codebases, it’s not an app but a distributed system.
- If multiple apps share the same code, it violates the fifteen-factor. The solution is to add the shared code as a dependency.
- There is only one codebase per app, but there are many deploys of the app. The app is the same across all deploys, but different versions may be active in each deploy.
2. Dependencies
- A fifteen-factor app declares all dependencies, completely and exactly, via a dependency declaration manifest. It simplifies the setup for developers new to the app. The new developers will set up everything by running the app’s code with a deterministic build command.
- A fifteen-factor app doesn’t rely on the implicit existence of any system tools. If the app needs to shell out to a system tool, that tool should be vendored into the app.
3. Config
- Never store constants in the code. To be fifteen-factor compliant requires a strict separation of config from code.
- Config varies across deploys; code doesn’t.
- Always prefer storing the config in environment variables; environment variables are easy to change between deploys without changing any code.
- Environment variables are fully orthogonal to other environment variables; they are never grouped but independently managed for each deployment.
4. Backing Services
- Backing Service: any service the app consumes over the network as part of its normal operation.
- Systems administrators who deploy the app’s runtime manage the backing services.
- There are local and third-party services, and a fifteen-factor app doesn’t make any distinction between them.
- Deploy a fifteen-factor app should swap out a local backing service with one managed by a third party without any changes to the app’s code.
- Each particular backing service is a resource, called attached-resource.
5. Build, release, run
- The build stage is a process that converts a code repo into an executable bundle known as a build.
- The release stage takes the build and combines it with the deploy’s current config.
- The run stage runs the app in the execution environment.
- Each stage is strongly separated.
6. Processes
- Fifteen-factor processes are stateless and share-nothing. We have to use a stateful backing service whether we want to store any data.
- We can use the memory space or filesystem as a temporary, single-transaction cache.
- Never use sticky sessions. Never assume that anything cached in memory or disk will be available on a future request or job.
7. Port binding
- The fifteen-factor app is completely self-contained.
- The web application exports HTTP as a service by binding to a specific port and listening to requests coming in on that port.
- Note also that the port-binding approach means that one app can become the backing service for another app.
8. Concurrency
- Processes are first-class citizens.
- We should design our application to distribute workload across multiple processes. Individual processes can leverage a concurrency model like Thread internally.
- Fifteen-factor app processes should never daemonize or write PID files, instead, rely on the operating system’s process manager.
9. Disposability
- The application should be disposable; it means that we can start or stop it at any moment.
- We should aim to minimize startup time. The process should take a few seconds from the time the launch command is executed until the process is up and ready to receive requests or jobs.
- Processes should also be robust against sudden death. A fifteen-factor app is designed to handle unexpected terminations.
10. Dev/prod parity
- The fifteen-factor app is designed for continuous deployment by keeping the gap between development and production small.
- The time between deploys should be just hours than weeks.
- The author of the code and who deploy the application is the same person.
- Dev env and prod env should be as similar as possible.
11. Logs
- Logs are the stream of aggregated, time-ordered events collected from the output streams of all running processes and backing services.
- Fifteen-factor app never concerns itself with routing or storage of its output stream. The application should write its event stream, unbuffered to the standard output.
- The stream can be sent to a log indexing and analysis system like Splunk to find past events, graph trends, and active alerting.
12. Admin processes
- One-off admin processes should be run in an identical environment as the regular long-running processes of the app.
- Admin code must ship with application code to avoid synchronization issues.
13. API First
- We should define the service contract first to help our consumers understand what to send and receive, defining a common contract.
- This approach enables consumers and service developers to work in parallel.
- It helps avoid bottlenecks and facilitates the virtualization of the APIs so the consumers can run the tests against the mocks.
14. Telemetry
- Monitoring our microservices, containers, and env help us to scale, self-heal and manage alerts for end-users and platform operators.
- We can use machine learning towards those metrics to derive future business strategies.
- We can observe the application’s performance, stream of events and data, health checks, when the application starts, scales, and so on.
15. Authentication
- Make sure all security policies are in place. Developers tend to underestimate the importance that security has.
- APIs should be secured using OAuth, RBAC, etc.
- Web content should be exposed externally on HTTPS
- MFA
- Database protection