Saltar al contenido principal

Documentación de código

La documentación de código consiste en anotar directamente el código fuente para describir el propósito, los parámetros, los valores de retorno y el comportamiento de funciones, clases y módulos. En el ecosistema JavaScript/TypeScript la herramienta estándar para esto es JSDoc, y su equivalente orientado a TypeScript es TypeDoc.

JSDoc

JSDoc es un sistema de anotaciones basado en comentarios /** ... */ que se colocan justo antes de una declaración. A partir de esas anotaciones se puede generar documentación HTML estática o proporcionar autocompletado en editores como VS Code.

Instalación:

npm install --save-dev jsdoc

Configuración básica (.jsdoc.json):

{
"source": {
"include": ["src"],
"includePattern": ".+\\.js$"
},
"opts": {
"destination": "docs/jsdoc",
"recurse": true
},
"plugins": ["plugins/markdown"]
}

Añade un script en package.json:

"scripts": {
"docs": "jsdoc -c .jsdoc.json"
}

Etiquetas JSDoc más habituales

EtiquetaDescripción
@paramDescribe un parámetro de entrada
@returnsDescribe el valor de retorno
@throwsDocumenta los errores que puede lanzar
@typedefDefine un tipo reutilizable
@typeAnota el tipo de una variable
@asyncIndica que la función es asíncrona
@deprecatedMarca algo como obsoleto
@exampleProporciona un ejemplo de uso
@moduleIndica que el fichero es un módulo
@classDocumenta una clase

Ejemplos prácticos

Función simple:

/**
* Calcula el precio total aplicando un descuento porcentual.
*
* @param {number} price - Precio base en euros.
* @param {number} discount - Porcentaje de descuento (0-100).
* @returns {number} Precio final tras aplicar el descuento.
* @throws {RangeError} Si el descuento está fuera del rango [0, 100].
*
* @example
* const total = applyDiscount(100, 20); // 80
*/
function applyDiscount(price, discount) {
if (discount < 0 || discount > 100) {
throw new RangeError('El descuento debe estar entre 0 y 100');
}
return price * (1 - discount / 100);
}

Función asíncrona con tipos definidos:

/**
* @typedef {Object} User
* @property {string} id - Identificador único del usuario.
* @property {string} name - Nombre completo.
* @property {string} email - Dirección de correo electrónico.
* @property {Date} createdAt - Fecha de creación de la cuenta.
*/

/**
* Obtiene un usuario de la base de datos por su ID.
*
* @async
* @param {string} userId - ID del usuario a buscar.
* @returns {Promise<User>} El objeto de usuario encontrado.
* @throws {Error} Si el usuario no existe en la base de datos.
*/
async function getUserById(userId) {
const user = await db.users.findOne({ id: userId });
if (!user) throw new Error(`Usuario ${userId} no encontrado`);
return user;
}

Clase completa:

/**
* Servicio para gestionar la autenticación de usuarios.
* Utiliza JWT para la emisión y verificación de tokens.
*
* @class AuthService
*/
class AuthService {
/**
* Crea una instancia de AuthService.
*
* @param {string} jwtSecret - Clave secreta para firmar los tokens JWT.
* @param {number} [expiresIn=3600] - Tiempo de expiración del token en segundos.
*/
constructor(jwtSecret, expiresIn = 3600) {
this.jwtSecret = jwtSecret;
this.expiresIn = expiresIn;
}

/**
* Genera un token JWT para el usuario indicado.
*
* @param {string} userId - ID del usuario autenticado.
* @returns {string} Token JWT firmado.
*/
generateToken(userId) {
return jwt.sign({ sub: userId }, this.jwtSecret, {
expiresIn: this.expiresIn,
});
}

/**
* Verifica y decodifica un token JWT.
*
* @param {string} token - Token JWT a verificar.
* @returns {{ sub: string, iat: number, exp: number }} Payload decodificado.
* @throws {JsonWebTokenError} Si el token es inválido o ha expirado.
*/
verifyToken(token) {
return jwt.verify(token, this.jwtSecret);
}
}

Buenas prácticas

  • No documentes lo obvio. // Incrementa el contador en 1 debajo de counter++ no aporta valor.
  • Documenta los contratos, no la implementación. Lo importante es qué recibe la función, qué devuelve y qué errores lanza.
  • Mantén los ejemplos ejecutables. Un ejemplo que compila/funciona vale más que un párrafo de explicación.
  • Usa @deprecated en lugar de borrar. Cuando una función queda obsoleta, márcala con @deprecated y señala la alternativa antes de eliminarla.
  • Revisa la documentación en los pull requests. Incluye la actualización de JSDoc/TypeDoc como parte del criterio de Definition of Done.