Saltar a contenido

2.5.-Documentar el código

2.5. Documentación del código en Python

Idea principal

Documentar no consiste en llenar el programa de comentarios. Consiste en hacer explícitos su propósito, su contrato y las decisiones que no pueden deducirse con seguridad leyendo solo las instrucciones.

Un programa se escribe una vez, pero se lee muchas veces: cuando se corrige un error, se añade una funcionalidad, se incorpora otra persona al equipo o se intenta reutilizar una biblioteca. Por eso la documentación forma parte de la calidad del software y no debe dejarse para el final.

En este tema distinguiremos comentar de documentar, aprenderemos a usar los comentarios y las docstrings de Python y veremos qué información debe acompañar a un proyecto. El recorrido empieza con la justificación y la motivación; después pasa a la escritura concreta de comentarios y documentación.

El tema se relaciona principalmente con el RA 3 del módulo de Programación:

Código Descripción literal de la normativa
RA 3 Escribe y depura código, analizando y utilizando las estructuras de control del lenguaje.
CE 3.g Se ha comentado y documentado el código.

Se trabajan los criterios que tienen que ver con la documentación de código, incluyendo comentarios, docstrings y documentación de proyectos. La documentación debe ser clara, útil y mantenible, y debe explicar el propósito, el contrato y las decisiones del código.

Qué deberías saber al terminar

Al acabar este tema deberías poder:

  • explicar por qué la documentación es parte de un software de calidad;
  • distinguir comentarios, docstrings, anotaciones de tipo, README y documentación de proyecto;
  • escribir comentarios breves que expliquen intención, decisiones y restricciones sin repetir el código;
  • documentar módulos, funciones, clases, métodos y scripts con docstrings;
  • elegir una convención de docstrings y mantenerla en todo el proyecto;
  • preparar una documentación adecuada para proyectos privados, compartidos y públicos.

Mapa del tema

En este documento seguiremos esta progresión:

  1. justificación, motivación y audiencias de la documentación;
  2. comentarios útiles frente a comentarios redundantes;
  3. docstrings, tipos de objetos y formatos de documentación en Python;
  4. documentación de proyectos, herramientas, buenas prácticas y práctica.

1. Por qué debemos documentar el código

1.1. El código se lee más veces de las que se escribe

Guido van Rossum, creador de Python, resumió una realidad cotidiana del desarrollo:

“Code is more often read than written.”

—Guido van Rossum

Cuando escribes código te diriges, al menos, a dos audiencias:

  • las personas que utilizarán el programa o la biblioteca;
  • las personas que mantendrán el código, incluida tu versión futura.

Es normal que, meses después, no recuerdes por qué una variable tenía un valor concreto, por qué se eligió un algoritmo o qué supuesto hacía válida una condición. Si a ti te cuesta reconstruir la decisión, a otra persona del equipo le costará aún más.

Una biblioteca sin documentación

Imagina que encuentras una biblioteca que parece resolver exactamente tu problema. Sin ejemplos, explicación de parámetros ni documentación oficial, tendrás que estudiar toda su implementación para saber cómo usarla. Es posible que decidas no utilizarla, aunque te ahorrase mucho trabajo.

Daniele Procida expresa esta idea de forma directa:

“It doesn’t matter how good your software is, because if the documentation is not good enough, people will not use it.”

—Daniele Procida

1.2. Un sistema sin documentación está incompleto

Un sistema de calidad debe comunicar, como mínimo:

  • por qué existen sus módulos, clases y funciones;
  • qué problema resuelve cada parte;
  • cómo se utiliza;
  • qué datos acepta y qué resultado produce;
  • qué efectos secundarios, restricciones o errores pueden aparecer.

Sin esta información, modificar un sistema existente se convierte en una investigación costosa. Para usar una función sin documentación hay que leer su implementación y deducir su comportamiento; para mantenerla, además, hay que adivinar qué pretendía hacer quien la escribió.

La documentación debe estar lo más cerca posible del código al que se refiere. Un comentario, una docstring o un ejemplo versionado junto al código es más fácil de encontrar y actualizar que un documento perdido en una carpeta de la nube. Para la documentación de usuario o de un proyecto completo también puede existir un sitio especializado, como MkDocs, Sphinx, Read the Docs o Docusaurus, pero esos sistemas deben construirse a partir de información controlada y mantenida.

Puedes documentar, entre otras cosas:

  • decisiones de diseño;
  • la razón de existir y el funcionamiento de una parte no evidente;
  • las interfaces públicas y ejemplos de uso;
  • los efectos de utilizar una función o módulo;
  • limitaciones conocidas, código pendiente y mejoras posibles mediante TODO o FIXME con contexto.

Documentación

La documentación es la información que explica el propósito, el uso, el contrato, las decisiones y las restricciones de un software para que otras personas puedan utilizarlo, mantenerlo o ampliarlo.

1.3. Documentar ayuda a diseñar

John Ousterhout, en A Philosophy of Software Design, propone utilizar los comentarios también como herramienta de diseño. Antes de implementar una función o módulo, explicar en lenguaje natural su propósito, interfaz y efectos permite comprobar si el diseño es lógico y suficiente.

Esta técnica es especialmente útil para la interfaz: obliga a ponerse en el lugar de quien utilizará el código. Si no puedes escribir una descripción corta y concreta de cómo se usa una pieza o por qué existe, quizá debas replantear su diseño antes de programarla.

flowchart TD
    A["Necesidad del programa"] --> B["Explicar propósito e interfaz"]
    B --> C{"¿El diseño se entiende?"}
    C -->|"No"| D["Revisar responsabilidades y uso"]
    D --> B
    C -->|"Sí"| E["Implementar código claro"]
    E --> F["Añadir comentarios y docstrings útiles"]
    F --> G["Publicar README y documentación del proyecto"]

Los comentarios no sustituyen al diseño, pero escribirlos pronto puede revelar una interfaz confusa antes de invertir tiempo en una implementación difícil de mantener.

1.4. El lenguaje de programación no expresa todas las decisiones

Python permite expresar con precisión el comportamiento ejecutable, pero no resulta práctico codificar todas las razones, restricciones y decisiones del equipo. El código suele explicar cómo se realiza una operación; la documentación puede explicar por qué se realiza de esa forma.

No es un fracaso necesitar una explicación en lenguaje natural. Es una decisión correcta cuando el comentario aporta una información que el código no puede expresar de forma clara y razonable. Lo que debemos evitar es usar comentarios como sustituto habitual de nombres, funciones y estructuras comprensibles.

2. Comentar no es lo mismo que documentar

Ambos conceptos están relacionados, pero no tienen exactamente el mismo objetivo:

Elemento Audiencia principal Qué explica Dónde aparece
Comentario Personas que leen y mantienen el código Intención, decisión, algoritmo o limitación local Junto a una instrucción o bloque
Docstring Personas que usan o mantienen una API Contrato, parámetros, retorno, excepciones y ejemplos En módulos, clases, funciones y métodos
README Personas que llegan al proyecto Propósito, instalación y uso inicial Raíz del repositorio
Guía o referencia Personas usuarias o desarrolladoras Procedimientos, conceptos y API completa Carpeta o sitio de documentación

Jeff Atwood lo resume así:

“Code tells you how; Comments tell you why.”

—Jeff Atwood

Aclaración

La frontera no es absoluta: una docstring también puede servir a una persona desarrolladora y un README puede incluir información técnica. Lo importante es identificar a quién va dirigida la información y colocarla donde esa persona la buscará.

2.1. Comentarios con #

En Python, un comentario comienza con # y el intérprete no ejecuta el texto que aparece después en esa línea:

def hello_world():
    # Explica la intención de la salida para quien lee el ejemplo.
    print("Hello World")

También puede aparecer al final de una instrucción, aunque conviene reservar los comentarios en línea para aclaraciones muy breves:

edad = 25  # Edad expresada en años, no en meses.

PEP 8 recomienda limitar las líneas de código a 79 caracteres y las líneas de comentarios o docstrings a 72 cuando se trata de texto con menos restricciones estructurales. No es una regla del intérprete, sino una convención que facilita leer diferencias, editores y terminales. Si una explicación es larga, divídela en varias líneas:

def hello_long_world():
    # La salida es deliberadamente larga porque se usa para probar
    # el ajuste de línea del terminal, no porque sea un saludo habitual.
    print("Hellooooooooooooooooooooooooooooooooooooooooooooooooooooooo World")

2.2. Para qué puede servir un comentario

Los comentarios pueden cumplir funciones distintas:

  • Planificación y revisión: permiten anotar pasos antes de implementar una funcionalidad. Deben eliminarse o transformarse en documentación definitiva después de revisar y probar el código.

    # 1. Validar la configuración.
    # 2. Intentar la conexión.
    # 3. Informar del resultado.
    

Una práctica especialmente útil consiste en escribir primero la explicación de la interfaz: propósito, forma de uso, efectos y restricciones. Esto permite detectar un diseño confuso antes de programarlo. No significa que todo comentario deba escribirse antes del código, sino que la documentación también puede ser una herramienta de diseño y revisión.

  • Intención de un bloque: explica una decisión que no resulta obvia al leer las instrucciones.

    # Se conserva la configuración anterior para permitir reintentar
    # la conexión sin pedir de nuevo todos los datos.
    
  • Descripción algorítmica: resume la estrategia, su complejidad o el motivo de elegir un algoritmo cuando esos datos son relevantes.

    # Usamos quicksort porque el conjunto suele estar en memoria y
    # necesitamos un buen rendimiento medio.
    
  • Etiquetado de trabajo pendiente: TODO, FIXME o BUG ayudan a localizar problemas conocidos. Deben incluir una descripción concreta y no convertirse en una lista de promesas olvidadas.

    # TODO: gestionar explícitamente la configuración ausente.
    

2.3. Escribe comentarios que aporten información

La regla práctica es: comenta el porqué, no repitas el qué.

# Redundante: el código ya expresa la operación.
x = x + 1  # Incrementar x en 1

# Útil: explica una decisión externa al código.
x = x + 1  # Compensar el índice basado en 1 de la API heredada.

# Redundante: el nombre y el literal son suficientes.
usuarios = []  # Crear una lista vacía

# Útil: explica el motivo de conservar la colección.
usuarios = []  # Caché para evitar consultas repetidas durante la sesión.

Antes de añadir un comentario sobre la implementación, pregúntate si puedes mejorar el código: cambia x por un nombre descriptivo, extrae una función o divide una expresión compleja. Si después de esa mejora sigue siendo necesaria la explicación, escríbela de forma breve y cercana al código.

Las decisiones cambian

Un comentario incorrecto o desactualizado puede ser peor que no tenerlo. Cada vez que cambies el comportamiento de un bloque, revisa también los comentarios, las docstrings, los ejemplos y el README relacionado.

2.4. Cuatro reglas para comentarios mantenibles

Estas reglas, difundidas por Jeff Atwood, son una guía práctica:

  1. Mantén el comentario cerca del código que describe. Una explicación alejada se pasa por alto y se desincroniza con facilidad.
  2. Evita formatos complejos, como tablas de caracteres o dibujos ASCII. Suelen distraer y son difíciles de mantener.
  3. No incluyas información redundante. Supón que quien lee conoce la sintaxis básica de Python y explica solo lo que no puede deducir con seguridad.
  4. Diseña el código para que sea legible por sí mismo: nombres expresivos, funciones pequeñas y estructuras claras reducen la necesidad de comentarios.

2.5. Las anotaciones de tipo también comunican

Las anotaciones de tipo, disponibles desde Python 3.5, hacen más explícito el contrato de una función:

def hello_name(name: str) -> str:
    return f"Hello {name}"

Al leer la cabecera se entiende que name se espera como texto y que la función devuelve texto. En Python moderno también pueden anotarse colecciones:

def procesar_nombres(nombres: list[str]) -> int:
    return len(nombres)


def obtener_configuracion() -> dict[str, int]:
    return {"timeout": 30, "reintentos": 3}

Las anotaciones son información accesible, por ejemplo, mediante funcion.__annotations__, pero Python no las valida automáticamente en cada llamada ni garantiza que el valor cumpla el tipo. Herramientas como mypy o Pyright pueden analizarlas. Por tanto, los type hints complementan las docstrings y la validación explícita; no las sustituyen.

2.6. Las cadenas triples no son comentarios

Una cadena entre triples comillas ("""...""" o '''...''') es un literal de cadena. Se convierte en docstring únicamente cuando es la primera instrucción de un módulo, una clase o una función. Una cadena suelta en cualquier otro lugar no es un comentario y no debe usarse como sustituto habitual de #:

def sumar(a: int, b: int) -> int:
    """Devuelve la suma de dos enteros."""  # Esta sí es una docstring.
    return a + b


# Para una anotación temporal o local, usa un comentario real.
resultado = sumar(2, 3)  # Se conserva para mostrar el ejemplo.

Las triples comillas son la convención de Python para docstrings porque permiten escribir texto de una o varias líneas. No significa que toda cadena triple sea documentación ni que una cadena independiente sea ignorada como un comentario.

3. Docstrings: documentación integrada en Python

3.1. Qué es una docstring

Una docstring es una cadena de documentación asociada automáticamente al primer literal de cadena del cuerpo de un módulo, una clase, una función o un método. Python la expone mediante el atributo __doc__, y la función help() la muestra en la consola. Las herramientas de documentación pueden leerla para generar una referencia de API.

def say_hello(name: str) -> None:
    """Imprime un saludo personalizado."""
    print(f"Hello {name}, is it me you're looking for?")


print(say_hello.__doc__)
help(say_hello)

La docstring debe estar inmediatamente después de la cabecera del objeto que documenta. Python también permite asignar manualmente __doc__ en objetos definidos por el programa, aunque escribirla en su posición natural es más legible:

def say_hello(name: str) -> None:
    print(f"Hello {name}, is it me you're looking for?")


say_hello.__doc__ = "Imprime un saludo personalizado."

Los objetos integrados pueden impedir esa asignación:

>>> str.__doc__ = "Una nueva documentación para str"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot set '__doc__' attribute of immutable type 'str'

También puedes consultar la documentación de objetos incorporados:

>>> dir(str)
['__add__', ..., '__doc__', ..., 'zfill']
>>> print(str.__doc__)
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str
...

3.2. Convenciones de PEP 257

PEP 257 establece convenciones para que las docstrings sean reconocibles y consistentes. No obliga a describir cada línea interna ni impone un formato completo para parámetros, pero sí recomienda que sean concisas, útiles y fáciles de mantener.

Para una docstring de una sola línea, escribe un resumen completo en una línea, normalmente con triples comillas dobles:

"""Devuelve el área de un rectángulo."""

Una docstring más extensa puede seguir este patrón:

def calcular_area_rectangulo(ancho: float, alto: float) -> float:
    """Calcula el área de un rectángulo.

    La unidad del resultado es el cuadrado de la unidad recibida.
    """
    return ancho * alto

La primera línea resume el comportamiento; una línea en blanco separa el resumen de la ampliación. Las líneas de texto deberían respetar la recomendación de 72 caracteres de PEP 8 cuando sea razonable.

Una docstring de una interfaz pública suele describir:

  • qué hace y para qué sirve;
  • qué significan sus argumentos, incluidos los opcionales y sus valores por defecto;
  • qué devuelve y en qué condiciones;
  • qué excepciones puede producir;
  • qué efectos secundarios tiene;
  • qué restricciones o precondiciones deben cumplirse;
  • ejemplos de uso si aclaran el contrato.

3.3. Docstrings de funciones y métodos

Este ejemplo usa el formato Google Style, sencillo y adecuado para empezar:

def calcular_promedio(numeros: list[float]) -> float:
    """Calcula el promedio de una lista de números.

    Args:
        numeros: Lista de números que se va a promediar.

    Returns:
        El promedio de los valores recibidos.

    Raises:
        ValueError: Si la lista está vacía.
    """
    if not numeros:
        raise ValueError("La lista no puede estar vacía.")
    return sum(numeros) / len(numeros)

La función comunica su contrato sin obligar a leer la implementación. Si una función tiene un efecto secundario, como escribir un fichero o modificar una colección recibida, debe indicarlo expresamente.

3.4. Docstrings de clases y métodos

La docstring de una clase resume qué representa, su comportamiento y sus atributos públicos. Cada método público puede tener su propia docstring. Los parámetros del constructor se documentan en __init__ o en la docstring de la clase, siguiendo la convención elegida para el proyecto.

class Animal:
    """Representa un animal y el sonido que puede emitir.

    Attributes:
        name: Nombre del animal.
        sound: Sonido utilizado por defecto.
        num_legs: Número de patas; por defecto es 4.
    """

    says_template = "{name} dice {sound}"

    def __init__(self, name: str, sound: str | None, num_legs: int = 4) -> None:
        """Inicializa un animal.

        Args:
            name: Nombre del animal.
            sound: Sonido por defecto; puede ser `None`.
            num_legs: Número de patas, que por defecto es 4.
        """
        self.name = name
        self.sound = sound
        self.num_legs = num_legs

    def says(self, sound: str | None = None) -> None:
        """Muestra el nombre y el sonido del animal.

        Args:
            sound: Sonido alternativo. Si se omite, se usa el predeterminado.

        Raises:
            NotImplementedError: Si no existe ningún sonido disponible.
        """
        if self.sound is None and sound is None:
            raise NotImplementedError("No se admiten animales silenciosos.")

        out_sound = self.sound if sound is None else sound
        print(self.says_template.format(name=self.name, sound=out_sound))

En una clase más grande también conviene documentar la interfaz prevista para subclases, las propiedades que deben mantenerse coherentes y los métodos que pueden sobrescribirse.

3.5. Docstrings de módulos y paquetes

La docstring de un módulo se coloca al principio del archivo, antes de los import. Debe explicar el propósito del módulo y puede enumerar las clases, excepciones y funciones principales que ofrece:

"""Utilidades geométricas para figuras planas.

El módulo ofrece `Rectangulo`, `Circulo` y funciones de cálculo de áreas.
"""

import math

La docstring de un paquete se coloca al principio de __init__.py. Puede explicar qué proporciona el paquete y qué submódulos o nombres forman parte de su interfaz pública. La documentación de cada función del módulo debe incluir los mismos elementos que la de un método: propósito, argumentos, retorno, efectos, excepciones y restricciones.

3.6. Docstrings de scripts ejecutables

Un script ejecutado desde la consola debe explicar qué hace, cómo se invoca, qué argumentos acepta y qué dependencias necesita. Si utiliza argparse, esa información puede integrarse en la descripción y en la ayuda de cada argumento:

"""Muestra las columnas de una hoja de cálculo.

Admite ficheros CSV y Excel (`.xls`, `.xlsx`). Requiere instalar `pandas`.
"""

import argparse


def main() -> None:
    """Procesa los argumentos y muestra las columnas solicitadas."""
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("input_file", help="Fichero de hoja de cálculo")
    args = parser.parse_args()
    print(f"Procesando {args.input_file}")


if __name__ == "__main__":
    main()

La condición if __name__ == "__main__" permite importar el módulo sin ejecutar el programa automáticamente. Las dependencias propias o de terceros, como pandas, deben aparecer en la documentación de instalación y en los ficheros de dependencias del proyecto.

3.7. Un script completo con una biblioteca externa

El siguiente ejemplo conserva el caso de una utilidad para obtener cabeceras de hojas de cálculo. La docstring del módulo explica el uso del script y la de la función documenta sus parámetros y retorno:

"""Imprime las cabeceras de una hoja de cálculo.

Admite ficheros CSV y Excel (`.xls`, `.xlsx`). Requiere `pandas`.
También puede importarse como módulo; ofrece `get_spreadsheet_cols` y `main`.
"""

import argparse
from pathlib import Path

import pandas as pd


def get_spreadsheet_cols(file_loc: str, print_cols: bool = False) -> list[str]:
    """Obtiene y, opcionalmente, muestra las cabeceras de una hoja.

    Args:
        file_loc: Ruta del fichero de hoja de cálculo.
        print_cols: Si es `True`, muestra las cabeceras en la consola.

    Returns:
        Lista de nombres de columna.

    Raises:
        ValueError: Si la extensión no es `.csv`, `.xls` o `.xlsx`.
    """
    extension = Path(file_loc).suffix.lower()
    if extension == ".csv":
        file_data = pd.read_csv(file_loc)
    elif extension in {".xls", ".xlsx"}:
        file_data = pd.read_excel(file_loc)
    else:
        raise ValueError("El fichero debe ser CSV o Excel.")

    col_headers = list(file_data.columns)

    if print_cols:
        print("\n".join(col_headers))

    return col_headers


def main() -> None:
    """Lee la ruta de la línea de órdenes y muestra sus columnas."""
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("input_file", help="Fichero cuyas columnas se mostrarán")
    args = parser.parse_args()
    get_spreadsheet_cols(args.input_file, print_cols=True)


if __name__ == "__main__":
    main()

4. Formatos y documentación de proyectos Python

4.1. Elegir un formato de docstring

No existe un único formato obligatorio para describir parámetros y retornos. Lo importante es elegir uno que entiendan las herramientas del proyecto y aplicarlo de forma coherente. Estos son formatos habituales:

Formato Características Soporte habitual
Google Style Sintaxis Args, Returns y Raises, fácil de leer. Sphinx mediante extensiones y otras herramientas.
reStructuredText Formato muy integrado con el ecosistema de Sphinx. Sphinx y Docutils.
NumPy/SciPy Secciones con títulos como Parameters y Returns. NumPyDoc y Sphinx.
Epytext Adaptación usada por Epydoc. Epydoc y herramientas compatibles.

Los ejemplos siguientes documentan la misma función con estilos distintos:

4.1.1. Google Style
"""Obtiene las cabeceras de una hoja de cálculo.

Args:
    file_loc (str): Ruta del fichero.
    print_cols (bool): Si muestra las cabeceras en consola.

Returns:
    list[str]: Nombres de las columnas.
"""
4.1.2. Texto reestructurado
"""Obtiene las cabeceras de una hoja de cálculo.

:param file_loc: Ruta del fichero.
:type file_loc: str
:param print_cols: Si muestra las cabeceras en consola.
:type print_cols: bool
:returns: Nombres de las columnas.
:rtype: list[str]
"""
4.1.3. NumPy/SciPy
"""Obtiene las cabeceras de una hoja de cálculo.

Parameters
----------
file_loc : str
    Ruta del fichero.
print_cols : bool, optional
    Si muestra las cabeceras en consola.

Returns
-------
list[str]
    Nombres de las columnas.
"""
4.1.4. Epytext
"""Obtiene las cabeceras de una hoja de cálculo.

@type file_loc: str
@param file_loc: Ruta del fichero.
@type print_cols: bool
@param print_cols: Si muestra las cabeceras en consola.
@rtype: list[str]
@returns: Nombres de las columnas.
"""

4.2. Estructura orientativa de un proyecto

La documentación depende del tamaño, del tipo de usuarios y del nivel de colaboración. Una raíz de proyecto puede organizarse así:

project_root/
├── project/              # Código fuente del paquete
├── tests/                # Pruebas automatizadas
├── docs/                 # Tutoriales, guías y referencia
├── README.md             # Primer contacto con el proyecto
├── HOW_TO_CONTRIBUTE.md  # Cómo colaborar
├── CODE_OF_CONDUCT.md    # Normas de convivencia
├── LICENSE               # Licencia
└── examples.py           # Ejemplos sencillos de uso

No todos los proyectos necesitan todos estos ficheros. El principio práctico es documentar lo que otra persona necesita para instalar, utilizar, mantener o contribuir al proyecto.

4.2.1. Proyectos privados

Un proyecto privado puede necesitar una documentación ligera:

  • README.md: propósito, requisitos y forma de instalación o ejecución;
  • examples.py o una carpeta examples/: usos sencillos;
  • comentarios y docstrings para decisiones que puedan resultar confusas en el futuro.

Aunque solo lo utilices tú, también eres una persona usuaria. Tu versión futura agradecerá saber qué necesita instalar y qué supuestos utiliza el programa.

4.2.2. Proyectos compartidos

Cuando colaboran varias personas, conviene añadir:

  • cambios importantes entre versiones;
  • instrucciones para empezar a contribuir;
  • convenciones de código, pruebas y revisión;
  • ejemplos que permitan comprobar rápidamente la instalación.

El objetivo es reducir el tiempo de incorporación y evitar que cada persona tenga que descubrir las reglas del proyecto leyendo todo su código.

4.2.3. Proyectos públicos y de código abierto

Un proyecto público debe conceder a la documentación una prioridad semejante a la del desarrollo. El README.md suele incluir propósito, requisitos, instalación, uso, ejemplos, cambios importantes, enlaces a la documentación, forma de informar de errores y licencia. Además, suelen ser necesarios:

  • Contribución: cómo proponer cambios, pruebas o documentación;
  • código de conducta: comportamiento esperado en la comunidad;
  • licencia: condiciones para utilizar y redistribuir el software;
  • docs/: documentación ampliada organizada por necesidades.
4.2.4. Un README.md mínimo
# Mi proyecto

Descripción breve del problema que resuelve.

## Instalación

```bash
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```

## Uso

```python
from mi_proyecto import funcion_principal

resultado = funcion_principal()
print(resultado)
```

## Contribuir

1. Crea una rama.
2. Añade código y pruebas.
3. Comprueba el formato y ejecuta la suite.
4. Abre una solicitud de cambios.

## Licencia

MIT

4.3. Las cuatro necesidades de docs/

Daniele Procida propone separar la documentación de un proyecto en cuatro tipos. No son cuatro niveles de calidad, sino cuatro formas de ayudar a la persona lectora:

  • Tutoriales: guían paso a paso a quien está aprendiendo.
  • Guías prácticas: resuelven una tarea concreta mediante una receta.
  • Referencias: ofrecen información precisa para consultar mientras se programa, como una API o una tabla de opciones.
  • Explicaciones: ayudan a comprender conceptos, arquitectura y decisiones.
Tipo de contenido Más útil al estudiar Más útil al programar
Paso práctico Tutoriales Guías prácticas
Conocimientos teóricos Explicaciones Referencias

Separar estos objetivos evita que un tutorial para principiantes se convierta en una lista de detalles de API o que una referencia técnica obligue a seguir una secuencia didáctica innecesaria.

4.4. Herramientas y recursos

Herramienta Uso principal
Sphinx Generar documentación a partir de fuentes y docstrings.
Epydoc Generar referencia de API Python a partir de docstrings.
Read the Docs Crear, versionar y alojar documentación automáticamente.
Doxygen Generar documentación para varios lenguajes, incluido Python.
MkDocs Crear sitios estáticos con Markdown; este repositorio utiliza MkDocs Material.
Pycco Mostrar código y documentación uno junto a otro.
pydoc Consultar o generar documentación de módulos Python.
Docusaurus Construir sitios de documentación, especialmente en el ecosistema JavaScript.

También es útil estudiar proyectos bien documentados, como Django, Requests, Click y Pandas.

4.5. Recursos para profundizar

Los siguientes recursos amplían las ideas del tema y conservan referencias útiles del material original:

4.6. Cómo empezar si el proyecto no tiene documentación

La documentación de un proyecto suele evolucionar en esta progresión:

  1. Sin documentación.
  2. Alguna documentación.
  3. Documentación completa.
  4. Buena documentación.
  5. Gran documentación.

No es necesario resolverlo todo de una vez. Si no existe ningún documento, empieza por un README.md con el propósito, los requisitos y un ejemplo de ejecución. Después añade las docstrings de la interfaz pública, guías para tareas frecuentes y referencia técnica. La constancia es más útil que intentar escribir una enciclopedia que nadie pueda mantener.

5. Buenas prácticas

Para trabajar con documentación con criterio profesional, conviene aplicar estas pautas:

  • Empieza por la interfaz: escribe cómo se usa, por qué existe y qué efectos produce antes de describir detalles internos.
  • Explica el porqué: documenta decisiones, restricciones, algoritmos no obvios y soluciones temporales; el código ya expresa normalmente qué hace.
  • Escribe código legible: usa nombres descriptivos, funciones pequeñas y estructuras sencillas para que el programa se explique a sí mismo.
  • Documenta la interfaz pública: incluye parámetros, retorno, excepciones, efectos secundarios, restricciones y ejemplos cuando aporten valor.
  • Elige una convención: Google, reStructuredText, NumPy/SciPy y Epytext son opciones válidas si las herramientas del proyecto las soportan; no las mezcles sin una razón clara.
  • Mantén la documentación cerca y actualizada: trata comentarios, docstrings, README y guías como parte del código revisado.
  • Automatiza cuando compense: integra linters, comprobadores de tipos, doctest, pruebas y generadores de documentación en el flujo del proyecto.
  • Adapta el esfuerzo al contexto: un script privado no necesita la misma documentación que una biblioteca pública, pero sí debe dejar claras sus dependencias y decisiones difíciles de recordar.
  • Protege la información sensible: no incluyas contraseñas, tokens ni datos personales en comentarios, ejemplos, capturas o documentación publicada.

6. Errores frecuentes

Error frecuente Por qué ocurre Cómo evitarlo
Comentar cada línea obvia. Se confunde documentar con traducir el código a lenguaje natural. Usa nombres claros y comenta solo la intención no evidente.
Usar cadenas con """ como si fueran comentarios. Se olvida que una cadena suelta es una expresión y solo ciertas posiciones crean docstrings. Usa # para comentarios y reserva las triples comillas para docstrings.
Documentar solo el nombre de una función. Se describe que existe, pero no su contrato. Explica parámetros, retorno, excepciones, efectos y restricciones.
Colocar mal una docstring. Solo el primer literal de un módulo, clase o función se convierte automáticamente en __doc__. Colócala inmediatamente después de la cabecera correspondiente.
Afirmar que un type hint valida el valor. Python no comprueba automáticamente las anotaciones en cada llamada. Valida explícitamente y usa mypy o Pyright si es necesario.
Mezclar formatos de docstring. Cada persona usa nombres y secciones diferentes. Elige un formato y aplícalo en todo el proyecto.
Dejar TODO o FIXME sin contexto. La etiqueta queda olvidada y no indica qué debe hacerse. Escribe una acción concreta y enlaza una incidencia cuando proceda.
Mantener documentación desactualizada. Se trata como una tarea posterior al cambio de código. Revísala en cada cambio relevante y en la revisión de código.
Crear documentación aislada del código. El documento se pierde o deja de coincidir con la implementación. Versiona la documentación técnica junto al código y publica la de usuario con el proyecto.
Usar un formato correcto, pero no documentar el contrato. Se presta más atención a la sintaxis que a la información que necesita quien usa la API. Comprueba siempre propósito, entradas, salida, errores, efectos y ejemplos.

7. Resumen

En este tema has aprendido que:

  • la documentación es parte de la calidad del software y sirve a personas usuarias, desarrolladoras y a tu yo futuro;
  • un comentario debe explicar sobre todo decisiones e intención, mientras que una docstring describe el contrato de un módulo, una clase o una función;
  • Python utiliza # para comentarios y reconoce como docstrings los literales colocados en posiciones concretas;
  • help(), __doc__, pydoc, Sphinx y MkDocs permiten consultar o publicar documentación;
  • los type hints complementan las docstrings, pero no sustituyen la validación ni garantizan por sí solos el tipo de los valores;
  • la documentación debe estar cerca del código, seguir una convención y actualizarse junto con la implementación.

Idea clave

Un buen comentario o una buena docstring aporta información que el código no expresa por sí solo: el propósito, el contrato, los efectos y las decisiones que hacen comprensible y mantenible el programa.

Conclusión

Documentar es una habilidad de programación, no una tarea decorativa. Empieza por hacer el código claro, añade comentarios solo cuando aporten contexto, describe las interfaces públicas con docstrings y acompaña el proyecto con un README y unas guías ajustadas a sus personas usuarias. Así, el trabajo será más fácil de utilizar, revisar, depurar y ampliar.

8. Para seguir practicando

  • Añade comentarios que expliquen decisiones no evidentes a uno de los programas de la práctica de documentación del código y elimina los que repitan literalmente el código.
  • Documenta con docstrings una función de conversión, otra de validación y una clase; comprueba después __doc__ con print() y help().
  • Elige Google Style o NumPy Style y reescribe con él las docstrings de un pequeño módulo, incluyendo parámetros, retorno, excepciones y ejemplos.
  • Crea un README.md mínimo con instalación, uso y ejemplos para uno de tus programas.
  • Revisa la depuración de programas y relaciona los comentarios de diseño con las hipótesis que se comprueban al depurar.

Bibliografía y fuentes

Presentación

Puedes repasar los conceptos principales con la presentación de documentación del código.