Este documento recoge las reglas del
Google Python Style Guide
que ruff no puede imponer automáticamente, además de las
invariantes arquitectónicas específicas de esta plantilla.
Lo que sí se automatiza está en pyproject.toml (ruff) y en tach.toml
(boundaries). Lo que sigue debe respetarse manualmente y revisarse en
code review.
- Line length: 88 (Google = 80). Adoptamos el default de Black/ruff por alineamiento con el ecosistema moderno.
- Indent: 4 espacios (Google permite 2 o 4). PEP 8 y default de toda la herramienta Python.
Estas reglas las fuerza tach check. No deben relajarse:
app.domainnunca importa deapp.adaptersniapp.entrypoint.app.adaptersno importa deapp.entrypoint.- No se permiten dependencias circulares entre módulos.
- Cualquier paquete nuevo bajo
src/app/debe declararse entach.tomlcon susdepends_onexplícitos.
Reglas adicionales no automatizadas:
- Las dependencias externas (typer, requests, sqlalchemy, etc.) viven
solo en
adapters/oentrypoint/, nunca endomain/. - Los fakes/mocks de test viven en
tests/conftest.pyo en archivos bajotests/, nunca ensrc/. - El mapeo de excepciones de dominio al canal de salida (códigos de
salida, colores, formatos) vive solo en
entrypoint/cli.py. El dominio no conocetyper.Exit.
- No usar metaclases salvo justificación arquitectónica explícita.
- No usar reflexión dinámica (
getattr/setattrcon strings derivados de input externo) sin comentario que la justifique. - No monkey-patchear módulos de terceros.
- No usar import hooks ni manipular
sys.modules.
- No introducir
threading/multiprocessingsin justificación documentada en el PR. - Preferir
concurrent.futuresoasynciosobrethreading.Threadpelado. - Estructuras compartidas: usar
queue.Queueo equivalentes thread-safe.
ruff con convention = "google" cubre formato y secciones, pero estas
reglas son cualitativas:
- Módulos: docstring de una línea como mínimo.
- Clases públicas: docstring con sección
Attributes:cuando aplique. - Funciones públicas: secciones
Args:,Returns:,Raises:cuando apliquen. - Funciones privadas (
_foo): pueden omitir secciones pero conservan un resumen. - No documentar tipos en docstring si ya están en la anotación.
- TODOs siempre con autor:
# TODO(usuario): descripción de qué falta. - Comentarios en frases completas, con mayúscula inicial y punto final.
- Esta plantilla usa español por preferencia del autor; mantener consistencia dentro del proyecto.
- Toda excepción propia hereda de
app.domain.errors.DomainError. except:desnudo está prohibido (ruff BLE001lo bloquea, pero también aplica aexcept Exception:sin justificación).- No usar excepciones para flujo de control normal.
- El mapeo
DomainError → typer.Exitvive solo enentrypoint/cli.py.
- Prohibido. Toda dependencia llega por inyección (puertos + wiring).
- Constantes en
UPPER_CASEson aceptables si son inmutables.
- Evitar clases anidadas salvo factory patterns claros.
- Closures solo cuando capturan estado relevante; si no, sacar a top-level.
@propertysolo para acceso O(1) sin side effects observables.- Si la propiedad puede fallar o es costosa, usar un método
get_*()explícito.
ruff B006lo bloquea, pero recordatorio: usarNonecomo sentinela y construir el default dentro del cuerpo.
- Solo para callbacks de una línea pasados a
sorted,map, etc. - Nunca asignar una lambda a un nombre (usar
def). Lo cubreE731.
- Una sola expresión ternaria por línea. Anidadas → usar
if/else.
- Siempre absolutos (
ruff TID252configurado). - Orden: stdlib, third-party, local (lo gestiona
I). - Un import por línea.
- Obligatorias en toda función pública y atributos públicos de clases
(
ruff ANN). Anysolo en interfaces dinámicas justificadas (ANN401enignore).- Preferir
typing.Protocolsobre ABCs para puertos.
- Si una función excede ~40 líneas, considerar partirla.
ruff PLR0915da una señal pero no cubre todos los casos; revisar en code review.
print()está prohibido en código de producción (ruff T201).- Toda salida al usuario pasa por un adapter (p. ej.
ConsoleGreeter). - Para logs internos:
logging.getLogger(__name__)con lazy formatting:logger.info("user %s", user_id). f-strings dentro de log calls los bloquearuff G004.
ruff N cubre la mayoría. Convenciones:
module_name,package_nameClassName,ExceptionNamefunction_name,method_nameGLOBAL_CONSTANT_NAMEglobal_var_name,instance_var_name,function_parameter_name,local_var_name- "Interno": prefijo
_. Módulos internos: prefijo_en el nombre del archivo.
Cuando se añada un nuevo caso de uso o adapter:
- Seguir los pasos de "Cómo añadir un nuevo comando" del README.
- Si se introduce un paquete nuevo bajo
src/app/, registrarlo entach.tomlcon susdepends_onexplícitos. Sin esto,tach checkfalla. - Nunca añadir
app.adaptersoapp.entrypointadepends_ondeapp.domain. Esa es la invariante que protege la arquitectura.