Skip to content

Tool Selection Decision Trees

This guide helps you make informed decisions about which tools and patterns to use in different scenarios.

Python Version Selection

graph TD
    A[New Project?] --> B{Production deployment<br/>in next 6 months?}
    B -->|Yes| C[Python 3.13]
    B -->|No| D[Python 3.14-beta]
    A --> E{Existing Project?}
    E --> F{Python version <br/>end-of-life?}
    F -->|Yes| G[Upgrade to 3.13<br/>Plan migration]
    F -->|No| H{Version < 3.11?}
    H -->|Yes| I[Consider upgrading<br/>3.11+ has major improvements]
    H -->|No| J[Stay on current<br/>version]

Recommendation: Use Python 3.13+ for all new projects. It's stable, fast, and supported.


Dependency Management

graph TD
    A[Choose Dependency Tool] --> B{Team Experience}
    B -->|New to Python| C[uv<br/>Fastest, simplest]
    B -->|Experienced| D{Project Type}
    D -->|Application| E[uv<br/>Great for apps]
    D -->|Library| F[Poetry<br/>Better for publishing]
    D -->|Existing pip-tools| G{Want to migrate?}
    G -->|Yes| E
    G -->|No| H[Keep pip-tools<br/>If working well]

Recommendation: Use uv for application development. It's 10-100x faster than pip and simpler than Poetry.

When to use Poetry: Publishing Python packages to PyPI, need advanced dependency resolution features.


Linting & Formatting

graph TD
    A[Code Quality Tools] --> B[Use Ruff]
    B --> C{Need additional checks?}
    C -->|Yes| D[Add Pylint for<br/>specific checks]
    C -->|No| E[Ruff alone<br/>is sufficient]
    A --> F{Legacy project?}
    F -->|Uses Black/flake8| G[Migrate to Ruff<br/>10-100x faster]
    F -->|Happy with tools| H[Consider Ruff<br/>when revisiting]

Recommendation: Use Ruff for all new projects. It replaces Black, isort, flake8, and many plugins.

Migration: Ruff is compatible with Black/flake8 configs. Migration is usually painless.


Testing Framework

graph TD
    A[Testing Framework] --> B[pytest]
    B --> C{Django Project?}
    C -->|Yes| D[pytest-django]
    C -->|No| E[pytest alone]
    E --> F{API testing?}
    F -->|Yes| G[Add pytest-vcr]
    F -->|No| H[pytest + coverage]
    D --> I{UI Testing?}
    I -->|Yes| J[Add Playwright]
    I -->|No| K[pytest-django only]

Recommendation: Always use pytest. It's the industry standard with excellent plugins.

Coverage Goal: Aim for 80%+ (be pragmatic). 100% coverage doesn't guarantee quality.


Task Runner

graph TD
    A[Task Automation] --> B{Simple tasks?}
    B -->|Yes| C[just<br/>Simple, fast]
    B -->|Complex| D[just with<br/>Python scripts]
    A --> E{Existing Makefile?}
    E -->|Working well| F[Keep Makefile]
    E -->|Want better DX| G[Migrate to just]
    A --> H{Python-heavy tasks?}
    H -->|Yes| I[just + Python<br/>Best of both worlds]

Recommendation: Use just for new projects. Cleaner syntax than Make, cross-platform.

When to use Make: CI/CD environments that expect Makefiles, team strongly prefers Make.


Development Environment

graph TD
    A[Dev Environment] --> B{Team Size}
    B -->|1 developer| C{Preference?}
    C -->|Local| D[venv + direnv]
    C -->|Containerized| E[Devcontainers]
    B -->|2+ developers| F[Devcontainers<br/>Consistency matters]
    B -->|Remote team| G[Devcontainers<br/>Works everywhere]
    A --> H{Complex dependencies?}
    H -->|Yes| I[Devcontainers<br/>Easier to manage]
    H -->|No| J[Either works]

Recommendation: Use devcontainers for team projects. Ensures everyone has identical environments.

When to skip: Solo projects, very simple apps, or if Docker adds too much overhead.


Database for Django

graph TD
    A[Database Choice] --> B{Multi-tenant?}
    B -->|Yes| C[MySQL<br/>Better tenant isolation]
    B -->|No| D{Team Experience}
    D -->|PostgreSQL fans| E[PostgreSQL<br/>Rich features]
    D -->|MySQL fans| F[MySQL<br/>Proven, reliable]
    D -->|No preference| G[PostgreSQL<br/>More Django features]
    A --> H{Full-text search?}
    H -->|Yes| I[PostgreSQL<br/>Built-in FTS]
    H -->|No| J[Either works]

Recommendation: PostgreSQL for most projects. MySQL if multi-tenant or team has MySQL expertise.

Multi-tenant: MySQL's database-level isolation can be simpler than schema-based approaches.


Secret Management

graph TD
    A[Secrets Management] --> B{Deployment Target}
    B -->|AWS| C[AWS SSM<br/>Parameter Store]
    B -->|Other Cloud| D{Which cloud?}
    D -->|GCP| E[Secret Manager]
    D -->|Azure| F[Key Vault]
    D -->|Multi-cloud| G[HashiCorp Vault]
    A --> H{Development}
    H --> I[.env files<br/>Never commit!]
    C --> J{Cost sensitive?}
    J -->|Yes| C
    J -->|No| K[AWS Secrets Manager<br/>Rotation features]

Recommendation: Use AWS SSM Parameter Store for AWS deployments. Free for standard parameters, integrated with ECS.

Development: Always use .env files locally, document in .env.example.


Frontend Stack (Django)

graph TD
    A[Frontend Approach] --> B{App Type}
    B -->|Admin/Internal| C[Django Templates]
    C --> D[TailwindCSS]
    D --> E[HTMX for<br/>interactivity]
    E --> F[Alpine.js for<br/>complex UI state]
    B -->|Public/Complex| G{Team Skills}
    G -->|JS-heavy| H[React/Vue SPA<br/>+ Django API]
    G -->|Python-first| I[Django + HTMX<br/>Less complexity]

Recommendation: Use TailwindCSS + HTMX + Alpine.js for Django projects. Avoids heavy JavaScript frameworks.

When to use React/Vue: Highly interactive UIs, real-time features, or team has strong JS skills.


CI/CD Platform

graph TD
    A[CI/CD Platform] --> B{Code Hosting}
    B -->|GitHub| C[GitHub Actions<br/>Free for public repos]
    B -->|GitLab| D[GitLab CI<br/>Built-in]
    B -->|Bitbucket| E[Bitbucket Pipelines]
    A --> F{AWS Deployment?}
    F -->|Yes| G[GitHub Actions +<br/>AWS CodeDeploy]
    F -->|No| H[GitHub Actions<br/>alone]

Recommendation: Use GitHub Actions for GitHub-hosted repos. Well-integrated with AWS.

Cost: Free for public repos, generous free tier for private repos.


Deployment Strategy

graph TD
    A[Deployment Target] --> B{Traffic Level}
    B -->|Low| C[AWS ECS Fargate<br/>Serverless containers]
    B -->|Medium| D[AWS ECS EC2<br/>More control]
    B -->|High| E[EKS<br/>Kubernetes]
    A --> F{Team Expertise}
    F -->|Docker only| G[ECS Fargate]
    F -->|Kubernetes| H[EKS]
    F -->|Neither| I[Learn ECS first<br/>Simpler than K8s]

Recommendation: Use AWS ECS Fargate for most Django apps. Simpler than Kubernetes, scales well.

When to use EKS: Very high scale, need Kubernetes-specific features, or multi-cloud strategy.


Monitoring & Observability

graph TD
    A[Monitoring] --> B[Error Tracking]
    B --> C[Sentry<br/>Essential]
    A --> D[Logs]
    D --> E{AWS Deployment?}
    E -->|Yes| F[CloudWatch Logs]
    E -->|No| G[Provider's solution]
    A --> H[Metrics]
    H --> I{Budget}
    I -->|Limited| J[CloudWatch<br/>Included with AWS]
    I -->|Generous| K[DataDog or<br/>New Relic]

Recommendation: - Errors: Sentry (best-in-class error tracking) - Logs: CloudWatch (if on AWS) - Metrics: CloudWatch for basics, upgrade later if needed


Decision Guidelines

Making Tool Choices

  1. Start simple: Choose the simplest tool that meets your needs
  2. Team consensus: Get buy-in from the team
  3. Evaluate periodically: Tools improve, re-evaluate yearly
  4. Document decisions: Use ADRs for significant choices
  5. Don't over-engineer: Premature optimization is real

Avoid

  • Chasing the newest tools without evaluation
  • Using different tools across similar projects (increases cognitive load)
  • Adopting tools no one on the team knows
  • Tools without active maintenance

Further Reading