читаемый код или программирование как искусство читать
Читаемый код, или Программирование как искусство PDF
Те, кто искали эту книгу – читают
Эта и ещё 2 книги за 299 ₽
Любому программисту доводилось видеть код, который настолько неаккуратен и так пестрит ошибками, что от его чтения начинает болеть голова. За пять лет авторы этой книги проанализировали сотни примеров «плохого» кода (в основном – собственного), пытаясь определить, чем плох тот или иной код и как его можно улучшить. К какому выводу они пришли? Необходимо писать такой код, который читатель сможет понять максимально быстро, причем, даже если этот читатель – сам создатель этого кода.
В данной книге рассматриваются базовые принципы и практические методы, которые можно применять всякий раз при написании кода. В каждой главе на примере несложных образцов кода, написанного на разных языках программирования, изучается отдельный аспект создания кода и демонстрируется, как сделать код простым для понимания.
Отзывы 1
Хорошая книга, рекомендую всем программистам
С первых строк даются простые советы, позволяющие качественно улучшить свой код. Помню, на заре моего интереса к программированию листал похожие книги, но не понимал всю важность заключённой в них информации. Сейчас, имея некоторый опыт программирования могу сказать, что к словам авторов следует прислушиваться как можно раньше.
Особенно будет полезно профессиональным программистам, работающим в команде, либо участвующим в разработке долгосрочных проектов с постоянно меняющимися требованиями. Сэкономите время себе и люди поддерживающие код будут меньше материться.
Читаемый код или программирование как искусство
Сейчас я читаю книгу «Читаемый код или программирование как искусство». В ней куча годных мыслей и примеров, которыми хочется поделиться. Но в одну заметку всё не уместится, поэтому я решил пересказывать книгу по несколько глав за раз. В этой заметке 1–4 главы.
Глава 1: код должен быть простым для понимания
Код чаще читают чем пишут. Чем быстрее человек понимает незнакомый код, тем он проще. В понятном коде легко найти баги и исправить их, не сломав при этом программу.
Короче — не всегда лучше для понимания:
Поэтому стремиться к компактности хорошо, но стремиться к высокой читаемости лучше.
Глава 2: подбирайте точные имена для переменных, функций и классов
Например, в функции GetPage слово get неточное. Оно не объясняет, берётся ли страница из кэша или из сети. Названия FetchPage или DownloadPage лучше объяснят, что происходит.
В примере ниже из тела функции и так понятно, что retval — возвращаемое значение.
Однако неясно, что оно в себе содержит, из-за этого просто пропустить ошибку:
Вместо абстрактных имён используйте конкретные, заточенные под ситуацию. Такие имена сами объясняют, для чего нужна переменная или функция. А конкретика помогает избежать двусмысленности.
Префиксы и суффиксы уточняют смысл. Например, измеряем скорость загрузки веб-страницы:
Если вы знакомы с Джаваскриптом, то заметили ошибку — getTime возвращает результат в миллисекундах. Поэтому код работает неправильно. Если добавить суффикс _ ms, то ошибку будет заметно:
Длина имени зависит от размера области видимости. Если переменная лежит внутри функции из 3 строк, то короткое имя ей подойдёт. Но чем больше область видимости, тем точнее должно быть имя. Например, days_since_last_update будет лучше, чем просто days.
Сокращения в именах вызывают вопросы. Для расшифровки сокращения может не хватать знаний. Кроме того сокращение проще всего истолковать неправильно. Поэтому BEManager — плохое имя, BackEndManager — лучше.
Если слово не дополняет смысл названия, его лучше выбросить. Например, convert_to_string можно заменить на to_string.
Правило для выбора имени: «Если новый член команды не может понять смысла функции или переменной по её названию, это плохое имя».
Глава 3: избегайте двусмысленных названий
Тестируйте названия на неверные интерпретации. Спросите себя, что ещё может подразумеваться под этим именем. Например, функция filter непонятная: она выбирает или значения, которые подходят под условие, или наоборот. А вот названия select или exclude сразу говорят, какие результаты мы получим.
Для булевых переменных используйте префиксы is, has, can, should Актуально и для функций, которые возвращают булево значение.
Глава 4: красивый код быстрее считывается
Избавляйтесь от непоследовательности. Используйте вспомогательные функции. Например, функция и тест для неё:
Две строки не влезают и перескакивают на следующие, читатель собьётся. Этого можно избежать с помощью вспомогательной функции:
При объявлении переменных, разбивайте их на смысловые блоки:
Сам код тоже можно разбивать на «параграфы». Если функция состоит из нескольких шагов, выделите эти шаги в коде пустыми строками между ними.
Что дальше?
На следующей неделе поговорим о главах 5–7. Расскажу, как:
Самый важный навык, который может освоить программист
Нет, нет, нет, нет и нет. И нет.
Огромное НЕТ. Давайте проясним это.
Все, что вам нужно сделать, это соединить эти три буквы и произнести слово.
Давайте сделаем это вместе. НЕЕЕЕЕЕЕТ!
Но подождите-ка минуточку. Зачем и когда говорить НЕТ?
Что ж, это важный момент. Многие программисты (даже синьоры) путаются.
Самая большая часть вашей работы как программиста — написание кода. В вашей жизни разработчика придется часто иметь дело с разными видами требования написать тот или иной код. Каждое требование заставит вас принимать сложные решения. Это НОРМАЛЬНО. В этом нет ничего плохого. Это все, что ожидают от программиста: написание кода. Итак, вопрос: нужно ли писать весь код, который от вас требуют?
Этот вопрос подводит нас к самому важному навыку, который может усвоить программист:
Знание того, когда не следует писать код, возможно, является наиболее важным навыком, который может освоить программист. — Читаемый код, или Программирование как искусство
Сначала я совсем не мог с этом согласиться. Я задавался вопросом: это с чего бы?
Программирование — это искусство решения проблем. Естественно, программисты решают проблемы. Как программисты, когда перед нами возникает новая проблема, готовая к решению, или по любой другой причине нужно написать какой-нибудь код, мы начинаем волноваться.
И это нормально, потому что мы программисты. Мы любим писать код.
Однако, если писать код слишком взволнованным, можно не заметить чего-то важного. Волнение заставляет нас игнорировать некоторые важные факты, которые могут вызвать серьезные проблемы в будущем.
Итак, какие важные факты мы склонны игнорировать?
Каждая написанная строчка кода:
Как писал Рич Скрента, код — наш враг:
Код — это плохо. Он гниёт. Он требует периодического обслуживания. В нем есть баги, которые нужно найти. Новые функции означают, что старый код нужно править.
Чем больше у вас кода, тем больше возможностей совершить ошибку. Больше времени уходит на проверки или на компиляцию. Новый сотруднику требуется все больше времени, чтобы понять вашу систему. Рефакторинг становится сложнее.
Кроме того, больше кода часто означает меньшую гибкость и функциональность. Это кажется нелогичным, но во многих случаях простое, элегантное решение оказывается более быстрым и общим, чем сложный код, созданный менее опытным программистом.
Код производится инженерами. Чтобы писать больше кода, нужно больше инженеров. На коммуникации требуется время, которое растет квадратично от числа программистов. И весь код, который разработчики добавляют в систему еще больше увеличивает эту цену.
Это правда, не так ли? Программисты, которые вдохновляют вас своей продуктивностью и стилем программирования, — это те, кто знает, когда говорить «нет», когда не писать код. Простое в обслуживании программное обеспечение, которое живет долго и помогает пользователям, не содержит лишних строк кода.
Лучший код — это вовсе не код, а самый эффективный программист — это тот, кто знает, когда не писать код.
Как узнать, когда не нужно кодировать?
Это нормально, если при работе над проектом вы взволнованы и думаете обо всех интересных функциях, которые хотелось бы реализовать. Но программисты склонны переоценивать, сколько функций нужно их проектам. Многие функции остаются незавершенными, не используются, или просто усложняют приложение. Вы должны хорошо представлять, что важно для вашего проекта, чтобы избежать этой ошибки.
Понимание цели программы и определение его ядра — это первый шаг к пониманию того, когда не следует писать код.
Позвольте привести пример. Допустим, у вас есть приложение для управления электронной почтой. Отправка и получение электронных писем — две важные функции вашего приложения. Вы не станете ожидать, что это приложение также будет управлять вашим списком дел, не так ли?
Поэтому вы должны сказать НЕТ любым запросам на новые функции, которые не имеют отношения к ядру приложения. Тогда вы будете точно уверен, что знаете, когда не следует писать код.
Никогда не расширяйте цель вашего приложения.
Знание того, когда не нужно писать код, делает вашу кодовую базу маленькой.
При старте проекта в нем всего два или три файла с исходным кодом. Все выглядит так просто. Сборка и запуск кода занимает всего несколько секунд. Вы знаете, где найти то, что вам нужно.
Затем, по мере роста проекта, все больше и больше файлов исходного кода заполняют вашу директорию с проектом. Каждый файл кода содержит сотни строк кода. Чтобы организовать их все, вам понадобятся несколько директорий. Помнить, какие функции вызывают какие все сложнее, а отслеживание ошибок требует немного больше усилий. Управлять вашим проектом становится трудно, и вам нужно больше программистов, чтобы справиться с этим. Затраты на коммуникации возрастают по мере увеличения числа программистов. Вы все замедляетесь и замедляетесь.
В итоге проект становится огромным. Добавление новых функций невероятно болезненно. Даже внесение небольших изменений занимает несколько часов. Исправление багов приводит к новым багам. Вы начинаете опаздывать к срокам.
Теперь жизнь — это борьба. Почему?
Потому что вы не знали, когда не следует писать код, вы отвечали ДА каждой новой функции. Вы были слепы. Создание чего-то нового заставило вас игнорировать существенные факты.
Похоже на фильм ужасов, верно?
Это то, что произойдет, если вы продолжаете говорить ДА всему. Запомните, когда не нужно писать код. Удалите весь ненужный код из вашего проекта. Это облегчит вашу жизнь и продлит срок службы приложения.
Один из моих самых продуктивных дней был, когда я выбросил 1000 строк кода. — Кен Томпсон
Я знаю, что понять, когда не нужно писать код, очень сложно. Даже для опытных программистов. Возможно, написанное в этой статье, трудно понять начинающим программистам, и это нормально и ожидаемо.
Я знаю, вы только начали свой путь программирования и хотите писать код. Вы так взволнованы этим. Это хорошо. Никогда не теряйте это волнение, но и не игнорируйте важные факты. Мы узнали их, делая свои собственные ошибки. Вы тоже будете совершать ошибки и учиться на них. Но, по крайней мере, вы можете быть более осознанными, если извлечете уроки из нашего опыта.
Продолжайте писать код, но знайте, когда остановиться.
Если вам понравилась статья, внизу можно поддержать автора хлопками 👏🏻 Спасибо за прочтение!
Книги по программному коду
Привет Хаброжители!
Издательство Питер решило вспомнить о хороших, но забытых книгах по чистому коду:
Чистый код: создание, анализ и рефакторинг. Библиотека программиста
Аннотация: даже плохой программный код может работать. Однако если код не является «чистым», это всегда будет мешать развитию проекта и компании-разработчика, отнимая значительные ресурсы на его поддержку и «укрощение». Эта книга посвящена хорошему программированию. Она полна реальных примеров кода. Мы будем рассматривать код с различных направлений: сверху вниз, снизу вверх и даже изнутри. Прочитав книгу, вы узнаете много нового о коде. Более того, вы научитесь отличать хороший код от плохого. Вы узнаете, как писать хороший код и как преобразовать плохой код в хороший. Книга состоит из трех частей. В первой части излагаются принципы, паттерны и приемы написания чистого кода; приводится большой объем примеров кода. Вторая часть состоит из практических сценариев нарастающей сложности. Каждый сценарий представляет собой упражнение по чистке кода или преобразованию проблемного кода в код с меньшим количеством проблем. Третья часть книги — концентрированное выражение ее сути. Она состоит из одной главы с перечнем эвристических правил и «запахов кода», собранных во время анализа. Эта часть представляет собой базу знаний, описывающую наш путь мышления в процессе чтения, написания и чистки кода.
Идеальный код
Аннотация: в этой уникальной книге самые авторитетные разработчики программного обеспечения делятся опытом оригинального решения задач, которые вставали перед ними при реализации крупных IT-проектов. С помощью этого издания читатель получит возможность оказаться на месте ведущих программистов, увидеть собственными глазами проблемы, возникавшие при реализации разнообразных проектов, и пройти увлекательный путь их преодоления. Авторские статьи отобраны Грегом Уилсоном, редактором журнала «Dr. Dobb’s Journal», одного из самых авторитетных IT-изданий в мире, а также редактором издательства O’Reilly Энди Орамом. Один лишь только список авторов делает эту книгу настоящим бестселлером — здесь вы найдете материалы, написанные такими признанными профессионалами, как Чарльз Петцольд, Джон Бентли, Тим Брэй, Брайан Керниган, и еще тридцатью четырьмя экспертами в области разработки программного обеспечения.
Читаемый код, или Программирование как искусство
Аннотация: любому программисту доводилось видеть код, который настолько неаккуратен и так пестрит ошибками, что от его чтения начинает болеть голова. За пять лет авторы этой книги проанализировали сотни примеров «плохого» кода (в основном — собственного), пытаясь определить, чем плох тот или иной код и как его можно улучшить. К какому выводу они пришли? Необходимо писать такой код, который читатель сможет понять максимально быстро, причем, даже если этот читатель — сам создатель этого кода. В данной книге рассматриваются базовые принципы и практические методы, которые можно применять всякий раз при написании кода. В каждой главе на примере несложных образцов кода, написанного на разных языках программирования, изучается отдельный аспект создания кода и демонстрируется, как сделать код простым для понимания.
Для Хаброжителей скидка 20% на всю категорию «Чистый код» — 87bdd2ae6c884881
Как писать читаемый код
Бывает, что посмотрев на старый код, мы говорим: «Его проще переписать, чем поменять». Печально, если речь идет о нашем собственном коде, с такой любовь написанном несколько лет назад. Head of Developer Relations в Evrone Григорий Петров в своем докладе на TechLead Conf 2020 разобрал проблемы, которые приводят к такой ситуации, и рассказал, как бороться с Software complexity problem.
В этой статье пересекаются, казалось бы, непересекаемые вещи: нейрофизиология, проклятие нулевой цены копирования, когнитивная и социальная интуиция. И, конечно же, в ней поднимается тема сложности кода. Вы узнаете о том, откуда она берется, почему ее нельзя убрать и как с ней жить.
В компании Evrone занимаются заказной разработкой сложного софта. Поэтому ее сотрудникам важно писать читаемый код, чтобы клиенты могли поддерживать его сами и благодарить компанию за хорошо сделанную работу.
Но несмотря на двадцатилетний опыт в программировании, Григорий признается: писать читаемый код до сих пор тяжело. И в этой статье мы обсудим все предполагаемые сложности.
Художник рисует мазками
Когда художник рисует картину, он делает это мазками: берет кисть, краски и начинает накладывать по одному мазку. Но нельзя забывать о том, что он всегда может отойти на шаг, чтобы посмотреть на свое творение целиком.
Можно сказать, что программисты тоже пишут код своеобразными «мазками»: идентификатор за идентификатором, оператор за оператором, expression, statement, строчка за строчкой получаются творения в 10, в 100, в 1000 строк кода.
Но, в отличие от художника, программисты не могут «отойти на шаг назад». Художник использует машинерию зрительной коры, у которой есть механизм зума. А когда пишется код, используются механизмы кратковременной и долговременной памяти, у которых механизм зума, к сожалению, архитектурно не предусмотрен.
Поэтому одна из главных проблем, существующих в разработке софта — это то, что мы называем Software complexity problem, что можно перевести на русский как «проблема сложности программ».
Но ведь есть огромное количество других областей, где точно также накапливается сложность. Например, ракетостроение. У людей, которые делают космические корабли, немало сложностей, правда?
Но есть у них и годы обучения, которые начинаются прямо с детского сада. Будущие ракетостроители учат счет, вначале устный, потом письменный, потом приходят в школу, там изучают физику, математику. Проходят годы, они поступают в институт, где узнают, собственно, о строительстве ракет. У них есть устоявшиеся практики о том, как создавать ракеты, а навыки закрепляются повторением. Будущий ракетостроитель проектирует, экспериментирует, совершенствуется, и пятнадцатая по счету ракета таки выйдет за пределы атмосферы.
Проблемы программирования
Нулевая цена копирования;
Если мы уже «построили ракету» — написали софт, у нас нет необходимости писать точно такой же еще раз, чтобы сделать его чуть-чуть лучше. Если разработчик работает над кодом, значит раньше подобного им написано не было. Иначе код был бы скопирован.
Нет понимания «как правильно»;
Индустрия программирования очень молода, мы еще не успели подготовить лучшие практики и не знаем, как «правильно» писать софт. Прямо сейчас можно наблюдать, как монолит объектно-ориентированного программирования, который последние 20 лет был незыблемым, сдает позиции функциональному программированию. Многие топовые разработчики сейчас говорят о том, что наследование — это не очень хороший способ декомпозиции кода. А в языках программирования последнего десятилетия (например, в Rust) в принципе нет классов, как таковых. И они неплохо себя чувствуют.
Отсутствие фундаментального образования;
Из-за молодости индустрии и нулевой цены копирования, в среде программистов отсутствует фундаментальное образование. Есть computer science, но это science. Она про науку, и имеет примерно такое же отношение к прикладной разработке софта как астрономия — к разработке телескопов. Программист, который в университете 6 лет учил алгоритмы и структуры данных, почти ничего не знает про систему управления версиями, идентификаторы, про то, как писать читаемый код и рассказывать этим кодом истории.
Сложно посмотреть, «как делают другие».
Художник может прийти в картинную галерею, посмотреть на разные топовые картины и сказать: «Вот это круто нарисовано. Я сейчас повторю и буду рисовать так же хорошо!». Для этого у него есть интуитивное мышление.
Интуитивное мышление, когнитивные искажения
Наш мозг, конечно, не «чистый лист» с рождения, но и не компьютер с предустановленным софтом. Считается, что мы можем думать ровно те мысли и тем способом, которому обучились за свою жизнь. Интуитивное мышление неплохо справляется на бытовом уровне при оценке диапазонов: оценить насколько красива картина, насколько хорошо сделан ремонт, насколько талантливо выступает артист.
Но если мы попробуем применить интуитивное мышление к чужому коду, наш мозг автоматически выдает результат: «Этот код плохой, ведь его писал не ты. Перепиши все».
У нас нет интуитивного способа оценить «качество кода». Программирование — это принципиально новая область, и наш мозг не может интуитивно применить к нему жизненный опыт из реального мира.
Кроме того, программистам, в отличие от художников, трудно обучаться у мастеров. Мы, конечно, можем прийти в наш аналог картинной галереи — GitHub — и посмотреть там на большие проекты. Но если сделать чекаут проекта с GitHub, там может оказаться полмиллиона строк кода. Это очень много, а у нас нет оптического зума, чтобы просто окинуть код взглядом, не вникая. Поэтому обучаться на примере программистам очень тяжело. Про то, что GitHub это скорее склад строительного материала, а не картинная галерея, я даже говорить не буду.
Так же тяжело заказчикам софта, которым интуиция не помогает понять, что такое технический долг и рефакторинг, и почему команда хочет много денег, чтобы, казалось бы, не сделать ничего особенного.
Так что возвращаясь к вопросу о накоплении сложности, в программировании все то же самое, что и в ракетостроении. Но, из-за отсутствия фундамента, сложность копится намного быстрее, а накопление сложности делает код нечитаемым.
Борьба со сложностью
К сожалению для нас, сложность из кода нельзя убрать. Ведь она — это та польза, которую приносит написанная нами программа.
Но сложность можно перераспределить! Именно об этом пойдет речь в статье.
Гиппокамп — это часть мозга, которая, предположительно, имеет отношение к формированию памяти. Известно, что когда выходит из строя гиппокамп, ломается память.
Как это происходит, не совсем ясно. Но существует такая закономерность, как «Кошелек Миллера»: когда человек смотрит на новые для себя объекты, в среднем, он может удержать в фокусе внимания от 5 до 9 из них.
Современные нейрофизиологи сделали вывод, что Миллер был большим оптимистом, и в реальности число удерживаемых в фокусе объектов ближе к 5. Именно столько новых штук может находиться в кратковременной памяти, прежде чем она начнет давать сбои.
Но у нас есть еще и долговременная память, объемы которой довольно велики. Однако помещение чего-либо в долговременную память занимает немало времени.
Когда человек только учится играть в шахматы, он медленно сканирует шахматную доску, вспоминая правила и пытаясь нащупать некие комбинации. Окно его внимания, содержащее 5 элементов, неспешно ползет по доске.
Но если речь идет об игроке, который сидит за шахматной доской 10-15 лет, то его мозг в автоматическом режиме пользуется привычными паттернами: комбинациями фигур, типичными атаками и защитами.
Когда опытный игрок в шахматы смотрит на доску, новой информации для него очень мало. Именно эта новая информация — то, что он держит в кратковременной памяти, и речь обычно идет всего о 2-3 элементах. Все остальное уже есть в долговременной памяти. Но для такой подготовки требуются годы.
Библиотеки и фреймворки для языков программирования могут стать способом перевести информацию из кратковременной памяти в долговременную.
Если программист много лет пишет на Python и использует requests, он к ним привыкает. Типичные конструкции использования requests — как сделать запрос, как передать и получить JSON, как решать вопросы скорости и задержек — ему привычны. Код, который использует библиотеку, становится для программиста читаемым. В таком коде больше нет сложности. По крайней мере, для этого конкретного программиста.
Если же программист начинает использовать другую библиотеку, читаемость кода для него падает. Поэтому иногда выбор не оптимальной, с точки зрения скоростных или usability характеристик, библиотеки или фреймворка, которые, тем не менее, мега популярны, может быть разумным. Такой код будет намного читаемее для большого количества программистов.
Точно также работает стандарт кодирования, «coding style». Код разработчиков может быть читаемым друг для друга, но только если они хотя бы несколько месяцев поживут с ним. Нейрофизиология утверждает, что несколько месяцев и несколько сотен повторений нужны нашей памяти, чтобы выстроить долговременные связи long-term potentiation, чем бы они ни были.
Все это сейчас очень удобно упаковывается в линтеры. Так что если мы хотим сделать так, чтобы код, который пишут программисты в нашей команде, был читаемым в первую очередь для них самих, мы запаковываем стандарт кодирования в линтеры и настраиваем линтеры в их IDE.
Но память — это долго. Это самый простой, но и самый длительный по времени способ борьбы со сложностью.
Второй по популярности способ — это декомпозиция на части по 5 элементов.
Посмотрим на эволюцию типичной сферической программы в вакууме.
Как правило, она начинается с одного файла, который реализует минимум функциональности. Затем, по мере добавления строк кода, программист интуитивно начинает разделять программу на файлы поменьше. Еще через некоторое время, когда файлов становится несколько десятков, более-менее опытный программист выделяет модули, которые дает язык программирования.
Чуть позже программист начинает использовать абстракции языка. Обычно это классы, миксины, интерфейсы, протоколы, синтаксический сахар. Современные языки программирования, как правило, позволяют программисту бороться со сложностью путем добавления высокоуровневых абстракций и синтаксического сахара.
Через некоторое время, когда абстракции языка программирования исчерпывают себя, и строчек становится несколько десятков тысяч, разработчики начинают с интересом смотреть в сторону DSL: YAML, JSON, Ruby, XML и т.д.
Особенно большой интерес проявляется в Java, где XML-конфиги к программам — просто стандарт де-факто. Но даже если команда не пишет на Java, она с большим удовольствием выкладывает и перераспределяет избыточную сложность в JSON, YAML и в другие места, которые сможет найти.
Наконец, когда строк кода становится очень много, программы начинают делить на модные сейчас микросервисы.
Вспоминается анекдот о том, что любую архитектурную проблему можно решить путем ввода дополнительного слоя абстракции. Кроме проблемы слишком большого количества дополнительных слоев абстракции.
Хорошо, что у нас есть и другие инструменты для того, чтобы писать читаемый код.
Прежде всего метаинформация нужна не компилятору и языку программирования, а людям.
Она как дорожные указатели, которые расставлены по коду. Там, где сложности скопилось слишком много, ее разделяют на части с указанием того, что в этих частях находится. Основная часть при этом одна, все такая же огромная, но внешние «дорожные указатели» позволяют посмотреть на нее под разными углами.
Главный, основной, фундаментальный дорожный указатель — идентификаторы.
Идентификаторы — это переменные, константы, названия функций и классов — все те имена, которые мы даем сущностям в коде.
Недокументированное свойство нашего мозга заключается в том, что часть коры, которая занимается распознаванием слов (зоны Брока и Вернике) очень хорошо умеет их склеивать вместе. Поэтому каким бы длинным ни было слово, с точки зрения нашей рабочей памяти это практически всегда будет одна сущность (в разумных пределах).
竜宮の乙姫の元結の切り外し или Мосгорводоканалстрой — это одна сущность для нашего мозга.
Идентификатор здорово помогает писать читаемый код, если отвечает на вопрос «что это?». Программист пришел в проект, посмотрел на идентификатор, и ему сразу понятно, что. В современных языках программирования для этого есть PascalCase, camelCase, snake_case. Выбирая конкретный стиль, мы выбираем то, что привычнее нашей команде.
В Go все очень тяжело со сложностью, потому что язык практически не предоставляет синтаксического сахара. В книге «Как писать на языке программирования Go» есть параграф про эволюцию идентификаторов. Там написано о том, как бороться с когнитивной сложностью в коде. Выбирая имя для идентификатора, авторы предлагают смотреть на то, что находится рядом с этим идентификатором. Если там что-то очень простое (функция, 2-3 строчки кода, которые очевидны), то идентификатор может быть i или v:
v => users => admin_users
Но по мере увеличения сложности и количества кода, мы хотим увеличивать длину идентификатора, чтобы он лучше отвечал на вопрос «что это?», если такая информация непонятна из контекста.
После идентификаторов идут комментарии, которые отвечают уже на вопрос «зачем это?».
Худший комментарий в коде тот, который пересказывает, что происходит в коде. Но это и так можно увидеть, прочитав код! А вот информация зачем это происходит, как правило, содержится только в голове разработчика.
Топовые мировые программисты нередко пишут код вообще без комментариев. Идентификаторы, которые они используют для переменных, констант, функций, классов, и то, как они разбивают код на части с помощью предоставляемых языком программирования средств, рассказывают историю лучше самых удачных комментариев. Лучшим комментарием является сам код.
Но писать так, как делают это лучшие программисты, тяжело. Поэтому, мы можем добавить в код комментарии, отвечающие на вопрос «зачем?».
Точно также комментарии в коммитах могут давать понимание, зачем сделан этот коммит. А если в таком коммите есть ссылка на тикет, то сложность перераспределяется и туда, давая дополнительные точки опоры при чтении кода через много лет и отвечая на вопрос «зачем это было сделано?».
Документацию же можно рассматривать в качестве последнего бастиона. Если не удалось сделать код, который отвечает на вопрос «зачем?», не получилось добавить в него комментарии, которые отвечают на этот вопрос, и с комментариями в коммитах и тикетах тоже не сложилось, открываем readme.md и пишем там большой архитектурный абзац.
У документации есть огромные риски рассинхронизироваться с кодом, поэтому, когда мы пишем читаемый код, нужно постараться выносить что-то в документацию только в том случае, если выбора нет. Например, когда у нас очень большой проект.
Автогенерация документации — это отдельная история. Многие примеры хорошего кода, которые мы видим: фреймворки и библиотеки. При их изготовлении нам важна документация, поэтому мы документируем каждый метод, а потом автогенерим документацию. Но это нужно делать с умом.
В роли документации могут выступать и тесты. Поскольку они показывают пути выполнения.
В последние 5-10 лет в динамические языки программирования пришли типы. Они выполняют роль своеобразных «капканов» для ошибок. Когда программист пишет код, он может воспользоваться Gradual подходом современных языков. И там, где сложность повышена, добавить типы, чтобы в коде расставились несколько «капканов».
Если программист через какое-то время (например, спустя полгода) воспользуется этим кодом неправильно, «капкан» сработает, подчеркнет ему строчку в IDE красным, и все сразу станет понятно.
Gradual подход к перераспределению сложности
Gradual подход к написанию читаемого кода по больше части вращается вокруг цифры 5.
Есть несколько способов перераспределения сложности:
Gradual decomposition;
Если в нашем коде собралось больше пяти элементов, мы пробуем распределить их декомпозицией по файлам, по модулям, по классам, по функциям: в зависимости от того, что у нас есть в языке программирования.
Gradual meta information;
Если мы понимаем, что у нас уже есть распределение на множество частей, начинаем добавлять метаинформацию: давать описательные имена идентификаторам, чтобы они отвечали на вопросы «что это?» и «зачем это?».
Gradual typing.
Наконец, когда сложность продолжает скапливаться, мы добавляем типы, как «капканы» на будущее. Чтобы по возвращению к этому коду через какое-то время, «капканы» сработали и защитили нас.
Gradual подход работы со сложностью можно сформулировать в одном предложении: если количество новых вещей в коде намного превышает цифру 5, нужно использовать один из способов перераспределения сложности из списка выше.
Вопрос о том, что такое «новая вещь», остается немного за кадром. Это зависит от бэкграунда разработчика: сколько лет он пишет код, какие языки программирования, фреймворки, подходы знает.
Если в команде есть разработчики разного уровня (например джуниоры и сеньоры), они не смогут писать код, который будет читаем друг для друга. То, что не является новинкой для сеньора, который 20 лет пишет код, для джуниора ею будет. Поэтому код, который напишет сеньор, будет очень простой, понятный, хорошо читаемый — но для сеньоров. А для джуниоров количество «нового» и, соответственно, сложности в таком коде будет зашкаливать.
Практика показывает: если мы хотим, чтобы код, который пишут наши разработчики, был читаемый в первую очередь для них самих, квалификация тех, кто занимается этим в одной команде, должна быть примерно одинакова.
Писать читаемый код сложно. И Gradual поход, о котором шла речь в статье, не всегда применим. Разработка софта очень разная: есть разработка микроконтроллеров, есть разработка игр, есть бизнес-автоматизация по спецификациям, и там правила игры совершенно другие.
Но в большинстве случаев Gradual подход, который крутится вокруг цифры 5, является неплохой стартовой точкой.
Конференция, полностью посвященная инженерным процессам и практикам, TechLead Conf 2021 пройдет 12 и 13 апреля. Билеты можно приобрести здесь. Вы можете успеть купить их до повышения цены!
А пока мы все ждем апреля, приглашаем вас на Quality Assurance Webinar. На нем поговорим о пирамиде тестирования, узнаем, как найти UI тесты, которые легко могут быть перенесены на более низкие уровни, и разберемся в инфраструктуре тестирования в браузерах.
Мероприятие начнется 21 января в 18:00 мск. До встречи!