Слова «самодокументируемый код» — это ещё один способ сказать «читаемый код». Сам по себе он не заменит настоящей документации или хороших комментариев, но с ними или без них определённо сделает вашу жизнь и жизнь ваших коллег проще.
Давайте разберём несколько важных принципов создания самодокументируемого кода.
Не используйте «магические числа»
Скажите, что означает эта строчка?
if (students.length > 23) {
Проверяет, больше ли студентов, чем 23? И что это означает? Почему именно 23, а не, скажем, 24?
«Магическое число» — число без контекста. Вам нужно будет потратить время и силы, чтобы этот контекст понять. Избавьтесь от лишней работы, сразу явно дайте числу обозначение:
const maxClassSize = 23;
if (students.length > maxClassSize) {
Попробуйте прочитать код теперь. Мы проверяем не «больше ли студентов, чем 23», а «больше ли студентов, чем вмещает класс».
Используйте ясные имена для переменных
Не знаю почему, но раньше я постоянно боялся делать имена переменных длинными. Что было глупо с моей стороны, так как rStuNms и fStuNms ужасны в сравнении с rawStudentNames и filteredStudentNames.
Последние всё-таки кажутся вам длинноватыми? Тогда подумайте вот над чем: после 2 недель отпуска и работы с другим кодом, вы забудете добрую половину сокращений. А именно способность читать имена переменных на ходу — это способность на ходу читать код:
const fStuNms = stus.map(s => s.n)
// в сравнении с
const filteredStudentNames = students.map(student => {
return student.name;
});
Еще один полезный совет — используйте конвенции (соглашения об именах). Если переменная булева, начинайте её имя с is или has (isEnrolled: true). Если в переменной массив, используйте множественное число (students). Многие числа должны начинаться с min или max. А имена функций должны содержать глагол, например, createSchedule или updateNickname. Кстати, о функциях...
Пишите крошечными именованными функциями
Переменные — не единственный способ читать код. В бытность молодым программистом, я использовал функции, только чтобы избежать дублирования кода. Настоящим откровением для меня стало, что прежде всего функции имеет смысл создавать для описания происходящего.
Посмотрите пару секунд на этот код и скажите, что он делает:
const handleSubmit = (event) => {
event.preventDefault();
NoteAdapter.update(currentNote)
.then(() => {
setCurrentAlert('Saved!')
setIsAlertVisible(true);
setTimeout(() => setIsAlertVisible(false), 2000);
})
.then(() => {
if (hasTitleChanged) {
context.setRefreshTitles(true);
setHasTitleChanged(false);
}
});
};
А теперь сделайте то же самое для кода:
const showSaveAlertFor = (milliseconds) => () => {
setCurrentAlert('Saved!')
setIsAlertVisible(true);
setTimeout(
() => setIsAlertVisible(false),
milliseconds,
);
};
const updateTitleIfNew = () => {
if (hasTitleChanged) {
context.setRefreshTitles(true);
setHasTitleChanged(false);
}
};
const handleSubmit = (event) => {
event.preventDefault();
NoteAdapter.update(currentNote)
.then(showSaveAlertFor(2000))
.then(updateTitleIfNew);
};
Вроде и символов больше, но насколько же читаемее, правда? Всего-то и надо было, что разнести логические операции по маленьким именованным функциям. Причём сами маленькие функции читать в большинстве ситуаций не нужно — это детали реализации. Чтобы понять код, достаточно лишь просмотреть самую верхнюю функцию, состоящую из цепочки легко понятных событий.
Но дальше — больше, чуть позже вы поймёте, что такие маленькие функции очень легко использовать повторно. Переиспользуемость — следствие улучшения читаемости, а не наоборот.
Добавьте полезные описания тестов
Наверное, реже всего говорят о самодокументируемых тестах, а зря.
Допустим, у нас есть такая функция:
const getDailySchedule = (student, dayOfWeek) => {
Представим, что она содержит много разных операций: получает расписание на месяц; если сегодня выходной, возвращает пустой массив; если ученик записан на дополнительные занятия, добавляет их в конец дня и т.д. В общем, идею вы поняли: функция комплексная и хорошо бы где-нибудь записать алгоритм её работы простыми словами.
Попытаться уместить его в комментарий — неудачная идея: комментарий однажды устареет и не факт, что его вовремя поправят. Знаете, где запись алгоритма работы уместна? В тестах:
describe('getDailySchedule тест', () => {
it("получает расписание на месяц", () => {
it('если сегодня выходной, возвращает пустой массив', () => {
it('добавляет дополнительные занятия в конец дня', () => {
Это самый элегантный способ комментировать код без комментариев в коде.
Итог: читаемость важнее заумности
Писать код понятный себе может любой, хороший разработчик пишет код понятный другим. Редко что-то важное создаётся единственным человеком, а, значит, рано или поздно другие люди будут читать ваш код. Но даже если вы уверены, что над каким-то кодом будете корпеть только вы, учтите что вы-сегодня и вы-через-месяц — разные люди в плане способности вспомнить этот код.