Documentar: comentarios, DocC y ejemplos que compilan
La documentación entendida como parte del diseño y no como trámite posterior: la anatomía de un comentario estructurado, el modelo de DocC como grafo de símbolos con catálogo propio, y la disciplina de los ejemplos que el compilador verifica en cada integración continua.
Las guías de diseño de Swift incluyen una instrucción que sorprende por su lugar: pide escribir el comentario de documentación antes de dar por buena la declaración, y usar la dificultad de redactarlo como diagnóstico. Si el resumen no cabe en una frase, o si hay que enumerar excepciones para describir qué hace el método, el problema no es el comentario sino la API. Esa inversión convierte la documentación en instrumento de diseño y no en deuda pendiente. Lo que sigue añade la otra mitad del asunto: cómo esas frases se convierten en un sitio navegable con DocC, y cómo evitar el destino habitual de todo ejemplo escrito a mano, que es dejar de compilar sin que nadie se entere.
- Escribir comentarios de documentación estructurados con resumen, discusión y campos.
- Explicar el modelo de DocC: grafo de símbolos, catálogo, enlaces y contenido curado.
- Integrar ejemplos que el compilador verifica en cada construcción del proyecto.
- Decidir qué merece documentarse y qué es ruido que envejece mal.
Anatomía de un comentario
Un comentario de documentación en Swift empieza con tres barras y se escribe en Markdown. Su estructura canónica tiene tres estratos con funciones muy distintas, y confundirlos es el error más común.
/// Devuelve los resultados que coinciden con el texto dado.
///
/// La búsqueda recorre el índice invertido y puntúa cada documento
/// por frecuencia de término. No modifica el índice ni toca la red.
///
/// - Parameters:
/// - texto: El término a buscar. Una cadena vacía devuelve un array vacío.
/// - limite: Número máximo de resultados. Por defecto no hay límite.
/// - Returns: Los resultados ordenados de mayor a menor puntuación.
/// - Throws: `BusquedaError.indiceCorrupto` si el índice no se puede leer.
/// - Complexity: O de n log n sobre el número de documentos indexados.
func buscar(_ texto: String, limite: Int = .max) throws -> [Resultado]
El resumen es la primera frase y aparece sola en listados, en el autocompletado y en la ayuda rápida. Debe ser una frase completa, terminada en punto, y debe bastar por sí misma: es el único texto que la mayoría de los lectores verá jamás. La discusión son los párrafos siguientes y responden al porqué, no al qué; es el lugar de las decisiones de diseño, las garantías de rendimiento y las interacciones no obvias. Los campos son la parte estructurada que las herramientas saben renderizar en tablas.
Hay una regla tipográfica que parece menor y no lo es: cuando la función tiene un solo parámetro, la forma singular con el nombre directamente detrás rinde mejor que la lista, porque evita una tabla de una fila. Y cuando el tipo es una colección o una clausura, el campo debe describir qué se espera de ella, no repetir su tipo, que ya está en la firma.
Conviene conocer el catálogo de campos más allá de los tres evidentes. Complexity documenta el coste asintótico y es obligatorio en cualquier API de colecciones que se respete. Precondition y Postcondition enuncian el contrato. Warning, Important y Note producen recuadros destacados. SeeAlso teje relaciones. Y Available no se escribe aquí, sino como atributo, cosa que veremos en la lección siguiente.
Si el resumen necesita una conjunción adversativa —hace esto pero también aquello— el método hace dos cosas y debería ser dos métodos. Si un parámetro necesita explicar que solo es válido cuando otro vale cierto, la firma pide una enumeración. Escribe el comentario primero y deja que te delate.
DocC: del comentario al sitio
DocC no es un generador de páginas a partir de comentarios, aunque empiece por ahí. Su modelo es un grafo de símbolos que el propio compilador emite durante la construcción, enriquecido después con el contenido de un catálogo de documentación que vive en el paquete.
El compilador conoce herencias, conformidades, requisitos de protocolo, disponibilidad por plataforma y relaciones genéricas. DocC toma ese grafo y le añade la prosa, lo que explica dos rasgos que distinguen a esta herramienta de sus predecesoras: la documentación de una extensión condicional aparece anotada con la condición exacta, y los enlaces entre símbolos se resuelven contra el grafo, de modo que un enlace roto es un aviso en la construcción y no un error en producción.
MiPaquete/
Sources/MiPaquete/
Busqueda.swift
MiPaquete.docc/
MiPaquete.md // pagina raiz y curacion de temas
Empezar.md // articulo conceptual
Recursos/diagrama.png
Dentro del catálogo, la página raíz organiza los símbolos por temas en lugar de dejarlos en una lista alfabética, y esa curación es la diferencia entre una referencia consultable y un volcado. Los artículos añaden material que no pertenece a ningún símbolo concreto: guías de inicio, explicaciones de arquitectura, notas de migración. Las extensiones de símbolo permiten ampliar la documentación de un tipo sin ensuciar el archivo fuente con veinte líneas de prosa.
Los enlaces merecen una nota propia, porque son lo que convierte un conjunto de páginas en un grafo navegable. DocC distingue dos sintaxis: la de código, que se escribe con comillas invertidas simples y solo aplica formato, y la de símbolo, que se escribe con comillas invertidas dobles y se resuelve contra el grafo. La segunda produce un enlace real, verifica que el símbolo existe y avisa cuando deja de existir; la primera no verifica nada. Usar la de código donde correspondía la de símbolo es el fallo más frecuente en catálogos escritos deprisa, y su síntoma es una documentación llena de nombres que parecen enlaces y no lo son.
La generación se dispara con el complemento oficial del gestor de paquetes, y el resultado es un archivo con extensión doccarchive que puede alojarse como sitio estático o abrirse en Xcode. Merece la pena integrarlo en la integración continua no tanto por publicar como por el efecto secundario: los enlaces rotos y los símbolos públicos sin documentar se convierten en señales visibles.
Una advertencia sobre el alcance. DocC documenta lo que el grafo de símbolos expone, es decir, la superficie pública del módulo; lo interno queda fuera por diseño. Eso lo convierte en una herramienta de documentación de interfaces y no de código, y es exactamente lo que quieres para una biblioteca. Para explicar por qué una implementación hace lo que hace siguen sirviendo los comentarios normales, que además no cargan con la obligación de envejecer bien ante extraños.
flowchart LR A[Codigo fuente] --> B[Compilador emite grafo de simbolos] C[Catalogo docc] --> D[DocC] B --> D D --> E[Archivo doccarchive] E --> F[Xcode] E --> G[Sitio estatico] style B fill:#89b4fa,color:#11111b style D fill:#a6e3a1,color:#11111b
Ejemplos que el compilador verifica
Todo ejemplo escrito dentro de un comentario tiene el mismo destino: envejecer sin que nadie lo note. El compilador no lo mira, las pruebas no lo ejecutan, y sobrevive intacto tres renombrados después de haber dejado de ser correcto. Un ejemplo obsoleto es peor que ninguno, porque el lector confía en él.
La solución que el ecosistema ha consolidado son los fragmentos: archivos de Swift reales, situados en un directorio dedicado del paquete, que se compilan como cualquier otro objetivo y se insertan en la documentación mediante una directiva. Si el ejemplo deja de compilar, la construcción falla.
// Snippets/BusquedaBasica.swift
import MiPaquete
let indice = Indice(documentos: documentos)
// snippet.hide
assert(!indice.esVacio)
// snippet.show
let resultados = try indice.buscar("swift", limite: 10)
print(resultados.count)
Los marcadores permiten ocultar el andamiaje —importaciones, datos de prueba, aserciones— y mostrar solo la parte pedagógica, de modo que el ejemplo sea a la vez ejecutable y limpio. La directiva correspondiente en el catálogo lo incrusta en la página.
La disciplina tiene un efecto secundario que compensa por sí solo el esfuerzo: escribir el ejemplo obliga a usar tu propia API desde fuera, sin acceso a lo interno y sin el contexto que tienes como autor. Casi todas las asperezas de ergonomía que una biblioteca esconde aparecen en los primeros diez minutos de redactar su ejemplo introductorio, y aparecen a tiempo de corregirlas.
Hay dos variantes complementarias que conviene conocer. La primera consiste en escribir los ejemplos directamente como pruebas unitarias y referenciarlos desde la documentación: pierdes la incrustación automática pero ganas verificación del resultado, no solo de la compilación. La segunda son los tutoriales de DocC, pensados para recorridos guiados paso a paso, donde cada paso muestra el archivo completo y la herramienta resalta las líneas nuevas.
Qué no documentar
Documentar de más tiene un coste que se paga en credibilidad. Cada línea de prosa es una promesa que alguien tendrá que mantener, y las que no se mantienen contaminan la confianza en las que sí.
No documentes lo que el nombre ya dice. Un comentario que repite la firma con otras palabras no añade información y sí añade una copia que puede desincronizarse. No documentes detalles de implementación en la interfaz pública: si mañana cambias la estructura de datos interna, habrás roto una promesa que nunca debiste hacer. Y no documentes lo que el sistema de tipos ya garantiza, porque escribir que el parámetro no puede ser nulo cuando su tipo no es opcional solo sugiere que en algún sitio sí podría serlo.
Tampoco documentes lo obvio por obligación burocrática. Un proyecto que exige una línea de comentario por cada símbolo público produce, sin falta, cientos de resúmenes vacíos que repiten el nombre en prosa y entierran los diez comentarios que sí decían algo. La cobertura de documentación es una métrica que se optimiza sola en la dirección equivocada.
Documenta en cambio, sin excepción, tres cosas: las precondiciones que el tipo no puede expresar, la complejidad de todo lo que recorra una colección, y los efectos que no se deducen del nombre, incluidos los de red, los de disco y los de concurrencia. Esa es exactamente la información que el consumidor no puede obtener por ningún otro medio, y por tanto la única que justifica su coste de mantenimiento.
Resumen que basta
Una frase completa que se sostenga sola, porque es lo único que verá la mayoría de los lectores.
Grafo, no páginas
DocC parte del grafo de símbolos del compilador, así que conoce conformidades, condiciones y disponibilidad.
Ejemplos verificados
Un fragmento que compila en cada integración no puede envejecer en silencio. Uno pegado en un comentario, sí.
Hay una tensión estructural en toda documentación que conviene mirar de frente, porque explica por qué la disciplina del ejemplo compilable no es una comodidad sino una necesidad epistemológica. Un sistema documentado contiene dos descripciones de sí mismo: el código, que es verdadero por definición porque es lo que efectivamente ocurre, y la prosa, que es una afirmación sobre el código y por tanto puede ser falsa. Nada obliga a que coincidan, y la entropía trabaja siempre en contra, porque el código cambia por presión de necesidades reales mientras que la prosa solo cambia si alguien se acuerda. El resultado conocido es que toda documentación no verificada tiende asintóticamente a la ficción, y lo hace de la peor manera posible: no se vuelve obviamente falsa, que sería inofensivo, sino sutilmente desactualizada, conservando la suficiente verosimilitud para que el lector siga confiando en ella. La respuesta profunda a este problema no es escribir mejor sino eliminar la segunda verdad, haciendo que las afirmaciones sobre el código sean ellas mismas código sujeto a verificación; es el mismo movimiento que llevó de los comentarios sobre tipos a los tipos declarados, de los comentarios sobre invariantes a las aserciones, y de los ejemplos pegados a los fragmentos compilados. Cada uno de esos pasos convierte una promesa social en una restricción mecánica, y el patrón se repite en toda la historia de la ingeniería del software con una regularidad que casi permite formular una ley: cualquier información que el sistema no verifique acabará siendo falsa, y el único plazo en discusión es cuánto tarda. De ahí que la instrucción de las guías de escribir el comentario antes que la implementación tenga un fundamento más serio de lo que parece: al redactar el resumen antes de que exista el código estás produciendo una especificación, es decir, una afirmación que el código deberá satisfacer en lugar de una descripción que el código podrá desmentir. Es la diferencia entre documentar lo que hiciste y decidir lo que harás, y explica por qué la documentación escrita a posteriori casi nunca mejora el diseño mientras que la escrita a priori lo mejora casi siempre.
El comentario tiene tres estratos: resumen autosuficiente, discusión sobre el porqué y campos estructurados como Parameters, Returns, Throws y Complexity. DocC construye sobre el grafo de símbolos del compilador y añade catálogo, curación por temas y enlaces verificados. Los ejemplos deben vivir en fragmentos o pruebas que se compilen, nunca pegados en un comentario. Y se documenta solo lo que ni el nombre ni el tipo pueden decir.
- Elige tres funciones públicas y escribe su resumen en una sola frase completa; anota cuáles te obligaron a cambiar la firma.
- Añade
Complexitya todo método público que recorra una colección y verifica que la cota declarada es real. - Crea un catálogo de documentación con página raíz y organiza los símbolos por temas en lugar de por orden alfabético.
- Mueve tu mejor ejemplo a un fragmento compilable y rompe la API a propósito para comprobar que la construcción falla.
- Revisa tus comentarios y elimina toda línea que repita el nombre o lo que el tipo ya garantiza; cuenta cuántas eran.