Por Jose R. Zapata
Ultima actualización: 6/Mar/2025
Contexto
“Indeed, the ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code. …[Therefore,] making it easy to read makes it easier to write.” - Robert C. Martin (Clean Code)
“Buggy code is bad science. Poorly tuned benchmarks are bad science. Poorly factored code is bad science (hinders reproducibility, increases chances of a mistake). If your field is all about empirical validation, then your code is a large part of your scientific output.” - François Chollet (keras creator)
https://x.com/fchollet/status/1018396455533506560
Code Quality Tools
Linters
Los linters son herramientas que analizan el código fuente para señalar errores de programación, errores estilísticos y problemas de diseño. Los linters son estáticos, lo que significa que no ejecutan el código. En su lugar, examinan el código fuente sin ejecutarlo. Los linters son útiles para detectar errores antes de ejecutar el código.
Ejemplos: Pylint, Flake8, Ruff
Formatters
Los formateadores son herramientas que reformatean el código fuente para cumplir con un estilo de codificación específico. Los formateadores son útiles para mantener un estilo de codificación consistente en un proyecto.
Los formatters no modifican el comportamiento del código. Ayuda a mantener la consistencia del código y lo hace más legible.
Ejemplos: Black, Ruff, isort, autopep8.
Static Typing
Python es un lenguaje de programación dinámico, lo que significa que no es necesario especificar el tipo de una variable. Sin embargo, a veces es útil especificar el tipo de una variable para ayudar a detectar errores en tiempo de compilación. Ademas, ayuda a documentar el código y permite a los desarrolladores entender mejor el código.
Ejemplos: Mypy
Security
La seguridad es un aspecto importante de la calidad del código. Los errores de seguridad pueden tener consecuencias graves, como la exposición de datos sensibles o la interrupción de un servicio. Es importante utilizar herramientas de seguridad para detectar errores de seguridad en el código de python.
Recomendación para linter y formatter
Se recomienda usar Ruff como linter y formatter para proyectos de Python. Ruff es una herramienta de calidad de código que combina linters, formatters y otras herramientas de calidad de código en un solo paquete. Ruff es fácil de configurar y usar, y es compatible con la mayoría de los editores de código.
Pre-commit
pre-commit es una herramienta que permite ejecutar linters, formatters y otras herramientas de calidad de código antes de realizar un commit en un repositorio de Git. pre-commit es útil para mantener la calidad del código en un proyecto. puede ejecutar validaciones de:
- Formato de código
- Errores de programación
- Errores de seguridad
- Tests
- Documentación
- etc.
Integracion pre-commit en CI/CD
Para integrar los checks de pre-commit en los pipelines de CI/CD se puede usar workflows de github actions si el código está en github y el proyecto esta gestionado con UV.
Agregar el siguiente archivo: .pre-commit-config.yaml
repos:
- repo: <https://github.com/pre-commit/pre-commit-hooks>
rev: v5.0.0
hooks:
- id: check-yaml
exclude: ^(mkdocs\.yml|{{cookiecutter.repo_name}}/mkdocs\.yml)$
- id: check-case-conflict
- id: debug-statements
- id: detect-private-key
- id: check-merge-conflict
- id: check-added-large-files
args: [--maxkb=100000] # 100MB
- repo: <https://github.com/astral-sh/ruff-pre-commit>
# Ruff version
rev: v0.9.9
hooks:
# Run the linter
- id: ruff
args:
- --fix
- --config
- .code_quality/ruff.toml # Run the formatter.
- id: ruff-format
args:
- --config
- .code_quality/ruff.toml
- repo: <https://github.com/pre-commit/mirrors-mypy>
rev: v1.15.0
hooks:
- id: mypy
args:
- --config-file=.code_quality/mypy.ini
- repo: <https://github.com/Yelp/detect-secrets>
rev: v1.5.0
hooks:
- id: detect-secrets
exclude: ^(poetry\.lock|\.cruft\.json|.*\.ipynb)$
- id: detect-secrets
name: 'detect-secrets-jupyter'
args: ['--exclude-files', '.*[^i][^p][^y][^n][^b]$', '--exclude-lines', '"(hash|id|image/\w+)":.*', ]
- repo: <https://github.com/commitizen-tools/commitizen>
rev: v4.4.1
hooks:
- id: commitizen
- id: commitizen-branch
stages: [pre-push]
Las reglas de calidad de codigo crear el archivo: .code_quality/ruff.toml
# Exclude a variety of commonly ignored directories.
exclude = [
".bzr",
".direnv",
".eggs",
".git",
".git-rewrite",
".hg",
".mypy_cache",
".nox",
".pants.d",
".pytype",
".ruff_cache",
".svn",
".tox",
".venv",
"__pypackages__",
"_build",
"buck-out",
"build",
"dist",
"node_modules",
"venv",
"old",
"env",
".env",
".venv",
"migrations",
]
#same as black
line-length = 100
indent-width = 4
# Assume Python 3.11
target-version = "py311"
# Include ipython notebooks
extend-include = ["*.ipynb"]
[lint]
select = [
# flake8-bugbear
"B",
# mccabe
"C90",
# pycodestyle
"E",
# pyflakes
"F",
# warnings
"W",
# pylint
"PL",
# isort
"I",
# flake8-bandit
"S",
# pyupgrade
"UP",
# ruff
"RUF",
# flake8-simplify
"SIM",
# tryceratops
"TRY",
]
ignore = [
"E203",
# bandit: Use of `assert` detected
"S101"
]
# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []
[format]
# Like Black, use double quotes for strings.
quote-style = "double"
# Like Black, indent with spaces, rather than tabs.
indent-style = "space"
# Like Black, respect magic trailing commas.
skip-magic-trailing-comma = false
# Like Black, automatically detect the appropriate line ending.
line-ending = "auto"
# Enable auto-formatting of code examples in docstrings.
docstring-code-format = true
[lint.mccabe]
# Unlike Flake8, default to a complexity level of 10.
max-complexity = 10
y para mypy crear el archivo: .code_quality/mypy.ini
[mypy]
show_error_codes = True
warn_return_any = True
warn_unused_configs = True
disallow_untyped_defs = True
disallow_untyped_calls = True
check_untyped_defs = True
ignore_missing_imports = True
Clean Code (Buenas Prácticas)
Modularización
Se base en dividir el código en componentes más pequeños y manejables. La modularización facilita la reutilización del código y y facilita su mantenimiento.
- Colaboración: Permite que varios científicos de datos trabajen en el mismo proyecto de manera más eficiente.
- Depuración: Simplifica la identificación y resolución de errores.
- Flexibilidad: Permite actualizar o cambiar partes del código sin afectar todo el proyecto.
Testing (Imprescindible)
- Esenciales para la calidad y confiabilidad del código
- Identifican errores temprano, ahorrando tiempo y dinero
- Aseguran el correcto funcionamiento del código
- Tipos de pruebas: Unitarias, de Integración, Funcionales, etc.
Code Review (Revisión de Código)
Pull Request: Fomenta la calidad del software al permitir discusiones y mejoras buscando un proceso de desarrollo más sólido y confiable.
Además, es beneficioso para todos, ya que tiende a tener efectos positivos en la cultura del equipo de trabajo.
Don’t Repeat Yourself (DRY)
- Evita la duplicación de código.
- Promueve la reutilización de código mediante funciones, clases y módulos.
- Reduce la cantidad de código que hay que mantener.
- Cambios en un solo lugar.
Single Responsibility Principle
- Cada clase debe tener un propósito bien definido y enfocado.
- Facilita el mantenimiento y la depuración del código.
- Mejora la legibilidad y la organización del código.
- Clases más pequeñas y fáciles de entender.
Keep It Simple S (KISS)
- Centrarse en soluciones simples y directas.
- Evitar la complejidad innecesaria.
- La simplicidad facilita el mantenimiento y la depuración.
- Código más fácil de entender y modificar.
Diapositivas
Referencias
- https://medium.com/analytics-vidhya/clean-code-the-art-of-writing-good-code-for-data-science-3085af715177
- https://code.visualstudio.com/docs/python/linting
- https://devblogs.microsoft.com/oldnewthing/20070406-00/?p=27343
- https://realpython.com/python-testing/
- https://medium.com/palantir/code-review-best-practices-19e02780015f
- https://realpython.com/python-refactoring/
- https://books.agiliq.com/projects/essential-python-tools/en/latest/linters.html
- https://realpython.com/python-code-quality/
Python Anti-Patterns
- https://docs.quantifiedcode.com/python-anti-patterns/index.html
- https://deepsource.com/blog/8-new-python-antipatterns
- https://medium.com/@koushik5586/common-python-anti-patterns-to-watch-out-for-815a94f97e79