Отладка кода без комментариев — это как быть детективом, пытающимся раскрыть преступление, но единственный свидетель говорит на иностранном языке, а какие-то влиятельные люди (клиенты) дышат тебе в затылок, чтобы вчера раскрыть дело.
источник изображения — Двое мужчин смотрят на ноутбук · Бесплатная стоковая фотография (pexels.com)
Введение
Добавление комментариев к коду важно по нескольким причинам:
1. Читаемость кода. Комментарии помогают разработчикам понять назначение кода, объясняя его простым языком, облегчая его чтение и изменение.
2. Техническое обслуживание. Комментарии помогают запомнить назначение вашего кода, упрощая его поддержку и обновление в будущем, не вызывая случайных проблем.
3. Совместная работа. Комментарии предотвращают ошибки и неверные толкования в совместных проектах, предоставляя контекст для изменений кода, гарантируя, что все находятся на одной странице.
4. Документация. Комментарии к коду проясняют назначение и функциональность, обеспечивая соответствие отраслевым стандартам и рекомендациям. Они делают код более читабельным, удобным в сопровождении и с ним проще работать, как инструкции LEGO по сборке набора.
Потратив время на добавление содержательных и точных комментариев к коду, разработчики могут улучшить общее качество и удобство сопровождения своих проектов.
Ментальная модель добавления комментариев к коду
Прежде чем писать комментарии вокруг фрагмента кода, важно четко понимать цель этого. Комментарий к коду — это механизм связи, который должен сообщать о следующих аспектах кода:
1. Цель. Объясните назначение кода, какую проблему он решает и почему он существует.
2. Входные данные. Укажите входные данные, требуемые кодом, включая их типы, ожидаемые значения и то, являются ли они необязательными или обязательными.
3. Вывод. Укажите вывод, создаваемый кодом, включая его тип и все необходимые сведения.
4. Использование. Приведите примеры использования кода, включая соответствующие фрагменты кода.
5. Ссылки. Добавьте ссылки на связанный код и внешние ресурсы.
6. Рекомендации. Выделите любые рекомендации или ошибки, связанные с кодом.
Следуя правильной ментальной модели, разработчики могут гарантировать, что их код будет хорошо документирован, прост для понимания и со временем будет поддерживаться.
Согласованность и стандартизация
Крайне важно поддерживать согласованность форматирования и стиля комментариев во всей кодовой базе. Хорошим вариантом является использование такого инструмента, как JS Doc (документация по JavaScript), который представляет собой набор стандартов документации и инструментов для документирования кода JavaScript.
Ниже приведены некоторые функции JS Doc:
- Он использует теги для сбора информации о структуре кода, функциях, параметрах, возвращаемых значениях и других деталях, чтобы создать удобочитаемый справочник для других разработчиков.
- Тег JS Doc начинается с символа
@
, за которым следует имя тега и любая соответствующая информация. Например, тегparam
используется для описания параметра функции, а тегreturns
используется для описания возвращаемого значения функции. - Он может генерировать документацию в HTML или других форматах из встроенных комментариев в исходном коде.
Давайте подробно рассмотрим некоторые из наиболее часто используемых тегов JS Doc. Для справки, мы добавим комментарии к следующему коду JS:
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); } }
Не беспокойтесь, если неясно, что делает код. В следующих разделах будет дано объяснение.
Часто используемые теги документов JS
Давайте взглянем на пару тегов JS Doc, которые используются довольно часто.
@todo
Прежде чем что-то делать, важно признать, что это необходимо сделать и что это приносит пользу системе. @todo
tag делает то же самое.
/** * @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); } }
@description
Первый шаг — описать, что делает код. Тег @description
используется для предоставления подробного описания функции, объекта или свойства. Посмотрим, как выглядит код после добавления этого тега.
/** * @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); } }
@param
А вот и та часть, где сообщается, какие входные данные принимает код. Тег @param
используется для описания параметров функции. Добавление его в пример делает код таким:
/** * @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); } }
@returns
Пока мы знаем, что делает функция, и какие входные данные она принимает. Далее идет описание возвращаемого значения функции. Добавление @returns
к примеру делает код таким:
/** * @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); } }
@throws
Будут моменты, когда функция будет сталкиваться с ошибками и не сможет дать желаемых результатов. @throws
помогает документировать эти сценарии. Добавление @throws
к примеру делает код таким:
/** * @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); } }
@example
Иногда потребитель или инициатор кода не заинтересован в деталях низкоуровневой реализации и озабочен вызовом и получением ожидаемых результатов. @example
tag используется для предоставления примера использования функции или объекта. Добавление @example
к примеру делает код таким:
/** * @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); } }
@type
,@typedef
и@property
Тег @type
JSDoc используется для указания типа переменной, функции или выражения. Он предоставляет дополнительную информацию о типе документируемого объекта и помогает повысить читабельность и удобство сопровождения кода.
С другой стороны, тег @typedef
JSDoc используется для определения пользовательского типа. Это может быть полезно в сложных проектах, где у вас есть пользовательские структуры данных или типы, которые необходимо задокументировать. Затем на пользовательский тип, определенный с помощью @typedef
, можно ссылаться с помощью тега @type
в других частях кода.
По сути, @typedef
используется для определения пользовательского типа, а @type
используется для указания типа объекта.
Тег @property
JSDoc используется для документирования свойств объекта или класса. Обычно используется в сочетании с @typedef
для документирования структуры объекта или класса. @property
tag указывает имя и тип свойства, а также описание его назначения.
Добавление @type
, @typedef
и @property
к примеру делает код таким:
/** * @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); } }
Важно отметить разницу между тегами @param
и @property
. @property
tag используется для описания свойств или атрибутов объекта или класса, тогда как @param
tag используется для описания параметров функции или метода. В отличие от тега @property
тег @param
используется внутри блока JSDocs функции или метода, а не за его пределами.
@callback
Он используется для описания функции обратного вызова. @callback
tag определяет параметры функции обратного вызова и их типы. Добавление тега @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); } }
В этом коде тег @callback
используется для определения пользовательского типа FactorialCallback
, который представляет собой функцию обратного вызова, передаваемую в качестве параметра функции factorialCallback
.
Затем на тип FactorialCallback
ссылаются в @param
tag для параметра обратного вызова функции factorialWithCallback
.
Пример/демонстрация
Предварительный просмотр приведенного выше фрагмента и документации, которую он генерирует с помощью JS Doc, можно проверить здесь.
Пожалуйста, обратите внимание, что пример представляет собой очень упрощенную реализацию, чтобы показать читателю потенциал, который может быть раскрыт, когда все эти методы будут поняты и реализованы в их проектах. 🙂
Краткое содержание
В мире, полном сложных и запутанных кодовых баз, комментарии к коду — это друг, в котором мы все нуждаемся. Такие инструменты, как JS Doc, имеют множество преимуществ — от улучшенной читабельности кода до автоматически создаваемой документации — в любом наборе средств разработки.
Независимо от того, являетесь ли вы опытным разработчиком или только начинаете, потратьте время на стандартизированное документирование своего кода. Это не только принесет пользу продукту в краткосрочной перспективе, но и обеспечит долговечность и ремонтопригодность кодовой базы на долгие годы.
Я бы посоветовал вам использовать эти системы в своих проектах. Поверьте, ваше будущее «я» скажет вам за это спасибо! 😊