Pular para conteúdo

RFC-003: Padrões de Código e Ferramentas de Linting

Campo Valor
Status Draft
Author Time de Tecnologia
Created 2026-02-05
Updated 2026-02-05
Reunião A ser agendada
Deciders Todo o time técnico

Status

🟡 Draft - RFC em elaboração, aguardando apresentação

Contexto e Problema

Embora já tenhamos padrões de código documentados em docs/development/coding-standards.md, falta formalização de:

  • Versões específicas das ferramentas obrigatórias
  • Enforcement automático via pre-commit hooks e CI/CD
  • Configurações padronizadas para todas as ferramentas
  • Processo de atualização de ferramentas e versões
  • Standards unificados para Django e FastAPI (coexistência)

Por que resolver isso agora?

  • Time crescendo, necessidade de consistência maior
  • Onboarding mais rápido com setup automatizado
  • Reduzir tempo em code review discutindo estilo
  • Prevenir bugs via análise estática
  • CI/CD mais confiável com quality gates claros

Impacto de não resolver

  • Código inconsistente entre desenvolvedores
  • Tempo perdido em code review com debates de estilo
  • Bugs evitáveis que passam sem linting
  • Setup de desenvolvimento manual e propenso a erros
  • Dificuldade em manter qualidade com time crescente

Documentação relacionada: - docs/development/coding-standards.md - Padrões atuais - docs/development/local-development.md - Setup de desenvolvimento - docs/cicd/github-actions.md - CI/CD pipelines - docs/testing/backend-testing.md - Standards de testes

Proposta de Solução

Padronizar e automatizar ferramentas de linting e formatting para Python (Django + FastAPI) e JavaScript/TypeScript.

Python (Django + FastAPI)

Ferramentas obrigatórias:

# pyproject.toml
[tool.black]
line-length = 100
target-version = ['py311']
include = '\.pyi?$'
extend-exclude = '''
/(
  # directories
  \.git
  | \.mypy_cache
  | \.venv
  | migrations
)/
'''

[tool.ruff]
line-length = 100
target-version = "py311"
select = [
    "E",  # pycodestyle errors
    "W",  # pycodestyle warnings
    "F",  # pyflakes
    "I",  # isort
    "B",  # flake8-bugbear
    "C4", # flake8-comprehensions
    "UP", # pyupgrade
]
ignore = [
    "E501",  # line too long (handled by black)
    "B008",  # do not perform function calls in argument defaults
    "C901",  # too complex (handled case by case)
]

[tool.ruff.per-file-ignores]
"__init__.py" = ["F401"]  # unused import
"tests/**/*.py" = ["S101"]  # assert usage in tests is ok

[tool.ruff.isort]
known-first-party = ["app"]

[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
plugins = ["pydantic.mypy"]

[[tool.mypy.overrides]]
module = "tests.*"
disallow_untyped_defs = false

Versões fixas (requirements-dev.txt):

black==24.1.1
ruff==0.1.15
mypy==1.8.0
pytest==8.0.0
pytest-cov==4.1.0
pytest-django==4.7.0  # Para Django
pytest-asyncio==0.23.3  # Para FastAPI

JavaScript/TypeScript (Frontend)

Ferramentas obrigatórias:

// .eslintrc.json
{
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:react/recommended",
    "plugin:react-hooks/recommended",
    "prettier"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 2021,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "rules": {
    "@typescript-eslint/explicit-module-boundary-types": "off",
    "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
    "react/react-in-jsx-scope": "off",
    "react/prop-types": "off"
  },
  "settings": {
    "react": {
      "version": "detect"
    }
  }
}

// .prettierrc.json
{
  "semi": true,
  "trailingComma": "es5",
  "singleQuote": true,
  "printWidth": 100,
  "tabWidth": 2,
  "useTabs": false,
  "arrowParens": "avoid"
}

Versões fixas (package.json):

{
  "devDependencies": {
    "eslint": "^8.56.0",
    "@typescript-eslint/eslint-plugin": "^6.19.0",
    "@typescript-eslint/parser": "^6.19.0",
    "eslint-plugin-react": "^7.33.2",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-config-prettier": "^9.1.0",
    "prettier": "^3.2.4"
  }
}

Pre-commit Hooks

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v4.5.0
    hooks:
      - id: trailing-whitespace
      - id: end-of-file-fixer
      - id: check-yaml
      - id: check-added-large-files
      - id: check-json
      - id: check-merge-conflict
      - id: detect-private-key

  - repo: https://github.com/psf/black
    rev: 24.1.1
    hooks:
      - id: black
        language_version: python3.11

  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.1.15
    hooks:
      - id: ruff
        args: [--fix, --exit-non-zero-on-fix]

  - repo: https://github.com/pre-commit/mirrors-mypy
    rev: v1.8.0
    hooks:
      - id: mypy
        additional_dependencies: [pydantic]

  - repo: https://github.com/pre-commit/mirrors-prettier
    rev: v3.1.0
    hooks:
      - id: prettier
        types_or: [javascript, jsx, ts, tsx, json, yaml, markdown]

CI/CD Quality Gates

# .github/workflows/lint.yml
name: Lint

on: [push, pull_request]

jobs:
  python-lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install dependencies
        run: |
          pip install black ruff mypy

      - name: Black check
        run: black --check .

      - name: Ruff check
        run: ruff check .

      - name: MyPy check
        run: mypy app/ --ignore-missing-imports

  javascript-lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install dependencies
        run: npm ci

      - name: ESLint check
        run: npm run lint

      - name: Prettier check
        run: npm run format:check

Quality Gates (Bloqueantes)

Bloqueia merge se: - ❌ Black check falhar - ❌ Ruff check falhar com erros (warnings são ok) - ❌ MyPy falhar em arquivos novos/modificados - ❌ ESLint falhar - ❌ Prettier check falhar

Alternativas Consideradas

Opção 1: Pylint ao invés de Ruff

Descrição: Usar Pylint como linter principal para Python

Prós: - Mais maduro e estabelecido - Mais checks disponíveis - Ampla adoção

Contras: - Muito mais lento (10-100x mais lento que Ruff) - Configuração mais complexa - Muitos false positives - Ruff já cobre maioria dos checks importantes

Custo/Esforço: Médio

Por que não escolhemos: Ruff é muito mais rápido (escrito em Rust), cobre 90% dos casos de Pylint, e tem melhor experiência de desenvolvedor.

Opção 2: Flake8 ao invés de Ruff

Descrição: Usar Flake8 + múltiplos plugins

Prós: - Ferramenta tradicional e conhecida - Muitos plugins disponíveis - Configuração familiar

Contras: - Mais lento que Ruff - Requer múltiplos plugins (isort, flake8-bugbear, etc.) - Ruff já engloba tudo em uma ferramenta - Menos mantido ativamente

Custo/Esforço: Médio

Por que não escolhemos: Ruff oferece tudo que Flake8 oferece (e mais) em uma única ferramenta, muito mais rápida.

Opção 3: ESLint + Standard ao invés de Prettier

Descrição: Usar apenas ESLint com regras de formatação

Prós: - Uma ferramenta a menos - ESLint já faz linting

Contras: - ESLint formatting é mais lento - Prettier é opinativo (menos configuração) - Prettier suporta mais formatos (JSON, Markdown, YAML) - Comunidade converge para ESLint + Prettier

Custo/Esforço: Baixo

Por que não escolhemos: Prettier + ESLint é o padrão da indústria e oferece melhor experiência.

Opção 4: Linting manual (sem enforcement)

Descrição: Apenas documentar padrões sem ferramentas obrigatórias

Prós: - Zero overhead de ferramentas - Máxima flexibilidade - Sem falsos positivos

Contras: - Inconsistência garantida - Tempo perdido em code review - Bugs evitáveis passam - Não escala com time crescente

Custo/Esforço: Zero

Por que não escolhemos: Não é viável para time crescente. Automação é essencial para qualidade e produtividade.

Análise de Impacto

Impacto Técnico

Times afetados: - Todo time de desenvolvimento - CI/CD pipeline (novos checks) - Onboarding (novo setup)

Sistemas afetados: - Repositórios Git (pre-commit hooks) - GitHub Actions (novos workflows) - IDEs (configurações recomendadas)

Dependências: - Instalar ferramentas localmente (todos os devs) - Configurar IDEs (opcional mas recomendado) - Atualizar CI/CD pipelines

Impacto em Negócio

  • Qualidade de código consistente e alta
  • Code review mais rápido (menos debates de estilo)
  • Onboarding mais rápido (setup automatizado)
  • Menos bugs via análise estática
  • Produtividade aumentada (menos tempo com estilo)
  • ⚠️ Setup inicial (1-2 horas por desenvolvedor)
  • ⚠️ CI/CD mais lento (+2-3 minutos por run)

Riscos Identificados

Risco 1: Falsos positivos bloqueiam desenvolvimento

  • Mitigação: Configurações bem ajustadas, possibilidade de ignores pontuais (# noqa, // eslint-disable-next-line)
  • Impacto: Médio
  • Probabilidade: Baixa

Risco 2: Ferramentas com bugs travam CI

  • Mitigação: Versões fixas, testar updates em branch separada
  • Impacto: Alto
  • Probabilidade: Muito Baixa

Risco 3: Resistência do time a ferramentas

  • Mitigação: Demonstrar benefícios, coletar feedback, ajustar configurações
  • Impacto: Médio
  • Probabilidade: Baixa

Plano de Implementação

Fase 1: Configuração (Semana 1)

Tasks: - [ ] Criar pyproject.toml com configurações Black, Ruff, MyPy - [ ] Criar .eslintrc.json e .prettierrc.json - [ ] Criar .pre-commit-config.yaml - [ ] Adicionar versões fixas em requirements-dev.txt e package.json - [ ] Atualizar .gitignore com artefatos de ferramentas

Responsável: Tech Lead
Prazo estimado: 2 dias

Fase 2: Formatação Inicial (Semana 1)

Tasks: - [ ] Rodar Black em toda a codebase - [ ] Rodar Prettier em toda a codebase - [ ] Commit de formatação: "style: apply black and prettier formatting" - [ ] Configurar git blame para ignorar commit de formatação

Responsável: Tech Lead
Prazo estimado: 1 dia

Fase 3: CI/CD (Semana 1-2)

Tasks: - [ ] Criar workflow .github/workflows/lint.yml - [ ] Configurar como required check em branch protection - [ ] Testar em PR de exemplo - [ ] Documentar processo de bypass (emergências)

Responsável: DevOps
Prazo estimado: 1 dia

Fase 4: Setup do Time (Semana 2)

Tasks: - [ ] Documentar instalação de pre-commit hooks - [ ] Criar guia de configuração de IDE (VS Code, PyCharm) - [ ] Sessão de treinamento (1h) - [ ] Pair programming para troubleshooting

Responsável: Tech Lead
Prazo estimado: 2 dias

Fase 5: Monitoramento (Semanas 3-4)

Tasks: - [ ] Monitorar adoção (pre-commit hooks instalados?) - [ ] Coletar feedback sobre falsos positivos - [ ] Ajustar configurações se necessário - [ ] Documentar casos especiais

Responsável: Todo o time
Prazo estimado: Contínuo

Métricas de Sucesso

Após 1 mês

  • ✅ 100% dos PRs passam em linting checks
  • ✅ 90%+ do time usa pre-commit hooks
  • ✅ Zero debates de estilo em code review
  • ✅ Tempo médio de code review reduzido em 20%

Após 3 meses

  • ✅ Onboarding 50% mais rápido (setup automatizado)
  • ✅ Bugs relacionados a type errors reduzidos em 30%
  • ✅ Codebase 100% formatada consistentemente
  • ✅ Time confortável com ferramentas

Após 6 meses

  • ✅ Zero PRs com problemas de formatação
  • ✅ Ferramentas atualizadas pelo menos 1x
  • ✅ Feedback positivo do time sobre produtividade

Referências