Комментарии и TODO
Комментарий — пояснение в коде, которое игнорируется интерпретатором. Хороший комментарий объясняет почему, а не что. Лучший код — самодокументирующийся.
Зачем нужно
Комментарии помогают передать контекст, который невозможно выразить через код: бизнес-причины решений, ссылки на баги, предупреждения о побочных эффектах. TODO-метки помогают отслеживать технический долг.
Где используется
- Пояснение нетривиальных решений
- Документация публичных API (JSDoc)
- Временные метки (TODO, FIXME, HACK)
- Предупреждения и ограничения
- Лицензионные заголовки
Предпосылки
Когда комментировать
Хорошие комментарии — объясняют ПОЧЕМУ
// Хорошо: объясняет бизнес-причину
// Скидка 20% для заказов старше 30 дней — требование маркетинга (#JIRA-1234)
if (daysSinceOrder > 30) {
applyDiscount(order, 0.2);
}
// Хорошо: предупреждает о неочевидном поведении
// API возвращает даты в формате MM/DD/YYYY (американский формат!)
const date = parseUSDate(response.createdAt);
// Хорошо: объясняет "магический" код
// Битовый сдвиг на 0 — самый быстрый способ отбросить дробную часть
// (быстрее Math.floor для положительных чисел)
const intValue = floatValue | 0;
// Хорошо: ссылка на источник решения
// Алгоритм Фишера-Йетса для перемешивания массива
// Источник: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
Плохие комментарии — описывают ЧТО (и так видно из кода)
// ПЛОХО: комментарий повторяет код
// Увеличиваем счётчик на 1
counter++;
// Проверяем, является ли пользователь администратором
if (user.role === 'admin') { /* ... */ }
// Возвращаем список пользователей
return users;
// Создаём новый массив
const newArray = ;
// ПЛОХО: устаревший комментарий (код изменился, комментарий — нет)
// Отправляем email пользователю
sendPushNotification(user, message); // email давно заменён на push!
Самодокументирующийся код
Лучшая альтернатива комментариям — код, который не нуждается в пояснении.
// ПЛОХО: нужен комментарий, чтобы понять
// Проверяем, может ли пользователь голосовать
if (user.age >= 18 && user.citizen === true && !user.banned) {
// ...
}
// ХОРОШО: код сам себя объясняет
function canVote(user) {
const isAdult = user.age >= VOTING_AGE;
const isCitizen = user.citizen === true;
const isNotBanned = !user.banned;
return isAdult && isCitizen && isNotBanned;
}
if (canVote(user)) {
// ...
}
// ПЛОХО: нужен комментарий
// Получаем пользователей старше 18 лет с подпиской, отсортированных по имени
const result = users
.filter(u => u.a >= 18 && u.s)
.sort((a, b) => a.n.localeCompare(b.n));
// ХОРОШО: понятно без комментариев
const adultSubscribers = users
.filter(user => user.age >= MINIMUM_AGE && user.hasSubscription)
.sort((a, b) => a.name.localeCompare(b.name));
TODO-конвенция
TODO-метки маркируют технический долг и незавершённую работу.
Стандартные метки
// TODO: задача, которую нужно сделать
// TODO: добавить пагинацию когда пользователей > 1000
// FIXME: известный баг, который нужно исправить
// FIXME: race condition при одновременных запросах
// HACK: временное некрасивое решение
// HACK: setTimeout(0) чтобы дождаться рендера DOM
// NOTE: важная информация для будущих разработчиков
// NOTE: этот endpoint вызывается и мобильным приложением, не меняйте контракт
// OPTIMIZE: место, которое можно оптимизировать
// OPTIMIZE: N+1 запрос к БД, нужен JOIN
// DEPRECATED: код, который скоро будет удалён
// DEPRECATED: использовать newApi вместо этого метода
Формат TODO с контекстом
// TODO(username): краткое описание — JIRA-1234
// TODO(anton): реализовать кэширование для /api/products — PROJ-567
// FIXME(team): утечка памяти при долгом WebSocket соединении — BUG-890
Поиск TODO в проекте
# Найти все TODO в проекте
grep -rn "TODO\|FIXME\|HACK" src/
# VS Code: расширение "Todo Tree" подсветит все метки
JSDoc — документация API
JSDoc позволяет документировать функции, классы и модули. IDE используют JSDoc для автодополнения и подсказок.
/**
* Вычисляет стоимость доставки заказа.
*
* @param {Object} order - Объект заказа
* @param {number} order.total - Сумма заказа в рублях
* @param {string} order.region - Регион доставки
* @param {boolean} [order.express=false] - Экспресс-доставка
* @returns {number} Стоимость доставки в рублях
* @throws {Error} Если регион не поддерживается
*
* @example
* calculateShipping({ total: 5000, region: 'moscow' });
* // => 300
*
* calculateShipping({ total: 5000, region: 'moscow', express: true });
* // => 600
*/
function calculateShipping(order) {
const { total, region, express = false } = order;
const rates = {
moscow: 300,
spb: 400,
regions: 600,
};
const baseRate = rates[region];
if (!baseRate) throw new Error(`Регион "${region}" не поддерживается`);
const rate = express ? baseRate * 2 : baseRate;
return total >= 10000 ? 0 : rate; // бесплатная доставка от 10000
}
/**
* Пользователь системы.
* @typedef {Object} User
* @property {number} id - Уникальный идентификатор
* @property {string} name - Имя пользователя
* @property {string} email - Email
* @property {'admin'|'user'|'moderator'} role - Роль
* @property {Date} createdAt - Дата создания
*/
/**
* Находит пользователя по ID.
* @param {number} id - ID пользователя
* @returns {Promise<User|null>} Пользователь или null
*/
async function findUserById(id) {
return db.users.findOne({ id });
}
Основные JSDoc-теги
| Тег | Назначение | Пример |
|---|---|---|
@param |
Параметр функции | @param {string} name |
@returns |
Возвращаемое значение | @returns {number} |
@throws |
Исключения | @throws {Error} |
@example |
Пример использования | Блок кода |
@typedef |
Определение типа | Описание объекта |
@deprecated |
Устаревший код | @deprecated Используйте newFn |
@see |
Ссылка | @see https://docs.example.com |
@since |
Версия появления | @since 2.0.0 |
Частые ошибки
- Комментировать очевидное.
i++ // инкремент i— бесполезно - Не обновлять комментарии. Устаревший комментарий хуже, чем его отсутствие
- Оставлять закомментированный код. Используйте git для истории, не комментарии
- Писать TODO без контекста.
// TODO: fix this— fix что? когда? почему? - Использовать комментарии вместо рефакторинга. Если нужен комментарий — может, стоит переписать код
Практика
- Просмотрите свой проект: удалите все закомментированные блоки кода
- Замените 3 комментария «что делает код» на самодокументирующийся код
- Добавьте JSDoc к 5 публичным функциям в проекте
- Установите расширение Todo Tree в VS Code и посмотрите все TODO
Связанные темы
Ресурсы
- JSDoc — официальная документация (jsdoc.app)
- Clean Code, глава 4 «Comments» (Robert C. Martin)
- VS Code расширение: Todo Tree
- VS Code расширение: Better Comments