Читабельность кода – что это?

  • Эта публикация - перевод статьи. Ее автор - Greg Jorgensen. Оригинал доступен по ссылке ниже:

Программисты жалуются на удобочитаемость и говорят о плохом, “грязном” коде, а также о трудностях, с которыми они сталкиваются, пытаясь понять и работать с этим кодом. Что мы подразумеваем под читабельностью? Что делает код нечитаемым?

Переосмысление проблемы

Я слышал, как программисты говорят о том, что какой-то код «не читается». Я прочел немало статей и книг о читабельности и ремонтопригодности. Что все это означает? Программисты обычно ссылаются на удобство чтения или, чаще всего, на отсутствие самого кода. Но, как и красота, читабельность лежит в глазах смотрящего. Когда мы говорим, что код «не читается», мы, на самом деле, имеем в виду одно или несколько из списка:

  • Я не могу прочитать код, потому что у меня нет достаточного опыта или знаний (с языком или предметной областью).
  • Я не потратил нужное количество времени, пытаясь прочитать и понять код («это не очевидно» или «это не интуитивно).
  • Я не очень заинтересован в понимании этого кода, предпочтя переписать его в собственном стиле.
  • Кодекс оскорбляет мое чувство эстетики; Я бы сделал это по-другому.
  • Программист не знал, как писать код.
  • Кодекс, вероятно, нарушает некоторые принципы или шаблоны, в которые я верю.

Просто перефразируя утверждение «этот код нечитабелен», как «я не могу прочитать этот код», проблема видна в перспективе.

По аналогии, многие люди считают чтение Гомера, Шекспира или Набокова трудным; однако при этом мы не говорим: «Макбет не читабелен». Мы понимаем, что проблема заключается в читателе. У нас может не быть достаточного опыта работы с языком и идиомами. У нас может не быть достаточного исторического и культурного контекста (похоже на недостаток знаний в предметной области при взгляде на программное обеспечение). У нас может недоставать терпения или желания тратить время на изучение того, как читать сложные книги. Статьи Википедии и заметки Клиффа существуют для того, чтобы давать версии книг людям, которые не могут или не хотят читать оригинал. Когда мы замечаем эту тенденцию в других контекстах (не связанных с программированием), мы можем интерпретировать это как лень или слабую концентрацию внимания. Когда мы реагируем таким образом на код, мы обвиняем код и программиста, написавшего его.

Когда я впервые прочитал «Искусство компьютерного программирования» Кнута, как подросток-программист-любитель, я обнаружил, что математический анализ алгоритмов Кнута сложно понять. Я не полагал, что Кнут не знает, как писать, или что его примеры и объяснения нуждаются в рефакторинге. Я полагал, что мне нужно больше узнать о математике и аналитических методах, чтобы понимать эти книги. По мере того, как мои математические навыки совершенствовались, ранее не читаемые книги Кнута принесли много полезной информации.

Недавно я сообщил другу-программисту, что, по моему опыту, весь код поддается переработке при достаточном изучении. Меня больше беспокоит время, которое требуется, чтобы понять код и осознать риски при внесении в него изменений. Хороший код должен уступать пониманию и представлять меньше рисков при внесении изменений. Эти качества проистекают из навыков исходного программиста и ограничений, наложенных во время написания кода. Исходный программист, возможно, пытался предсказать будущее обслуживание и сделать код понятным и читаемым, но для этого требуется делать предположения и прогнозы относительно неизвестных будущих требований и неизвестных будущих программистов. Программисты могут легко увлечься, делая такие предположения, добавляя сложность и универсальность и отдаляясь от требований, фактически не делая код более читабельным или обслуживаемым.

Смещение программиста

Программисты обычно думают, что им необходимо сосредоточиться на написании кода. Чтение кода (особенно чьего-либо) кажется “грязной” работой, неизбежным злом, часто отводимым джуниорам. Чтение кода и его интерпретация не являются творческой или даже продуктивной деятельностью.

Я лично несколько раз был свидетелем того, когда профессиональные программисты отклоняли рабочий, производственный код как «нечитаемый» и «не поддерживаемый» после нескольких минут ознакомления. Их возражения обычно сводились к идее: «Я ненавижу PHP». «Код использует табуляции вместо пробелов и выглядит плохо в моем редакторе». «Код не был написан с классами и объектами». Они не потратили достаточно времени, чтобы понять систему или узнать достаточно о бизнес-сфере, чтобы прочитать код в контексте.

Программисты, изучающие код, который они не понимают или не любят, могут найти примеры нарушения священных принципов: «Это нарушает принцип единой ответственности». «Это выглядит как нарушение DRY». «Глобалы – это “запах” кода». Затем они предлагают переписать систему или, возможно, ее части на свое усмотрение (предпочтительный язык и стиль – ошибочно называемый как «рефакторинг», потому что это звучит как техническая вещь для клиента или начальника).

Всякий раз, когда мне приходится думать, чтобы понять, что делает код, я спрашиваю себя, могу ли я реорганизовать код, чтобы сделать это понимание более очевидным – Мартин Фаулер

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

Все уважают Мартина Фаулера, но эти цитаты иллюстрируют мою точку зрения. Мой опыт позволяет ожидать то, что мне придется «подумать», чтобы понять незнакомый код. Однако я не ожидаю, что сразу пойму нетривиальный код, даже с моим десятилетним опытом. После того, как я пойму код, я могу предположить, что напишу его более четко и реорганизую его, или я чувствую, что я узнал что-то новое из кода и оставил его “в покое”. Я не думаю, что код должен поддаваться пониманию с первого захода, особенно учитывая очень широкий диапазон навыков и опыта программиста. 

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

Если люди говорят вам, что это невозможно, это не обязательно означает, что это невозможно. Это просто означает, что они не могут этого сделать. - Андерс Хейлсберг

Это относится как к чтению, так и к написанию кода. Помните, что в следующий раз вы или кто-то из ваших коллег назовут код «нечитаемым» и «невозможным для поддержки».

Истинный тест интеллекта состоит не в том, сколько мы знаем, как что-то делать, а в том, как вести себя, когда мы не знаем, что делать. - Джон Холт

“Простой” против “тупого”

Это недавно встретилось на моем канале в Твиттере:

Хороший код прост. Обзоры кода - отличный способ обучить команды написанию простого кода. Не бойтесь сказать «это сложно понять». - Эрик Эллиотт

Фраза «Хороший код прост» на самом деле ничего не значит. Мой многолетний опыт программирования и бизнес-экспертиза дают мне совершенно другое представление о «простом», чем у кого-то с меньшим опытом и отсутствием специальных знаний о предметном коде. 

То, что мы называем «простым», зависит от нашего опыта, навыков, интереса, терпения и любопытства. Программисты должны озвучить что-то, когда они не понимают код, но вместо того, чтобы сказать «этот код отстой», они должны сказать «я не могу понять этот код – пока что». Это делает акцент на человека, который пытается понять, а не на код. Я согласен, что проверки кода улучшают качество кода и сплоченность команды, но это зависит от программистов. Команды программистов обычно сходятся на общих идиомах и стиле, и это облегчает совместное программирование,

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

Управление сложностью - это сущность компьютерного программирования. - Брайан В. Керниган

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

Демонстрация читаемости 

Мы думаем о программировании как о процессе использования и написания абстракций. Когда абстракции сопоставляются с требованиями достаточно очевидным образом, код обычно имеет больше смысла. Когда абстракции исходят из неоправданного применения «шаблонов проектирования» или «лучших практик», код становится сложнее для понимания, потому что нужно мысленно следовать разрозненным цепочкам абстракций: бизнес-требованиям и программной реализации.

В былые времена программисты писали код, который увидели бы немногие другие программисты - другие члены их команды или группы, их гуру, может быть аналитик или менеджер проекта. Теперь у нас есть открытый код, также люди публикуют свой код в блогах и в вопросах на Stack Overflow. Программисты, вкладывающие эго свой в код, беспокоятся о критике со стороны людей, которых они даже не знают. Образцы кода вне контекста подвергаются критике. Этот процесс может быть полезным для “толстокожих” программистов, которые склонны интерпретировать критику как полезное наставничество или бесполезные оскорбления. Менее опытные программисты могут быть введены в заблуждение. Публичные обзоры кода создают своего рода искусство производительности программиста, когда программисты пишут код, чтобы произвести впечатление на других программистов.

Ключ к эффективному развитию - делать новые интересные ошибки. - Том Лав

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

Программирование – это творческая форма искусства, основанная на логике. Каждый программист индивидуален и кодит по-разному. Это результат, который имеет значение. - Джон Ромеро

Наиболее важное свойство программы – выполняет ли она намерение своего пользователя. - Чарльз Энтони Ричард Хоар

Лучшее программирование приходит через практику, учебу (по книгам и анализу другого кода) и наставничество. Это происходит не от попыток слепо придерживаться правил и догм, которые вы не понимаете или не можете соотносить с реальным кодом.

Как написать читабельный код

Когда я начал программировать в середине 1970-х годов, один из моих наставников дал мне копию «Элементы программирования стиля» (Kernighan and Plauger, 1974). Из этой книги я узнал, что некоторые техники часто работают лучше, чем другие. Также я узнал о языковых идиомах, именовании переменных и функций и других стилистических и эстетических соображениях. Я прочитал довольно много других книг о «хорошем» программировании, изучил массу кода, кое-что понял и многое – нет (или не сразу понял). Понравилась английская классика «Элементы стиля»; Kernighan и Plauger фокусируются в основном на методах и стиле кодирования, а не на более крупных вопросах проектирования системы, декомпозиции модулей, связности и связывания, а также сбора требований. Элементы стиля программирования служат отправной точкой, введением в разработку стиля, который сделает ваш код выразительным, лаконичным и легким для чтения. Точно так же «Элементы стиля» советуют «опускать ненужные слова» и предостерегают писателей от пассивного голоса и слишком большого числа прилагательных.

Мы строим наши компьютеры (системы) так, как мы строим наши города: со временем, без плана, на вершине руин. - Эллен Уллман

Ну да, и нам, как правило, нравятся многие наши города. Я согласен с Эллен Уллман в том, что разработка программного обеспечения часто идет по более извилистому пути, чем мы хотели бы. То есть, мы не можем надежно предсказать будущее, и у нас не всегда есть ресурсы или желание разрушить и начать все сначала. Жанр программных афоризмов наполняется такими утверждениями, которые имеют смысл, только если мы верим в «правильный путь» разработки программного обеспечения, набор жестких, проверенных принципов, которые приводят к «хорошему» коду.

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

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

Никто в краткой истории вычислений никогда не писал идеальное программное обеспечение. Вряд ли вы будете первым. - Энди Хант

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