https://12factor.net/ # Lesson: The Twelve-Factor App Methodology ## Introduction The Twelve-Factor App is a set of principles for building software-as-a-service applications that are robust, scalable, and easy to deploy. It was created by developers at Heroku, a cloud platform as a service (PaaS) that has been used to deploy hundreds of thousands of applications. ## Objectives By the end of this lesson, you should be able to: - Understand the twelve factors that make up the methodology. - Apply these factors to improve the design and deployment of web applications using Flask (Python) and Node.js. ## The Twelve Factors Here's a brief overview of each factor with specific examples for Flask and Node.js: ### I. Codebase **One codebase tracked in revision control, many deploys** - **Flask & Node.js**: Use Git for version control. Each microservice or component of your application should have its own repository if they are deployed independently. ### II. Dependencies **Explicitly declare and isolate dependencies** - **Flask**: Use a `requirements.txt` file or a Pipfile (when using pipenv) to declare dependencies. - **Node.js**: Declare your dependencies in a `package.json` file. ### III. Config **Store config in the environment** - **Flask**: Use environment variables with `os.environ` or the `python-dotenv` package. - **Node.js**: Use the `dotenv` package to load environment variables. ### IV. Backing services **Treat backing services as attached resources** - **Flask & Node.js**: Use environment variables to store URLs and credentials for backing services like databases, and treat them as attached resources that can be replaced without code changes. ### V. Build, release, run **Strictly separate build and run stages** - **Flask & Node.js**: Use Docker containers to package your application and its dependencies. Use continuous integration and continuous deployment (CI/CD) pipelines to automate the build and release process. ### VI. Processes **Execute the app as one or more stateless processes** - **Flask & Node.js**: Ensure that any data that needs to persist is stored in a stateful backing service like a database, not in the process's memory. ### VII. Port binding **Export services via port binding** - **Flask**: Use Gunicorn or another WSGI server to bind to a port provided by the environment. - **Node.js**: Bind to a port provided by the environment using `process.env.PORT`. ### VIII. Concurrency **Scale out via the process model** - **Flask & Node.js**: Use a process manager like Gunicorn (for Flask) or PM2 (for Node.js) to run multiple instances of your application. ### IX. Disposability **Maximize robustness with fast startup and graceful shutdown** - **Flask & Node.js**: Ensure that your application can start quickly and that it can shut down gracefully by handling SIGTERM signals. ### X. Dev/prod parity **Keep development, staging, and production as similar as possible** - **Flask & Node.js**: Use Docker to maintain consistency across environments. Use environment variables to manage any differences. ### XI. Logs **Treat logs as event streams** - **Flask & Node.js**: Write logs to `stdout` and `stderr`. Do not concern the app with routing or storage of logs. ### XII. Admin processes **Run admin/management tasks as one-off processes** - **Flask & Node.js**: Use scripts that can be run from the command line for tasks like database migrations. These should be run as one-off processes in the execution environment. ## Examples ### Flask Example: Environment Configuration ```python from flask import Flask import os app = Flask(__name__) app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY') # Rest of the Flask app... ``` ### Node.js Example: Dependency Declaration and Process Management ```javascript // package.json snippet { "dependencies": { "express": "^4.17.1", "dotenv": "^8.2.0" } } // server.js require('dotenv').config(); const express = require('express'); const app = express(); const PORT = process.env.PORT || 3000; app.listen(PORT, () => console.log(`Server running on port ${PORT}`)); // Rest of the Node.js app... ``` ## Cheat Sheet - **Codebase**: One codebase per service, tracked in version control. - **Dependencies**: Declare and isolate dependencies explicitly. - **Config**: Store configuration in the environment. - **Backing Services**: Treat backing services as attached resources. - **Build, Release, Run**: Separate build and run stages. - **Processes**: Execute the app as one or more stateless processes. - **Port Binding**: Export services via port binding. - **Concurrency**: Scale out via the process model. - **Disposability**: Fast startup and graceful shutdown. - **Dev/Prod Parity**: Keep development, staging, and production as similar as possible. - **Logs**: Treat logs as event streams. - **Admin Processes**: Run admin/management tasks as one-off processes. ## Exercise Create a simple CRUD (Create, Read, Update, Delete) application using Flask or Node.js applying the twelve-factor methodology. Ensure that: - Your codebase is tracked in Git. - All dependencies are explicitly declared. - Configuration is stored in environment variables. - You can run your application using a process manager. - You write logs to `stdout` and `stderr`. - You can execute a database migration as a one-off process. ## Additional Resources - [Flask Documentation](https://flask.palletsprojects.com/en/2.0.x/) - [Node.js Documentation](https://nodejs.org/en/docs/) - [The Twelve-Factor App](https://12factor.net/) Remember, the key to mastering the Twelve-Factor App methodology is consistent practice and application in real-world projects. Try to refactor an existing project or start a new one with these principles in mind.