Python Best Practices developed by Dmitry Mugtasimov during the course of his 26-year career in software engineering.
DISCLAIMER: This repository documents Python best practices as I have developed and refined them over 26 years of professional software engineering. They reflect my experience, reasoning, and approach to building and maintaining software, and are shared as a practical reference rather than as a definitive or universal standard. As with any engineering guidance, their applicability may vary depending on context, constraints, and goals.
DISCLAIMER 2: This is "work in progress" repository. If you did not find something you might have expected then it is just not written yet.
You can contact me via:
- Email: dmugtasimov@gmail.com
- X: @dmugtasimov
- Telegram: @dmugtasimov
- Python - programming language
- Django - web framework
- Django REST Framework (alternatively FastAPI + SQLAlchemy + Alembic) - REST API framework
- Celery - distributed task queue
- PostgreSQL - relational database
- RabbitMQ - message broker
- Redis - in-memory data store
- uv (earlier Poetry + pyenv) - package management
- Docker + Docker Compose - containerization platform
- Pulumi - infrastructure as code
- Sentry - error tracking
- AWS - cloud platform
- Uvicorn, Gunicorn - application servers
- NGINX (or Traefik for containerized deployments) - load balancer and reverse proxy
- Let's Encrypt - SSL/TLS certificate authority
- GitHub Actions - CI/CD platform
- PyCharm - IDE
- AI coding assistants
- Linear (alternatively - GitHub Projects) - project management
- pytest - testing framework
- diff-cover - test coverage tool
- pre-commit - git hook manager
- Ruff (earlier Flake8, Pylint) - linting and formatting
- GNU Make - command automation
- model-bakery - fixture factory
- ngrok - local tunneling service
- VCR.py - HTTP interaction recording
- Moto - AWS service mocking
- pdbpp - enhanced debugger
- colorlog - colored logging
- django-split-settings - settings organization
- django-restql - GraphQL-like API queries
- django-dirtyfields - model field change tracking
- WhiteNoise - static file serving
- Anymail - email service integration
- python-jose - JWT library
- Jinja - template engine
- time-machine - time mocking for tests
- Pydantic - data validation
- tqdm - progress bars
- cachetools - caching utilities
- HTTPX (preferred over Requests) - HTTP client
- Tenacity - retry library
- Beautiful Soup - HTML/XML parser
- Liquid - template engine
- Respect best practices
- Respect industry standards
- Respect backward compatibility
- Respect forward compatibility
- Write code to be read by humans (and AI), not just to be executed
- Continuous refactoring
- Continuous Learning
- Use AI for coding as much as possible
- Review and refactor AI-generated code
- The Less code (lines) the better
- DRY (Don't Repeat Yourself)
- KISS (Keep It Simple, Stupid)
- YAGNI (You Aren't Gonna Need It)
- Principle of Least Astonishment
- Code reuse
- Encapsulation
- Have a reason behind every decision
- Respect business needs over technical preferences
- Automate repetitive tasks
- Unit testing
- Consistency
- and more...
- Start new project with latest dependencies if possible
- Declare and assign variable values as close to the usages as possible
- Do not put a value to a variable if it is then read just once
- Do not implement logic that depends on environment name the code is running in
- Do not hard code a list of environments
- Avoid dead code
- Self and AI code review
- Use comments and docstrings reasonably
- Use asserts to describe expected invariants and assumptions in the code
- Use TODO or FIX comments to describe technical debt and convey intended imperfections to other developers
- Implement database schema changes and related business logic in the same pull request
- Use consistent data attributes naming
- Assign or declare variables as close to their usage as possible
- and more...
- Follow PEP 8 coding style guide, read more here
- In except clause always prefer
.exception()over.error()logger method, unless you have a good reason for otherwise - Use keyword arguments for arguments with default values. Call
def f(arg='default'):withf(arg='value')instead off('value'). - and more...