«Любой дурак может написать код, понятный компьютеру. Хорошие программисты пишут код, понятный людям. — Мартин Фаулер

Разработчики часто жалуются, что просмотр их старого кода — это проявление ненависти к себе. Все, что мы видим, это недостатки, неузнаваемые подпрограммы, отсутствие документации, несоблюдение соглашений об именах и в лучшем случае тусклая информация о версиях. Проклиная автора, мы открываем журнал коммитов и видим, что… о, дерьмо… ‘commit by jjung’.

Можем ли мы писать код и знать, что возвращение к нему даст вам чувство дзен-благодарности за его элегантность?

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

Эмпатия разработчиков

Проектирование для следующего человека — это форма эмпатии разработчика (подробно обсуждается в Кодирование с эмпатией). Эмпатия разработчиков — это способность поставить себя на место следующего разработчика и представить, что облегчит им жизнь при использовании вашего кода.

5 признаков низкой эмпатии разработчиков

За прошедшие годы, вернувшись к своему собственному коду, я понял, что есть несколько признаков того, что код, который я написал раньше, был не очень внимателен к моему будущему «я» (или кому-либо, если уж на то пошло).

1) Копировать-вставить

«Копировать и вставлять — ошибка дизайна». — Дэвид Парнас

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

Но, Джош, у меня такая ситуация, и у меня плотный график, и я просто…

«Мне нужно сделать одно и то же несколько раз, но каждый раз немного по-разному!»
используйте цикл

«Мне тоже нужен этот код!»
создайте служебный метод и вызовите его из обоих мест

«Мне нужен новый объект с некоторыми из тех же функций!»
создайте базовый класс и/или интерфейс

«Другому моему приложению нужен такой же код!»
создать библиотеку

Когда я работал над крупным государственным контрактом, мы реализовывали структуру для всех наших общих компонентов во всех наших приложениях. Наша команда по продажам сообщила клиенту, что все приложения имеют одинаковые функции. Один руководитель нового проекта, имя которого останется неназванным, но навсегда вызовет мой гнев, решил скопировать всю структуру в проект и внести изменения. Его объяснение заключалось в том, что ему нужно было внести изменения немедленно, и он не мог ждать обновления фреймворка.

Что ж, неизбежно после очередного выпуска другого проекта клиент вернулся и сказал, что он расстроен, потому что в выпуске другого проекта, который предположительно использовал тот же фреймворк, не было этих обновлений. Но к тому времени две кодовые базы довольно сильно разошлись, и даже не находились в одном репозитории.

Я потратил довольно много времени на уборку этого беспорядка, выполняя довольно большое ручное слияние файл за файлом.

Не копируйте код! всегда есть лучший способ.

2) Грустно! Именование

Мы все сталкивались с кодом, где каждая переменная нуждается в комментарии, потому что она так расплывчато или неправильно названа. Бедняга, столкнувшийся с этой хаммурабской катастрофой, должен приобрести способности телепатии, чтобы понять, что происходит. Если вы когда-нибудь задавались вопросом, исходит ли код, который вы читаете, прямо из недр декомпилятора или разума вашего менее чуткого сверстника (или вас самого в прошлом): это, вероятно, не декомпилятор. В конце концов, у декомпиляторов хотя бы хватает приличия не делать вид, будто они понимают английский.

Потратьте время, чтобы назвать ваши переменные тщательно и последовательно.

Вот несколько приемов, чтобы показать, что вы не начинающий декомпилятор:

Сохраняйте имена переменных согласованными при передаче по приложению.

Одна простая проверка для этого заключается в том, что при передаче переменной в метод, если имя свойства в методе названо иначе, чем имя передаваемой переменной, вам может потребоваться пересмотреть свои соглашения об именах. Исключение будет, если метод является утилитой, а переданная переменная специфична. Но если у вас есть метод с именем «setupModal(modalSettings)», не вызывайте переменную, которую вы передаете, «modalProps». Назовите это «modalSettings»!

Если вы называете переменную «Контакт» в одном месте, не называйте ее «Пользователь» в другом. Если метод называется addUser в одной коллекции, не создавайте в другой коллекции метод с именем createCompany, выполняющий то же самое действие. Если вы называете это «модальным» в одном месте, не называйте его «всплывающим» в другом.

Назовите один раз, используйте повторно везде.

Избегайте длинных имен, используя общепринятые сокращения.

Такие названия, как «curCompany», «selCompany», «prevCompany», «nextCompany» — достаточно очевидные и недвусмысленные аббревиатуры, которые использовались в отрасли на протяжении многих лет. Кроме того, при сохранении аббревиатур примерно одинаковой длины, когда код выстраивается в линию, он выглядит одинаково.

Кроме того, существуют установленные способы определения типа переменной по стилю ее именования. Например, «элементы» указывают, что это упорядоченный набор (массив или коллекция) объектов любого типа. «Контакты» указывают на упорядоченный набор — как вы уже догадались — объектов Contact. Нет необходимости в длинных именах, таких как «itemCollection» или «contactArray». Множественного числа достаточно, чтобы указать на это. Чтобы различать массивы и хэши (например, объект Javascript), мне нравится описывать ожидаемый тип ключа в самом имени, например «firstNameToPersonMap» или «addressToCompanyMap».

Не смешивайте синтаксис человеческого языка.

Если вы называете одну переменную «предыдущий контакт», не думайте, что «контакт» означает следующий контакт. Назовите его «следующий контакт». Если вы используете «isVisible» в одном месте, не используйте «visible» в другом. Если у вас есть синтаксис для имен методов, держите его согласованным. Например, если у вас есть один метод с именем «openModal», не создавайте другой метод с именем «createModal» или «setupModal» в другом месте с такими же функциями.

Последовательно используйте стандартные термины сложных объектов.

Существуют устоявшиеся слова для методов, которые изменяют такие объекты, как хэши, массивы и строки. Используй их!

Не используйте слово «добавить», если вы имеете в виду отправить. Если у вас есть метод, который объединяет два упорядоченных набора (массива) объектов вместе, назовите его «concat» или «concatenate», а не «join». Соединение — это термин, который регулярно используется для связывания всех объектов в массиве в строку. Узнайте, как используются эти термины, чтобы следующий разработчик никогда не запутался в том, почему метод «объединения» в одном месте связывает две строки вместе, а в другом объединяет два объекта!

Обратите внимание, что термины, которые иногда используются, зависят от языка, поэтому лучше проконсультироваться с основными платформами для используемого вами языка, чтобы узнать, какие термины используются.

Будьте как можно более конкретными.

Старайтесь изо всех сил не использовать общие имена методов, такие как «openModal()», когда код специально написан для «openDeleteModal()». Избегайте называть переменную «пользователи», когда вы на самом деле имеете в виду «filteredUsers».

Алфавитизация и поиск с опережением ввода - ваши друзья!

Большинство IDE предоставляют способ поиска по типу, а файловые системы часто предназначены для организации файлов и папок в алфавитном порядке по умолчанию. Используйте это в своих интересах!

Если вы называете один метод «sendEmail», не называйте другой метод «validateAndSendEmail». Назовите его «sendAndValidateEmail», чтобы глагол остался в начале. Если у вас есть класс «Пользователь» и есть понятие «друг», не называйте другой класс «Друг», назовите его «Пользовательский контакт». Теперь они хорошо выстраиваются в ваш алфавитный список в вашем менеджере проектов в вашей IDE и отображаются рядом друг с другом при поиске с вводом текста и явно предназначены для совместной работы архитектором приложения.

3) Несовместимое форматирование

Давным-давно в далекой компьютерной лаборатории, когда у компьютеров не было столько памяти, сколько у божеств, пробелы имели значение. Вкладки были изобретены как способ использовать только 8 бит информации для передачи нескольких пробелов. Таким образом, кодирование с 2, 3 или 4 пробелами вместо табуляции считалось таким же неэффективным, как Ford Bronco 1988 года. Такие языки, как Make, использовали табуляцию и пробелы в качестве лексических идентификаторов для компилятора. Одно маленькое несоответствие пробела могло привести к катастрофе в функционировании написанного кода, поэтому разработчики обращали на это пристальное внимание!

Сегодня это не такая большая проблема, но пробелы по-прежнему имеют значение. Причина гораздо больше связана с необходимостью последовательного форматирования. Как существа, мы хорошо замечаем закономерности, и когда одна мелочь не на своем месте, мы сразу же замечаем, что что-то не так. Если весь код не отформатирован, то все кажется неправильным. Если код отформатирован последовательно, а один раздел не отформатирован, мы немедленно замечаем эту область в коде и понимаем, что это может указывать на быструю проверку и может содержать ошибку.

Форматирование также просто красиво, и давайте признаем: нам нравятся красивые вещи. И эта статья об эстетике. Выберите стандарт, самый красивый из тех, что вы можете найти, и придерживайтесь его. В конце концов, будущий разработчик должен найти ваш верстак не только удобным, но и красивым!

4) Неподдерживаемая документация

Как гласит классическая поговорка, отсутствие документации лучше, чем неточная документация. Но это не повод избегать документирования!

Комментарии

«Код никогда не лжет, иногда лгут комментарии». — Рон Джеффрис

В качестве примера плохого комментирования, вот код, который я составил на основе прошлого опыта:

// Set the user on the modal
myModal.user = user;
// Make sure the emails are okay
for (var j = user.emails.length; j >= 0; j--) {
     user.emails.push({email: ''}); // need temp or else crashes
     if (theConflabulator.hasStoppedConflabulating(true)) {
         break; // Need to break here or else errors. Bill? (TODO)
     }
}

«А, да, понятно. Я очень волновался, что первая строка кода перезагрузит мою машину или, возможно, взломает IRS. Очень рады, что прояснили это комментарием!»

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

Комментарии должны быть написаны по пяти основным причинам:

  1. Вы используете генератор документации (или планируете)
  2. Часть кода отличается от стандартного ожидаемого поведения
  3. Часть кода достаточно сложна (например, математическая), поэтому вам нужно сослаться на что-то, что разработчик не должен знать.
  4. Вы хотите создать эстетические перерывы в коде
  5. У вас есть замечательная ASCII-графика, которую нужно добавить, чтобы оживить обстановку.

Просто пошутил над последним. Вроде, как бы, что-то вроде.

Кроме того, никогда не комментируйте код и не проверяйте его, если вы не хотите, чтобы следующий разработчик спросил, знаете ли вы, как работает репозиторий кода.

Внешняя документация

Целью внешней документации является, прежде всего, описание проблемы и того, как этот код решает ее, обеспечение запуска, а затем предоставление примеров. Внешняя документация не должна описывать то, что ясно говорит сам код, а внешняя документация не должна быть многословной или самодовольной.

Одним из бесценных способов использования внешней документации является описание используемых вами шаблонов программного обеспечения, которые могут быть не очевидны в кодовой базе. В конце концов, программные шаблоны часто охватывают довольно много файлов.

5) Плохая обработка ошибок

Подобно поговорке, что отсутствие документации лучше, чем плохая документация, отсутствие обработки ошибок иногда может быть лучше, чем плохая обработка ошибок! Позвольте мне привести несколько примеров.

Давным-давно я копался глубоко в недрах фреймворка Adobe Flex и нашел небольшой try/catch, который отправлял одну критическую ошибку, которая, как последние слова злодея в комиксе Marvel, говорила только одно: — Тебе никогда не следует сюда приходить.

Хотя это немного юмористично, даже это было лучше следующего:

try {
  doSomethingSuperSweetAndComplicated();
} catch (err : Error) {
  //TODO
}

Эта попытка/поймать стоила мне хорошего дня отладки. Я до сих пор понятия не имею, о чем думал этот разработчик, который потратил время на то, чтобы написать try/catch, а затем проглотить ошибку и продолжить работу, как будто ничего не произошло. Мало того, что код не работал, он больше не отправлял ошибку и он скрывал место возникновения ошибки!

Написание хорошей обработки ошибок в вашем коде — это еще одна часть искусства заботы о следующем разработчике.

Вывод

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

Люблю следующего разработчика. Следующим разработчиком можете стать вы.