В работе со своими студентами я стараюсь обращать их внимание на работу с готовым кодом. Это огромная часть рабочего времени разработчика — крайне редко Вы будете получать возможность написать всё с нуля. Да и наличие фреймворков обязывает к пониманию их работы.

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

Ниже приведён перевод статьи Немила Дадала о чтении кода. Его мнение является сугубо персональным, поэтому после неё я также оставлю несколько заметок со своей стороны. Но теперь не смею отвлекать от чтения!

One secret to becoming a great software engineer: read code

Если однажды проснувшись Вы вдруг решите стать великим писателем, Вы наверняка услышите два простых совета:

  • Много пишите
  • Читайте ещё больше

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

Читайте много и часто. Вероятно, именно здесь кроется разница между хорошим и великим инженерами.

Почему я должен читать код?

Великие писатели унаследовали много от тех авторов, которых они читали. Можно даже назвать их «производными». Вспомните Джоан Дидион, которая в 16 лет перепечатывала предложение за предложением в книгах Хэмингуэя, учась тому, как он их использует. Или о Аврааме Линкольне, чья поздняя лирика берёт начало из его любимой Библии короля Джеймса.

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

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

Свободное чтение чужого кода также снижает вероятность того, что Вы предпочтёте написать свой собственный код вместо работы с имеющимся. Чем больше вы читаете, тем легче Вам будет расширять чужой код, а не создавать свой собственный. Это изменение уменьшит вероятность того, что Вас не поразит синдром неприятия чужой разработки.

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

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

Как говорил Дональд Кнут: “[чтение кода] действительно ценно для того, что оно выстраивает в Вашем сознании. Чем больше Вы изучаете чужие конструкции, тем способнее Вы к созданию своих собственных”.

А теперь о том, как сделать чтение кода безболезненным и продуктивным, насколько это возможно.

Читая код…

Как я должен читать код?

Работа с кодовой базой как с книгой — то есть чтение её от корки до корки — прямой путь к провалу (что забавно, именно так читают код компьютеры).

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

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

Я использую подход из четырёх частей для работы со сложными кодовыми базами (RSDW):

  1. «Запуск» [(R)un]: компилируйте, запускайте и понимайте, что должен делать код с точки зрения пользователя.
  2. «Изучение структуры» [Examine (S)tructure]: Изучайте высокоуровневую структуру и ключевые интеграционные тесты.
  3. «Погружение» [(D)ive in]: Следуйте по пути основных логических потоков и знакомься с ключевыми структурами данных.
  4. «Написание кода» [(W)rite code]: Пишите код, тесты, приоритезируя простые улучшения кода и исправления багов.

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

1. «Запуск» [(R)un]

Первый шаг в чтении кода — это не чтение кода, а применение ПО. Читайте код только тогда, когда поймёте, какую функциональность предлагает программа. На этой стадии Вы будете иметь общее представление о коде, а также понимание о вводе и выводе программы.

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

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

2. «Изучение структуры» [Examine (S)tructure]

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

Начните с понимания структуры кода. Как минимум, запустите пару инструментов (например tree или cloc), чтобы понять, какие языки используются в проекте, а также какова иерархия файлов в проекте.

Чтобы выделить ключевые файлы, обратите внимание на наиболее изменяемые файлы в проекте (Git в помощь). Рассмотрите наиболее важные интеграционные тесты, почитайте код функций, которые в них вызываются. Отметьте такие тесты на будущее.

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

3. «Погружение» [(D)ive in]

Как только Вы почувствуете себя уверенно на поверхности, погружайтесь вглубь.

При чтении кода обращайте внимание на потоки данных и логики (в результате чего создаются те или иные шаги) и знакомьтесь с объектами и структурами данных (где и как хранятся результаты выполнения кода).

Для начала выберите 3-5 важных потоков, которые Вы можете взять из изученных ранее интеграционных тестов или Ваших изысканий по коду. Именно в их направлении производите погружение. Начинайте с вершины конкретного действия и отслеживайте его выполнение (вызываемые методы, состояние) до тех пор, пока не дойдёте до последнего вызова. Некоторые разработчики полагаются на дебаггеры и трассировщики (например, Xdebug в PHP), другие предпочитают строить UML или «пламенные» диаграммы.

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

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

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

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

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

4. «Написание кода» [(W)rite code]

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

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

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

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

Эти методы дают Вам пути к быстрым достижениям, в чём Вы, не зная кода, нуждаетесь больше всего. Наращивая RSDW своими собственными практиками и другими инструментами, Вы будете упрощать процесс чтения кода.

Небольшие подсказки

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

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

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

При том, что важно развивать навыки чтения, также важно быть внимательным к тому, что вы читаете.

Какой код стоит читать?

В самом начале карьере по моему мнению 60% Вашего рабочего времени должно уходить на чтение кода. Около трети его должно уходить на код, с которым Вы не работаете напрямую в своём проекте. Это довольно много времени! Так на что же его тратить продуктивно?

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

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

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

Например, Redis известен как популярная отправная точка в C. Для менее читаемых, более сложных кодовых баз простой способ начать — это прочитать конкретную подсистему.

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

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

Еще один хороший подход к чтению кода — это чтение и переписывание кода разработчиков, которых Вы уважаете. Там, где молодая Дидион перепечатала Хемингуэя или Хантер Томпсон напечатал «Великого Гэтсби», напишите код Антиреса, Гаэрона или Мрдуба, начиная с простой библиотеки. Прочитайте их другие кодовые базы. Будьте в курсе их последних работ.

Стивен Кинг предупредил авторов: «Если у Вас нет времени на чтение, у Вас нет времени (или инструментов) для авторства. Все просто». Аналогичным образом, для разработчиков программного обеспечения написание свежего кода может быть самым интересным, но (активное) чтение кода — это то, что выделит Вас.

Комментарий к статье

Как отмечает и сам автор статьи, не всё нужно безоговорочно принимать к действию. Статья описывает довольно идеальную ситуацию работы с проектом, у которого есть и документация, и знающие люди, и нормальное версионирование. В реальном мире разработки, многого может, к сожалению, и не встретиться. Тем не менее, статья предоставляет множество инструментов и на такой случай. Те же дебаггеры и точки останова уж точно можно применить на любом проекте. А если документации нет, то изучение — самое время её создать!

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

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

В остальном считаю статью крайне полезной в работе. А Вы? 😉