Советы по написанию самодокументируемого кода

от автора

Слова «самодокументируемый код» — это ещё один способ сказать «читаемый код». Сам по себе он не заменит настоящей документации или хороших комментариев, но с ними или без них определённо сделает вашу жизнь и жизнь ваших коллег проще.

Давайте разберём несколько важных принципов создания самодокументируемого кода.

Не используйте «магические числа»

Скажите, что означает эта строчка?

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('добавляет дополнительные занятия в конец дня', () => {

Это самый элегантный способ комментировать код без комментариев в коде.

Итог: читаемость важнее заумности

Писать код понятный себе может любой, хороший разработчик пишет код понятный другим. Редко что-то важное создаётся единственным человеком, а, значит, рано или поздно другие люди будут читать ваш код. Но даже если вы уверены, что над каким-то кодом будете корпеть только вы, учтите что вы-сегодня и вы-через-месяц — разные люди в плане способности вспомнить этот код.


ссылка на оригинал статьи https://habr.com/ru/post/481124/