Pull to refresh

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

Reading time3 min
Views7.2K
Original author: Mike Cronin

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


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



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


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


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

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


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


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

Tags:
Hubs:
If this publication inspired you and you want to support the author, do not hesitate to click on the button
Total votes 19: ↑17 and ↓2+15
Comments17

Articles