1. Code Organization and Structure
tornadobest-practicescode-organizationperformancesecurity
Description
Comprehensive best practices and coding standards for the Tornado framework. This rule provides guidelines on code organization, performance, security, testing, and common pitfalls when developing Tornado applications.
Globs
**/*.py
---
description: Comprehensive best practices and coding standards for the Tornado framework. This rule provides guidelines on code organization, performance, security, testing, and common pitfalls when developing Tornado applications.
globs: **/*.py
---
## 1. Code Organization and Structure
### 1.1. Directory Structure Best Practices
A well-structured directory layout enhances code maintainability and scalability. Consider the following structure:
project_name/
├── app/
│ ├── __init__.py
│ ├── handlers/
│ │ ├── __init__.py
│ │ ├── base_handler.py # Base class for handlers
│ │ ├── home_handler.py # Specific request handlers
│ │ ├── auth_handler.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── user.py # Data models
│ │ ├── packet.py
│ ├── services/
│ │ ├── __init__.py
│ │ ├── authentication_service.py # Business Logic
│ │ ├── packet_service.py
│ ├── utils/
│ │ ├── __init__.py
│ │ ├── database.py # Database connection and setup
│ │ ├── helpers.py # Utility functions
│ ├── config.py # Application configuration
│ ├── application.py # Tornado Application setup
│ └── main.py # Entry point for the application
├── tests/
│ ├── __init__.py
│ ├── test_handlers.py # Unit tests for handlers
│ ├── test_models.py # Unit tests for models
│ └── test_services.py # Unit tests for services
├── static/ # Static files (CSS, JavaScript, images)
├── templates/ # HTML templates
├── docs/ # Documentation
├── requirements.txt # Project dependencies
├── .env # Environment variables (development)
└── README.md
### 1.2. File Naming Conventions
* Use descriptive and consistent file names.
* Handlers: `home_handler.py`, `user_handler.py`
* Models: `user.py`, `product.py`
* Utilities: `database.py`, `string_utils.py`
* Tests: `test_handlers.py`, `test_models.py`
### 1.3. Module Organization
* Group related functionalities into modules.
* Keep modules focused and avoid creating overly large modules.
* Use clear and concise names for modules.
* Use packages (directories with `__init__.py`) to further organize modules.
### 1.4. Component Architecture
* **MVC (Model-View-Controller):** A common architectural pattern.
* **Models:** Represent data and business logic.
* **Views:** (Templates) Display data to the user.
* **Controllers (Handlers):** Handle user requests and interact with models.
* **Microservices:** Decompose the application into smaller, independent services.
* **Hexagonal Architecture (Ports and Adapters):** Isolates the core application logic from external dependencies.
### 1.5. Code Splitting
* **Split large handler files:** Decompose complex handlers into smaller, reusable functions or classes.
* **Modularize functionality:** Extract common logic into separate modules or services.
* **Lazy loading:** Import modules only when needed to reduce startup time. Avoid doing heavy imports at the top of the file. Consider `import tornado.ioloop` inside of a method if it's only used there.
## 2. Common Patterns and Anti-patterns
### 2.1. Design Patterns
* **Singleton:** For managing global resources like database connections.
* **Factory:** For creating instances of objects without specifying their concrete classes.
* **Observer:** For implementing event-driven architectures.
* **Template Method:** For defining a skeleton algorithm in a base class and letting subclasses implement specific steps.
* **Middleware:** Implement custom request processing logic (authentication, logging).
### 2.2. Recommended Approaches
* **Asynchronous Operations:** Leverage Tornado's asynchronous capabilities (using `async` and `await`) for non-blocking I/O operations. This includes database queries, API calls, and file system operations.
* **Use `IOLoop.add_callback` for thread safety:** When interacting with Tornado objects from other threads.
* **Configuration Management:** Utilize environment variables for storing configuration settings, adhering to the Twelve-Factor App methodology.
* **Logging:** Implement robust logging using Tornado's built-in logging capabilities.
* **Routing:** Utilize Tornado's routing system effectively by defining URL patterns and corresponding request handlers.
* **Authentication/Authorization:** Employ decorators like `@tornado.web.authenticated` for securing routes.
* **Use a BaseHandler class:** Encapsulate common logic, such as authentication checks, error handling, and template rendering.
### 2.3. Anti-patterns and Code Smells
* **Blocking I/O in Handlers:** Performing synchronous operations within request handlers will block the I/O loop, severely impacting performance. Always use asynchronous alternatives.
* **Ignoring Exceptions:** Catching exceptions without proper handling or logging can mask critical errors.
* **Overly Complex Handlers:** Large, monolithic handlers are difficult to maintain and test. Break them down into smaller, focused functions or classes.
* **Hardcoding Configuration:** Embedding configuration values directly in the code makes it difficult to manage and deploy the application across different environments. Use environment variables or configuration files.
* **Global State:** Over-reliance on global variables can lead to unpredictable behavior and make the code harder to reason about. Use dependency injection or other techniques to manage state explicitly.
* **Ignoring Thread Safety:** Tornado applications are single-threaded, but interactions with external resources might not be. Using `IOLoop.run_in_executor` is key to thread safety. If using WSGI containers, this becomes extremely important.
### 2.4. State Management
* **Stateless Handlers:** Design handlers to be stateless to improve scalability and fault tolerance.
* **Session Management:** Use signed cookies or external session stores (Redis, Memcached) for managing user sessions.
* **Caching:** Implement caching mechanisms (in-memory, Redis, Memcached) to reduce database load and improve response times.
* **Avoid Global Variables:** Minimize the use of global variables to prevent unintended side effects.
### 2.5. Error Handling
* **Centralized Error Handling:** Create a custom error handler (e.g., a base handler with error handling logic) to handle exceptions consistently across the application.
* **Logging:** Log all exceptions and errors with sufficient context (request details, user information).
* **Custom Error Pages:** Provide user-friendly error pages for common HTTP errors (404, 500).
* **Exception Propagation:** Allow exceptions to propagate to the Tornado error handler to ensure proper logging and handling.
* **Use `try...except` Blocks:** Wrap potentially failing code blocks in `try...except` blocks to gracefully handle errors.
## 3. Performance Considerations
### 3.1. Optimization Techniques
* **Asynchronous I/O:** Use asynchronous I/O operations to avoid blocking the I/O loop.
* **Connection Pooling:** Use connection pooling for database connections to reduce connection overhead. Libraries like SQLAlchemy provide this.
* **Caching:** Implement caching strategies to reduce database load and improve response times. Consider using `functools.lru_cache` for frequently called, pure functions.
* **Gzip Compression:** Enable Gzip compression for responses to reduce bandwidth usage.
* **Optimize Database Queries:** Ensure that database queries are efficient and properly indexed.
* **Minimize External Dependencies:** Reduce the number of external dependencies to minimize startup time and improve performance.
* **WebSockets**: Implement websockets using Tornado's native support for persistent connections to offload work from HTTP handlers.
### 3.2. Memory Management
* **Avoid Memory Leaks:** Be mindful of memory leaks, especially when dealing with long-lived connections or background tasks. Use tools like `memory_profiler` to identify and fix memory leaks.
* **Use Generators:** Use generators for processing large datasets to avoid loading the entire dataset into memory at once.
* **Object Pooling:** Use object pooling for frequently created objects to reduce object creation overhead.
* **Limit Object Sizes:** Avoid creating excessively large objects that can consume significant memory.
### 3.3. Rendering Optimization (If applicable)
* **Template Caching:** Cache compiled templates to reduce rendering overhead. Tornado automatically caches templates by default.
* **Minimize Template Logic:** Keep template logic simple and move complex calculations to the handler.
* **Use Template Inheritance:** Use template inheritance to reuse common template elements and reduce duplication.
* **Optimize Static Files:** Minimize, compress, and cache static files (CSS, JavaScript, images).
### 3.4. Bundle Size Optimization (If applicable)
* **Minify CSS and JavaScript:** Use tools like UglifyJS or CSSNano to minify CSS and JavaScript files.
* **Combine CSS and JavaScript:** Combine multiple CSS and JavaScript files into fewer files to reduce HTTP requests.
* **Use a CDN:** Serve static files from a Content Delivery Network (CDN) to improve loading times.
### 3.5. Lazy Loading
* **Lazy-load Modules:** Import modules only when needed to reduce startup time.
* **Lazy-load Images:** Load images only when they are visible in the viewport.
* **Lazy-load Data:** Fetch data only when it is needed.
## 4. Security Best Practices
### 4.1. Common Vulnerabilities
* **Cross-Site Scripting (XSS):** Sanitize user input to prevent XSS attacks.
* **SQL Injection:** Use parameterized queries or an ORM to prevent SQL injection attacks.
* **Cross-Site Request Forgery (CSRF):** Implement CSRF protection to prevent malicious websites from performing unauthorized actions on behalf of logged-in users. Tornado includes CSRF protection features.
* **Authentication and Authorization Flaws:** Implement robust authentication and authorization mechanisms to prevent unauthorized access to resources.
* **Session Hijacking:** Use secure cookies (HTTPOnly, Secure) and session management techniques to prevent session hijacking.
* **Denial of Service (DoS):** Implement rate limiting and other measures to prevent DoS attacks.
### 4.2. Input Validation
* **Validate All Input:** Validate all user input to prevent malicious data from entering the application.
* **Use Whitelisting:** Use whitelisting to define the allowed characters and formats for input fields.
* **Sanitize Input:** Sanitize input to remove or escape potentially dangerous characters.
* **Escape Output:** Escape output to prevent XSS attacks.
### 4.3. Authentication and Authorization
* **Use Strong Passwords:** Enforce strong password policies and use a secure hashing algorithm (bcrypt, Argon2) to store passwords.
* **Implement Two-Factor Authentication (2FA):** Use 2FA to add an extra layer of security to user accounts.
* **Use Role-Based Access Control (RBAC):** Implement RBAC to control access to resources based on user roles.
* **Principle of Least Privilege:** Grant users only the minimum privileges required to perform their tasks.
* **JSON Web Tokens (JWT):** Use JWT for stateless authentication.
### 4.4. Data Protection
* **Encrypt Sensitive Data:** Encrypt sensitive data at rest and in transit.
* **Use HTTPS:** Use HTTPS to encrypt communication between the client and server.
* **Store Secrets Securely:** Store secrets (API keys, database passwords) securely using environment variables or a secrets management system.
* **Regularly Rotate Secrets:** Rotate secrets regularly to reduce the risk of compromise.
### 4.5. Secure API Communication
* **Use HTTPS:** Enforce HTTPS for all API endpoints.
* **Implement API Authentication:** Use API keys, JWT, or OAuth 2.0 to authenticate API clients.
* **Rate Limiting:** Implement rate limiting to prevent abuse and DoS attacks.
* **Input Validation:** Validate all API input to prevent malicious data from entering the application.
* **Output Sanitization:** Sanitize API output to prevent XSS attacks.
## 5. Testing Approaches
### 5.1. Unit Testing
* **Test Individual Components:** Unit tests should focus on testing individual components (handlers, models, services) in isolation.
* **Use Mocking and Stubbing:** Use mocking and stubbing to isolate the component under test from its dependencies.
* **Test Edge Cases:** Test edge cases and boundary conditions to ensure that the component handles unexpected inputs correctly.
* **Follow Arrange-Act-Assert Pattern:** Structure unit tests using the Arrange-Act-Assert pattern.
* **Use `unittest` or `pytest`:** Python's built-in `unittest` module or the popular `pytest` framework are commonly used.
### 5.2. Integration Testing
* **Test Interactions Between Components:** Integration tests should focus on testing the interactions between different components of the application.
* **Use a Test Database:** Use a separate test database to avoid polluting the production database.
* **Test API Endpoints:** Test API endpoints to ensure that they function correctly and return the expected results.
* **Test Database Interactions:** Test database interactions to ensure that data is being read and written correctly.
### 5.3. End-to-End Testing
* **Test the Entire Application:** End-to-end tests should test the entire application from the user's perspective.
* **Use a Testing Framework:** Use a testing framework like Selenium or Cypress to automate end-to-end tests.
* **Test User Flows:** Test common user flows to ensure that the application functions correctly.
### 5.4. Test Organization
* **Organize Tests by Module:** Organize tests into separate files or directories for each module.
* **Use Descriptive Test Names:** Use descriptive test names to make it clear what each test is testing.
* **Keep Tests Independent:** Ensure that tests are independent of each other and can be run in any order.
### 5.5. Mocking and Stubbing
* **Use Mocking Libraries:** Use mocking libraries like `unittest.mock` or `pytest-mock` to create mock objects and stubs.
* **Mock External Dependencies:** Mock external dependencies (databases, APIs) to isolate the component under test.
* **Stub Complex Logic:** Stub complex logic to simplify the test and focus on the specific behavior being tested.
## 6. Common Pitfalls and Gotchas
### 6.1. Frequent Mistakes
* **Blocking the I/O Loop:** Performing synchronous operations in handlers.
* **Not Handling Exceptions Properly:** Ignoring or mishandling exceptions.
* **Incorrectly Using `async` and `await`:** Forgetting to `await` asynchronous calls.
* **Not Understanding Thread Safety:** Improperly accessing Tornado objects from threads.
* **Over-complicating handlers:** Making handlers too long and hard to understand.
### 6.2. Edge Cases
* **Handling Long-lived Connections:** Managing WebSocket connections and preventing memory leaks.
* **Dealing with Slow Clients:** Implementing timeouts and connection limits.
* **Handling Unexpected Input:** Validating and sanitizing user input.
* **Dealing with Network Errors:** Implementing retry logic and error handling.
### 6.3. Version-Specific Issues
* **Compatibility with Python Versions:** Ensuring compatibility with supported Python versions.
* **API Changes:** Being aware of API changes between Tornado versions.
* **Deprecated Features:** Avoiding the use of deprecated features.
### 6.4. Compatibility Concerns
* **WSGI Compatibility:** Understanding the limitations of WSGI integration.
* **Asynchronous Libraries:** Ensuring compatibility with other asynchronous libraries.
* **Database Drivers:** Using asynchronous database drivers compatible with Tornado.
### 6.5. Debugging Strategies
* **Logging:** Use extensive logging to track the flow of execution and identify errors.
* **Debugging Tools:** Use debugging tools like `pdb` or IDE debuggers to step through the code and inspect variables.
* **Profiling:** Use profiling tools to identify performance bottlenecks.
* **Monitoring:** Use monitoring tools to track the application's health and performance in production.
## 7. Tooling and Environment
### 7.1. Recommended Development Tools
* **IDE:** VS Code, PyCharm
* **Virtual Environment:** `venv`, `virtualenvwrapper`, `conda`
* **Package Manager:** `pip`, `uv`
* **Debugging Tools:** `pdb`, IDE debuggers
* **Profiling Tools:** `cProfile`, `memory_profiler`
* **Linting and Formatting:** `flake8`, `pylint`, `black`
* **Testing Frameworks:** `unittest`, `pytest`
### 7.2. Build Configuration
* **Use `requirements.txt`:** Specify project dependencies in a `requirements.txt` file.
* **Use `setup.py` or `pyproject.toml`:** For packaging and distributing the application.
* **Use a Build System:** Consider using a build system like `make` or `tox` to automate build tasks.
### 7.3. Linting and Formatting
* **Use a Linter:** Use a linter like `flake8` or `pylint` to enforce coding standards and identify potential errors.
* **Use a Formatter:** Use a formatter like `black` to automatically format the code according to PEP 8.
* **Configure Editor:** Configure the editor to automatically run the linter and formatter on save.
### 7.4. Deployment
* **Use a Production-Ready Server:** Deploy the application on a production-ready server like Gunicorn or uWSGI.
* **Use a Reverse Proxy:** Use a reverse proxy like Nginx or Apache to handle SSL termination, load balancing, and caching.
* **Use a Process Manager:** Use a process manager like Supervisor or systemd to manage the application process.
* **Use a Containerization Technology:** Consider using containerization technologies like Docker to package and deploy the application.
### 7.5. CI/CD Integration
* **Use a CI/CD System:** Use a CI/CD system like Jenkins, GitLab CI, GitHub Actions, or CircleCI to automate the build, test, and deployment processes.
* **Automate Testing:** Automate unit, integration, and end-to-end tests as part of the CI/CD pipeline.
* **Automate Deployment:** Automate the deployment process to reduce the risk of human error.
* **Implement Rollback Strategy:** Implement a rollback strategy to quickly revert to a previous version in case of errors.