A sutil arte de adicionar comentários de código em JavaScript
Depurar código sem comentários é como ser um detetive tentando solucionar um crime, mas a única testemunha fala em língua estrangeira, e tem algumas pessoas influentes (clientes) respirando no seu pescoço para resolver o caso ontem.
fonte da imagem — Dois homens olhando para um laptop · Foto de stock gratuita (pexels.com)
Introdução
Adicionar comentários de código é importante por vários motivos:
1. Legibilidade do código. Os comentários ajudam os desenvolvedores a entender o propósito por trás do código, explicando-o em linguagem simples, tornando-o mais fácil de ler e modificar.
2. Manutenção. Os comentários ajudam você a lembrar o objetivo do seu código, facilitando a manutenção e a atualização no futuro sem causar problemas acidentalmente.
3. Colaboração. Os comentários evitam erros e interpretações erradas em projetos colaborativos, fornecendo contexto para alterações de código, garantindo que todos estejam na mesma página.
4. Documentação. Os comentários do código fornecem clareza sobre o propósito e a funcionalidade, garantindo a conformidade com os padrões e as melhores práticas do setor. Eles tornam o código mais legível, fácil de manter e mais fácil de trabalhar, assim como o guia de instruções LEGO na construção de um conjunto.
Ao reservar um tempo para adicionar comentários significativos e precisos ao código, os desenvolvedores podem melhorar a qualidade geral e a capacidade de manutenção de seus projetos.
Modelo mental para adicionar comentários ao código
Antes de escrever comentários sobre um pedaço de código, é importante ser claro sobre a intenção de fazê-lo. Um comentário de código é um mecanismo de comunicação que deve comunicar os seguintes aspectos do código:
1. Objetivo. Explique o propósito do código, qual problema ele resolve e por que ele existe.
2. Entrada. Especifique as entradas exigidas pelo código, incluindo seus tipos, valores esperados e se são opcionais ou obrigatórios.
3. Saída. Especifique a saída produzida pelo código, incluindo seu tipo e quaisquer detalhes relevantes.
4. Uso. Forneça exemplos de como usar o código, incluindo trechos de código relevantes.
5. Vinculação. Adicione links para código relacionado e recursos externos.
6. Melhores práticas. Destaque quaisquer práticas recomendadas ou pegadinhas relacionadas ao código.
Ao seguir o modelo mental correto, os desenvolvedores podem garantir que seu código seja bem documentado, fácil de entender e de fácil manutenção ao longo do tempo.
Consistência e Padronização
É crucial manter a consistência na formatação e no estilo dos comentários em toda a base de código. Usar uma ferramenta como JS Doc (documentação JavaScript), que é um conjunto de padrões de documentação e ferramentas para documentar o código JavaScript, é uma boa opção.
A seguir estão alguns dos recursos do JS Doc:
- Ele usa tags para capturar informações sobre a estrutura, função, parâmetros, valores de retorno e outros detalhes do código para criar uma referência legível por humanos para outros desenvolvedores.
- Uma tag JS Doc começa com um
@símbolo, seguido pelo nome da tag e qualquer informação relevante. Por exemplo, aparamtag é usada para descrever um parâmetro de função, enquanto areturnstag é usada para descrever o valor de retorno de uma função. - Ele pode gerar documentação em HTML ou outros formatos a partir de comentários embutidos no código-fonte.
function factorial(n) {
if (typeof n !== "number") {
throw new TypeError("Input must be a number");
}
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
function factorialWithCallback(n, callback) {
try {
const result = {
input: n,
output: factorial(n),
};
callback(null, result);
} catch (error) {
callback(error);
}
}
Tags JS Doc comumente usadas
Vamos dar uma olhada em algumas tags JS Doc que são usadas com bastante frequência.
@todo
/**
* @todo Add details about the factorial calculation and edge cases.
*/
function factorial(n) {
if (typeof n !== "number") {
throw new TypeError("Input must be a number");
}
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
/**
* @todo Add an example usage of the callback function.
*/
function factorialWithCallback(n, callback) {
try {
const result = {
input: n,
output: factorial(n),
};
callback(null, result);
} catch (error) {
callback(error);
}
}
O primeiro passo é descrever o que o código faz. @descriptiontag é usada para fornecer uma descrição detalhada de uma função, objeto ou propriedade. Vamos ver como fica o código depois de adicionar essa tag.
/**
* @description A function that calculates the factorial of a number using recursion.
*/
function factorial(n) {
if (typeof n !== "number") {
throw new TypeError("Input must be a number");
}
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
/**
* @description A version of the factorial function that returns the result via a callback.
*/
function factorialWithCallback(n, callback) {
try {
const result = {
input: n,
output: factorial(n),
};
callback(null, result);
} catch (error) {
callback(error);
}
}
Aqui vem a parte em que é informado qual entrada o código recebe. @paramtag é usada para descrever os parâmetros de uma função. Adicioná-lo ao exemplo faz com que o código fique assim:
/**
* @description A function that calculates the factorial of a number using recursion.
*
* @param {number} n - The number for which to calculate the factorial.
*/
function factorial(n) {
if (typeof n !== "number") {
throw new TypeError("Input must be a number");
}
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
/**
* @description A version of the factorial function that returns the result via a callback.
*
* @param {number} n - The number for which to calculate the factorial.
* @param {function} callback - The function to call with the result of the calculation.
*/
function factorialWithCallback(n, callback) {
try {
const result = {
input: n,
output: factorial(n),
};
callback(null, result);
} catch (error) {
callback(error);
}
}
Até agora, sabemos o que a função faz e as entradas necessárias. A seguir vem a descrição do valor de retorno de uma função. Adicionar @returnsao exemplo faz com que o código fique assim:
/**
* @description A function that calculates the factorial of a number using recursion.
*
* @param {number} n - The number for which to calculate the factorial.
*
* @returns {number} The factorial of `n`.
*/
function factorial(n) {
if (typeof n !== "number") {
throw new TypeError("Input must be a number");
}
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
/**
* @description A version of the factorial function that returns the result via a callback.
*
* @param {number} n - The number for which to calculate the factorial.
* @param {function} callback - The function to call with the result of the calculation.
*
* @returns {void}
*/
function factorialWithCallback(n, callback) {
try {
const result = {
input: n,
output: factorial(n),
};
callback(null, result);
} catch (error) {
callback(error);
}
}
Haverá momentos em que a função encontrará erros e não será capaz de produzir os resultados desejados. @throwsajuda a documentar esses cenários. Adicionar @throwsao exemplo faz com que o código fique assim:
/**
* @description A function that calculates the factorial of a number using recursion.
*
* @param {number} n - The number for which to calculate the factorial.
*
* @returns {number} The factorial of `n`.
*
* @throws {TypeError} If the input is not a number.
*/
function factorial(n) {
if (typeof n !== "number") {
throw new TypeError("Input must be a number");
}
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
/**
* @description A version of the factorial function that returns the result via a callback.
*
* @param {number} n - The number for which to calculate the factorial.
* @param {function} callback - The function to call with the result of the calculation.
*
* @returns {void}
*/
function factorialWithCallback(n, callback) {
try {
const result = {
input: n,
output: factorial(n),
};
callback(null, result);
} catch (error) {
callback(error);
}
}
Às vezes, o consumidor ou invocador do código não está interessado nos detalhes de implementação de baixo nível e está preocupado com a invocação e com a obtenção dos resultados esperados. @exampletag é usada para fornecer um exemplo de como usar uma função ou objeto. Adicionar @exampleao exemplo faz com que o código fique assim:
/**
* @description A function that calculates the factorial of a number using recursion.
*
* @param {number} n - The number for which to calculate the factorial.
*
* @returns {number} The factorial of `n`.
*
* @throws {TypeError} If the input is not a number.
*
* @example
* factorial(5);
* // returns 120
*/
function factorial(n) {
if (typeof n !== "number") {
throw new TypeError("Input must be a number");
}
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
/**
* @description A version of the factorial function that returns the result via a callback.
*
* @param {number} n - The number for which to calculate the factorial.
* @param {function} callback - The function to call with the result of the calculation.
*
* @returns {void}
*
* @example
* factorialWithCallback(5, (error, result) => {
* if (error) {
* console.error(error);
* } else {
* console.log(result);
* }
* });
* // logs { input: 5, output: 120 }
*/
function factorialWithCallback(n, callback) {
try {
const result = {
input: n,
output: factorial(n),
};
callback(null, result);
} catch (error) {
callback(error);
}
}
A @typetag JSDoc é usada para especificar o tipo de uma variável, função ou expressão. Ele fornece informações adicionais sobre o tipo de entidade que está sendo documentada e ajuda na legibilidade e manutenção do código.
A @typedeftag JSDoc, por outro lado, é usada para definir um tipo personalizado. Isso pode ser útil em projetos complexos em que você possui estruturas ou tipos de dados personalizados que precisam ser documentados. O tipo personalizado definido com @typedefpode então ser referenciado com a @typetag em outras partes do código.
Em essência, @typedefé usado para definir um tipo personalizado, enquanto @typeé usado para especificar o tipo de uma entidade.
A @propertytag JSDoc é usada para documentar as propriedades de um objeto ou classe. É normalmente usado em conjunto com @typedefpara documentar a estrutura de um objeto ou classe. A @propertytag especifica o nome e o tipo de uma propriedade, bem como uma descrição de sua finalidade.
Adicionar @type, @typedefe @propertyao exemplo faz com que o código fique assim:
/**
* @typedef {Object} FactorialResult
*
* @property {number} input - The input to the factorial function.
* @property {number} output - The output of the factorial function.
*/
/**
* @description A function that calculates the factorial of a number using recursion.
*
* @param {number} n - The number for which to calculate the factorial.
*
* @returns {number} The factorial of `n`.
*
* @throws {TypeError} If the input is not a number.
*
* @example
* factorial(5);
* // returns 120
*/
function factorial(n) {
if (typeof n !== "number") {
throw new TypeError("Input must be a number");
}
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
/**
* @description A version of the factorial function that returns the result via a callback.
*
* @param {number} n - The number for which to calculate the factorial.
* @param {function} callback - The function to call with the result of the calculation.
*
* @returns {void}
*
* @example
* factorialWithCallback(5, (error, result) => {
* if (error) {
* console.error(error);
* } else {
* console.log(result);
* }
* });
* // logs { input: 5, output: 120 }
*/
function factorialWithCallback(n, callback) {
/**
* @type {FactorialResult}
*/
const result = {
input: n,
output: factorial(n),
};
try {
callback(null, result);
} catch (error) {
callback(error);
}
}
@callback
/**
* @typedef {Object} FactorialResult
*
* @property {number} input - The input to the factorial function.
* @property {number} output - The output of the factorial function.
*/
/**
* @callback FactorialCallback
*
* @param {Error} error - The error that occurred during the calculation, if any.
* @param {FactorialResult} result - The result of the calculation.
*/
/**
* @description A function that calculates the factorial of a number using recursion.
*
* @param {number} n - The number for which to calculate the factorial.
*
* @returns {number} The factorial of `n`.
*
* @throws {TypeError} If the input is not a number.
*
* @example
* factorial(5);
* // returns 120
*/
function factorial(n) {
if (typeof n !== "number") {
throw new TypeError("Input must be a number");
}
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
/**
* @description A version of the factorial function that returns the result via a callback.
*
* @param {number} n - The number for which to calculate the factorial.
* @param {FactorialCallback} callback - The function to call with the result of the calculation.
*
* @returns {void}
*
* @example
* factorialWithCallback(5, (error, result) => {
* if (error) {
* console.error(error);
* } else {
* console.log(result);
* }
* });
* // logs { input: 5, output: 120 }
*/
function factorialWithCallback(n, callback) {
/**
* @type {FactorialResult}
*/
const result = {
input: n,
output: factorial(n),
};
try {
callback(null, result);
} catch (error) {
callback(error);
}
}
O FactorialCallbacktipo é então referenciado na @paramtag para o parâmetro callback da factorialWithCallbackfunção.
Exemplo/Demonstração
Uma prévia do snippet acima e da documentação que ele gera usando o JS Doc pode ser conferida aqui .
Observe que o exemplo é uma implementação bastante simplificada para mostrar ao leitor o potencial que pode ser desbloqueado quando todas essas técnicas forem compreendidas e implementadas em seus projetos.
Resumo
Em um mundo cheio de bases de código complexas e intrincadas, os comentários de código são um amigo de que todos precisamos. Com benefícios que variam de legibilidade de código aprimorada a documentação gerada automaticamente, ferramentas como JS Doc são essenciais para qualquer kit de ferramentas de desenvolvimento.
Seja você um desenvolvedor experiente ou apenas começando, reservar um tempo para documentar seu código de maneira padronizada não apenas beneficiará o produto a curto prazo, mas também garantirá a longevidade e a capacidade de manutenção da base de código nos próximos anos.
Eu o encorajaria a usar esses sistemas em seus projetos. Confie em mim, seu futuro eu vai agradecer por isso!





































![O que é uma lista vinculada, afinal? [Parte 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)