эффективная работа с унаследованным кодом pdf
Эффективная работа с унаследованным кодом pdf
Библиотека программиста запись закреплена
Эффективная работа с унаследованным кодом
Учитесь извлекать максимум пользы из унаследованных систем, повышая их производительность, функциональность, надежность и сопровождаемость!
Можете ли вы без особого труда изменить код и тут же получить ответную реакцию на внесенные изменения? Насколько понятен этот код? Если вы ответите на эти вопросы отрицательно, значит, вы имеете дело с унаследованным кодом и понапрасну тратите время и средства на разработку.
В своей книге Майкл Физерс предлагает полноценные стратегические приемы эффективной работы с крупными базами унаследованного нетестированного кода. В основу этой книги положен материал, подготовленный автором к известным семинарам, организуемым компанией Object Mentor, включая приемы, которым автор обучил сотни разработчиков, технических руководителей и тестирующих программное обеспечение подчинять себе непослушные унаследованные системы.
В этой книге освещаются следующие вопросы:
— Представление о механизмах внесения изменений в программное обеспечение, включая ввод новых свойств, устранение программных ошибок, улучшение структуры кода, оптимизацию производительности.
— Перенос унаследованного кода в средства тестирования.
Написание тестов, препятствующих внесению новых ошибок в код.
— Применение методов, подходящих для любого языка или платформы, с примерами кода на Java, C++, C и C#.
— Точное выявление мест в коде, где требуется внести изменения.
— Работа с унаследованным кодом, который не является объектно-ориентированным.
— Обращение с приложениями, у которых, на первый взгляд, нет вообще никакой структуры.
Кроме того, в этой книге представлены 24 способа разрыва зависимостей, помогающих работать с элементами программного обеспечения обособленно, чтобы сделать внесение изменений в код более безопасным.
Эффективная работа с унаследованным кодом
Можете ли вы без особого труда изменить код и тут же получить ответную реакцию на внесенные изменения? Насколько понятен этот код? Если вы ответите на эти вопросы отрицательно, значит, вы имеете дело с унаследованным кодом и понапрасну тратите время и средства на разработку.
Учитесь извлекать максимум пользы из унаследованных систем, повышая их производительность, функциональность, надежность и сопровождаемость!
В своей книге Майкл Физерс предлагает полноценные стратегические приемы эффективной работы с крупными базами унаследованного нетестированного кода. В основу этой книги положен материал, подготовленный автором к известным семинарам, организуемым компанией Object Mentor, включая приемы, которым автор обучил сотни разработчиков, технических руководителей и тестирующих программное обеспечение подчинять себе непослушные унаследованные системы.
В этой книге освещаются следующие вопросы:
Кроме того, в этой книге представлены 24 способа разрыва зависимостей, помогающих работать с элементами программного обеспечения обособленно, чтобы сделать внесение изменений в код более безопасным.
Здесь можно скачать книгу «Эффективная работа с унаследованным кодом» для ознакомления (бесплатный PDF фрагмент от правообладателя), почитать онлайн или купить полную электронную версию в форматах FB2, PDF, EPUB, TXT, FB3, MOBI.
Эффективная работа с унаследованным кодом pdf
Working effectively with legacy code / Эффективная работа с унаследованным кодом
Год издания: 2009
Автор: M. Feathers / М. Физерс
Переводчик: И. В. Берштейн
Жанр или тематика: Программирование, проектирование, рефакторинг, модульное тестирование, TDD
Издательство: Вильямс
ISBN: 978-5-8459-1530-6
Язык: Русский
Формат: PDF
Качество: Изначально компьютерное (eBook)
Интерактивное оглавление: Нет
Количество страниц: 400
Описание: Из предисловия:
Возможно, у вас, как и у меня, возникают мысли о запутанной, непонятной структуре, коде,
который требуется изменить, но на самом деле вы его просто не понимаете. Поэтому у вас
появляются воспоминания о бессонных ночах, проведенных в попытках ввести в такой
код новые свойства, которые, казалось бы, нетрудно было добавить, о состоянии полной
деморализации и болезненном ощущении от базы кода, вызывающем полное безразличие у всей
группы разработчиков к коду, от которого проще помереть, чем исправить его.
В программировании понятие унаследованный код нередко употребляется как жаргон-
ное обозначение трудноизменяемого кода, который совершенно непонятен. Но приобретя
многолетний опыт работы с группами разработчиков над разрешением серьезных осложнений
с кодом, я пришел к другому определению данного понятия.
С моей точки зрения, унаследованный код — это просто код, не прошедший тесты. Такое
определение далось мне горьким опытом. Что же должны делать тесты для выявления
неудачного кода? Для меня ответ на данный вопрос очевиден, и он составляет главный
предмет, подробно разрабатываемый в этой книге.
Эффективная работа с унаследованным кодом
Автор: Физерс, Майкл
Название: Эффективная работа с унаследованным кодом
Издательство: М.: ООО «И.Д. Вильямс»
Год: 2009
ISBN: 978-5845915306
Язык: Русский
Формат: djvu
Размер: 8,5 mb
Страниц: 400, ил.
Практически каждая проектируемая система страдает недостатком — медленным, разрушительным загниванием. И это загнивание настолько распространено, что для обозначения испорченных программ был придуман специальный термин. Такие программы называют унаследованным кодом.
Унаследованный код. Это выражение инстинктивно вызывает отвращение у всякого, занимающегося программированием. Ведь воображение тотчас рисует ужасные картины продирания сквозь непроходимые таежные буреломы и топи с упорно цепляющимися за ноги ветками деревьев и кустарников, безжалостно впивающимися в тело тучами мошкары и одуряющими запахами гниения, разложения и застоя. Мучения, которые доставляет разбирательство с унаследованным кодом, нередко гасят любые первые порывы энтузиазма, возникающие при программировании.
В книге идет речь о том, как запутанная, непонятная и сложная система медленно, но верно, постепенно и по частям превращается в простую, изящно структурированную и правильно спроектированную систему. Это книга об обращении вспять процесса энтропии.
Поиск и чтение унаследованного кода
Вася — молодой программист. Получив задачу и засучив рукава, он берется за написание кода. Уже через день решение задачи готово, Вася запускает его… И сталкивается с неожиданной досадной ошибкой. Вася старательно исправляет ее и повторно запускает решение. В результате — снова неприятная ошибка. Так Вася долго наступает на грабли, пару раз значительно переписывает программу, пока, наконец, через неделю задача окончательно не решена.
Петя — опытный программист. Получив постановку, он ищет, нет ли исходного кода, решавшего аналогичную задачу. Пару дней Петя проводит, читая материалы и разбираясь в чужих модулях, а на третий — запускает свое решение, основанное на уже существующем коде. В нем есть пара незначительных ошибок, которые удается быстро исправить. Ура! Все работает так, как нужно, уже на третий день.
Как найти нужный вам кусок исходного кода? Как его понять? А главное — зачем все это делать? В поиске ответов на эти вопросы добро пожаловать под кат.
Почему важно уметь искать и читать код?
Д. Томас и Д. Спинеллис в книге «Анализ программного кода на примере проектов Open Source» формулируют несколько важных тезисов.
Чтение кода — это повседневное занятие программиста.
Со стороны кажется, что основная работа программиста состоит в написании исходников, но это не так. Чаще всего код приходится читать, а не писать. Вчера ваш товарищ написал модуль, а сегодня перед вами стоит задача усовершенствовать его или исправить ошибку, что невозможно без предварительного изучения трудов вашего товарища.
90 % ошибок можно устранить при чтении кода.
С цифрой 90 %, как мне кажется, можно поспорить, но основная мысль ясна: при чтении (в данном случае — рецензировании) программы можно (и нужно) выявлять и устранять ошибки.
Нас часто учат писать код, но редко — читать его.
И напрасно, поскольку без чтения существующих исходников приходится постоянно изобретать велосипед. Даже если вы можете написать что-то с нуля, гораздо эффективнее будет осмотреться вокруг и использовать чужой исходный код напрямую или как аналогию. Чужой код проверен, отлажен и, скорее всего, уже содержит какие-то «фичи», которые будут полезны и при решении вашей задачи.
Итак, читайте код, чтобы не писать велосипедов. Читайте код, чтобы вносить изменения быстрее. Читайте код, чтобы в программах было меньше ошибок.
О чем эта статья?
Основная цель статьи заключается в том, чтобы систематизировать существующие подходы к поиску и чтению кода. Знание конкретных подходов дает возможность применять те из них, которые наиболее приемлемы в том или ином случае. Кроме того, статья содержит обзор инструментов, которые позволят эффективно применять описанные в статье подходы. Стоит отметить, что искать и понимать исходный код можно и без специальных инструментов, однако их применение делает процесс более наглядным и менее рутинным.
Приведенные в статье примеры кода взяты из приложений ShareX и Greenshot (оба распространяются под лицензией GNU GPL) из репозитория ShareX по состоянию на 30 июня 2015. Я благодарю авторов этих приложений за возможность воспользоваться их кодовой базой. Также благодарю моих коллег, в особенности Дениса Гаврилова и Владислава Иофе, за высказанные ими замечания во время работы над статьей.
Поиск кода
Поиск кода представляет собой процесс, результатом которого выступают части исходного кода, связанные с тематикой решаемой задачи.
Поиск вне кода
Начинать искать исходники можно и нужно вне кодовой базы. Предварительное общение с командой, чтение документации и баг-трекера могут существенно упростить непосредственный поиск кода. Подробнее о работе с артефактами можно узнать из семинара Д. Гаврилова «Практики командной работы: о пользе письменных артефактов». Помимо чтения документации и общения с командой полезно вспомнить, что вы уже знаете о том, что предстоит найти. Например, если предстоит найти экранную форму, то стоит вспомнить, что название экранных форм в вашем проекте обычно заканчивается на Form, а все формы лежат в сборе ”UI”.
Можно запустить приложение на исполнение и искать экранную форму перебором. При переборе программист открывает в случайном (или не очень) порядке формы до тех пор, пока не найдет окно, кнопку, пункт меню или любой другой элемент интерфейса, который, как кажется, использует искомый функционал. Перебор применяется, когда задача поиска размыта или программист плохо знаком с системой. Например, вы ни разу не работали с приложением, а от вас требуется добавить функцию, которая бы экспортировала все открытые картинки в буфер обмена. Логичным представляется для начала исследовать приложение: посмотреть, умеет ли оно экспортировать картинки в буфер обмена по одной, есть ли какие-то настройки, связанные с буфером или экспортом и т. д.
Поиск по ключевым словам
Ключевое слово — это слово или словосочетание из текста документа или запроса, несущее существенную смысловую нагрузку с точки зрения информационного поиска. Необходимая для поиска подборка ключевых слов формируется через общение с пользователями, просмотр экранных форм перебором и другие методы, описанные выше в качестве поиска «вне кода». Ключевые слова можно взять из описания задачи, экранных форм и действий пользователя, текста ошибки или сообщения, SQL-запроса, то есть из любых артефактов, связанных с решаемой задачей.
Чтобы поиск по ключевым словам был максимально эффективным, необходимо подбирать редкие ключевые слова. Например, если вы работаете над проектом, в котором много разных документов (Document), то поиск по слову Document даст множество лишних результатов. Однако бывают ситуации, когда подобрать редкие ключевые слова нет возможности. В этом случае сначала нужно найти множество потенциально полезной информации, а затем сузить поиск. Например, найти все существующие упоминания Document, а затем исключить из результатов тесты, поискать в найденных файлах дополнительные ключевые слова и т. д. В целом следует стремиться найти хотя бы что-то (чуть больше или чуть меньше), а не именно то, что нужно.
В большинстве случаев для поиска по ключевым словам достаточно встроенного в IDE поиска (обычно он вызывается сочетанием клавиш Ctrl + F). Иногда может быть полезен файловый менеджер — для поиска в папках, которые не входят в программное решение, — или поисковые движки: например, OpenGrok и DocFetcher (о них речь пойдет ниже). Так, ReSharper содержит полезную функцию Search by Pattern, с помощью которой можно найти, например, все свойства классов, объявленные как нулябельные перечисления (public TEnum? Enum < get; set; >). Конечно же, не стоит забывать и про мощный механизм регулярных выражений; да, он требуется редко, но иногда здорово выручает.
Давайте поговорим чуть подробнее про поисковые движки, работающие с исходным кодом. Главное преимущество поисковых движков состоит в том, что они позволяют осуществлять гибкий поиск. Например, нужно найти все классы, в которых есть упоминания Clipboard и Image. Обычные средства, встроенные в IDE, дадут вам возможность найти либо файлы с Clipboard, либо файлы с Image. Здесь за скобками оставляем пресловутый механизм регулярных выражений: он может помочь, но конструкция поиска будет громоздкой. Более сложный пример, с которым встроенные средства поиска не справятся: необходимость найти свойства классов, помеченные атрибутом A, но не помеченные атрибутом B. Помимо гибкости поисковые движки увеличивают скорость поиска. Если вашей IDE нужна пара-тройка, а иногда и не один десяток секунд, чтобы пробежаться по всем файлам проекта, то поисковый движок имеет индекс, позволяющий делать то же самое в доли секунды.
Существуют различные поисковые движки по исходному коду, можно почитать их обсуждение на StackOverflow или ознакомиться с подборкой на сайте beyondgrep.com. В своей работе я использую OpenGrok: он бесплатный и умеет работать с различными языками, такими как C#, C, PHP, SQL и с десяток других. Движок состоит из 2-х модулей: модуля индексации исходников и веб-приложения для поиска и навигации по коду. Первый модуль индексирует папки проекта в файловой системе. Веб-приложение работает под Apache, позволяет вводить разные поисковые запросы и просматривать полученные результаты. OpenGrok написан на Java, доступен для скачивания на официальном сайте проекта, а в соответствующих статьях можно прочитать о том, как установить движок под Windows и под Linux.
OpenGrok поддерживает различные виды поиска: по тексту всего документа или только в определениях, то есть названиях классов, функций. Кроме того, он позволяет задавать фильтрацию папок и названия искомого файла, выбирать язык, на котором должен быть написан код и т. д. Этот движок показывает результаты в наглядной форме, сгруппированными по файлам, а также позволяет в один клик перейти к нужной строчке в файле и умеет показывать код с подсветкой или в «сыром» виде.
Поисковый запрос и результаты поиска в OpenGrok по ShareX
У OpenGrok есть несколько ограничений: во-первых, отсутствует интеграция с Visual Studio, во-вторых, он не умеет работать с кириллицей (по крайней мере, мне не удалось добиться этого при помощи настроек). Если вам часто приходится искать русский текст, то можно использовать DocFetcher: данный инструмент не заточен напрямую под поиск в исходниках, но умеет индексировать любые текстовые файлы и отлично справляется с русским языком.
В таблице ниже представлено сравнение возможностей поисковых движков OpenGrok и DocFetcher.
С помощью этой таблицы можно выделить для себя необходимые параметры поиска и выбрать наиболее подходящий инструмент.
Параметр | OpenGrok | DocFetcher |
---|---|---|
Гибкость поиска (через поддержку поискового языка) | Да | Да |
Быстрота поиска (через индексацию) | Да | Да |
Специальные инструменты для поиска кода | Да | Нет |
Работа с кириллицей | Нет | Да |
Интеграция с Visual Studio | Нет | Нет |
Мультиплатформенность | Да | Да |
Лицензия | CDDL | Eclipse Public License |
Поиск по классификаторам
Классификатор — это систематизированный перечень наименованных объектов. Наиболее востребованным программистами классификатором, на мой взгляд, является список всех классов программного решения. Примерами других классификаторов могут быть список членов классов, упорядоченных по классам, список файлов, упорядоченных по папкам и др.
Классы приложения ShareX
С одной стороны, классификатором можно пользоваться как инструментом работы с древовидным списком. Вы «разворачиваете» базовое пространство имен программного решения, далее «разворачиваете» пространство имен нужного модуля и так далее, пока, наконец, не доберетесь до нужного класса. С другой стороны, внутри классификатора можно осуществлять сквозной поиск. Например, вы набираете *Document*, а классификатор показывает все классы, в названиях которых встречается Document.
Если вы работаете с ReSharper, то наверняка знаете про функцию Go to Everything, которая позволяет перейти к любому классу, методу, свойству или файлу во всем программном решении. В Visual Studio «из коробки» есть следующие классификаторы: Solution Explorer (классифицирует сборки, папки, файлы, классы и их члены), Class View (классифицирует пространства имен, классы и их члены) и Object Browser (классифицирует сборки, пространства имен, классы и их члены). Solution Explorer и Class View выдают перечень классов внутри вашего решения, а Object Browser — как в вашем решении, так и в сторонних используемых сборках. OpenGrok позволяет искать по определениям (Definition), в том числе с использованием символов подстановки (*Document*). Еще один классификатор — это обычный файловый менеджер, который отображает артефакты, упорядоченные по папкам.
Когда следует применять классификаторы? Чтобы успешно использовать классификатор, программист должен хорошо знать программный продукт. Особенно важно, в частности, знать соглашения об именах (например, *Form — это экранная форма, а DocumentNameListForm — списочная форма документов типа DocumentName), а также принципы, по которым классы упорядочиваются в папках и пространствах имен (в Dictionaries лежат справочники, а в Documents — документы). Еще одна возможность применения поиска по классификатору — ситуация, когда известно точное название класса или его члена.
Поиск ошибки
Периодически возникает задача найти строчку кода, в которой возникает некоторая ошибка. Как вариант, нужную строчку можно найти по известному номеру ошибки. В данном случае номер ошибки — ключевое слово, по которому осуществляется поиск (про поиск по ключевым словам было рассказано выше). В иной ситуации может быть известна трассировка стека ошибки. В ReSharper есть удобный инструмент Stack Traces, который позволяет просматривать стек и перемещаться по методам, которые вызывались перед тем, как произошла ошибка. Чтобы использовать Stack Traces, необходимо скопировать стек ошибки в буфер обмена, после чего в Visual Studio нажать Shift + Ctrl + E.
Просмотр стека ShareX и навигация по нему в Stack Traces
Если у вас нет информации ни о номере ошибки, ни о трассировке стека, можно запустить проект и включить прерывания по ошибке. Для Visual Studio создано удобное дополнение Exception Breaker, позволяющее включать и выключать прерывание по ошибке одним кликом мыши.
По действию пользователя
Иногда требуется узнать, какой метод вызывается при нажатии кнопки или другом действии пользователя. В этом случае можно сначала найти класс, в котором находится вызываемый метод (например, поиском по ключевым словам или по классификатору), а затем расставить точки останова во всех членах этого класса и запустить приложение. В веб-приложениях в некоторых случаях бывает полезен Fiddler, в частности, в нем можно посмотреть название вызываемой WCF-функции и значения переданных в нее параметров.
Итоги
Перед тем как приступать к поиску кода, стоит потратить немного времени на общение с командой, чтение документации и перебор экранных форм. Это необходимо для того, чтобы собрать ключевые слова, узнать названия классов и методов, без которых дальнейший поиск будет затруднительным. Начинать его стоит с самого простого, при этом можно найти чуть больше или чуть меньше, чем требуется. Искать исходники также можно при помощи ключевых слов или классификаторов. Для поиска ошибок и функций, вызываемых по действию пользователя, есть специальные методики.
Понимание кода
Поиск кода неразрывно связан с его пониманием. Понимание необходимо, чтобы выделить из всех найденных действительно полезные для решения задачи блоки исходников, чтобы понять, как надо модифицировать и как можно использовать полученные при поиске результаты.
Понимание без чтения кода
Вне кодовой базы начинается не только поиск кода, но и процесс его понимания. Запуск приложения, чтение документации, баг-трекера, лога приложения или системы контроля версий, общение с командой и (или) пользователями дают хорошее представление о том, что происходит внутри приложения. Так же, как и при поиске исходников, перед непосредственным чтением кода важно вспомнить, что уже известно про разбираемую область.
Чтение «черного ящика»
Чтение кода как «черного ящика» предполагает, что по некоторым внешним признакам мы пытаемся установить, что происходит внутри функции или класса. О назначении объекта можно догадаться, посмотрев на его имя, принимаемые параметры и возвращаемое значение. Например,
по всей видимости, помещает изображение image в буфер обмена, а информацию о произошедших ошибках помещает в возвращаемый ResultOrError.
Для чтения «черного ящика» важно знать соглашения об именах, то есть о принятых в проекте префиксах, постфиксах и других частях названий. К «черному ящику» относится чтение описаний или комментариев внутри функций.
Чтобы убедиться в правильности предположений о назначении функции, можно изучить ее использование. Также можно найти, какие действия пользователя приводят к вызову функции (например, пользователь нажал на кнопку «Копировать в буфер») и на основе этих знаний понять, что пользователь ожидает получить в результате выполнения функции (в нашем случае, очевидно, скопировать некий объект в буфер обмена).
ReSharper предлагает мощные инструменты Inspect This и Find Usages, которые позволяют найти места, из которых вызывается функция. Inspect This представляется более удобным, поскольку позволяет легко и наглядно осуществлять дальнейший поиск фрагментов кода, из которых вызываются места, где вызывается функция, и так далее. В самой Visual Studio «из коробки» доступен инструмент Call Hierarchy, который имеет возможности, аналогичные Inspect This.
Чтение «белого ящика»
Если в «черном ящике» код метода был для нас «закрыт» (мы изучаем исходники на границе и вокруг функции), то в «белом ящике» предполагается изучение кода внутри исследуемого метода.
При «белом ящике» важен порядок чтения исходников. С одной стороны, чтобы понять код, не надо читать его целиком, поэтому начинать чтение стоит с наиболее важных его частей, пропуская менее значимые строки. С другой стороны, от последовательности чтения зависит быстрота понимания. Чтение слева направо и сверху вниз — не лучший способ погружения в исходники.
Один из приемов чтения «белого ящика» состоит в чтении «вглубь»: вначале читаем код первого уровня, затем переходим ко второму и так далее по уровням.
Чтение «вглубь» (ShareX.UploadManager.UploadFile: 43-64)
Для Visual Studio есть дополнение C# outline, которое позволяет сворачивать и разворачивать текст внутри if, for и других управляющих конструкций («из коробки» Visual Studio умеет сворачивать и разворачивать пространства имен, классы, регионы и методы, но не if, for и подобные им конструкции).
Другой способ чтения кода как «белого ящика» состоит в чтении «от ключевых мест». Как правило, это места, где функция возвращает или вычисляет результат, каким-то образом использует входные параметры, делает вывод в файл, на экран или другое устройство. Ключевые места в разных функциях могут быть различными. Важно уметь их найти и прочитать в первую очередь.
Для Visual Studio есть дополнение RockMargin, которое подсвечивает в редакторе и на полосе прокрутки все места, в которых встречаются вхождения выбранного ключевого слова. Например, вы два раза щелкаете на taskSettings, а RockMargin подсвечивает все места, где встречается taskSettings в файле:
Подсветка RockMargin для ShareX\UploadManager.cs
В вашем приложении, скорее всего, есть много однотипных, шаблонных кусков. Это могут быть как общеиспользуемые шаблоны (например, Singleton), так и шаблоны, специфичные для вашего проекта (например, какие-то особенности в построении UI). Понять, что делает шаблон, можно по двум-трем ключевым словам, поэтому шаблоны надо учиться читать «целиком», без «разбора букв». Например, на картинке ниже — класс-Singleton, о чем можно догадаться по двум строкам кода, которые выделены красным.
Класс-Singleton (Greenshot.Drawing.Fields.Binding.DecimalFloatConverter:29-52)
Еще одна последовательность, которую следует соблюдать при чтении исходников, состоит в чтении от простого к сложному. Вначале разберитесь с тем, что понятно и так, а затем переходите к более сложным конструкциям.
В заключение раздела о «белом ящике» я бы хотел сказать несколько слов о чтении при рецензировании кода. Перед непосредственным чтением (особенно если прорецензировать предстоит объемную доработку) следует просмотреть названия всех измененных файлов, а затем понять, в каких файлах произошли ключевые изменения. Чтение необходимо начинать с файлов с ключевыми изменениями, из которых вы схватите общую суть и лучше поймете все остальные доработки.
Улучшение кода
Чтобы понять исходный код, можно не только читать его, но и улучшать. Самый простой способ улучшить восприятие кода — правильно расставить отступы. Другой способ улучшить читабельность — рефакторинг. Простейшие переименования и разделение длинных функций на несколько коротких позволяют быстро сделать текст программы более понятным.
Для понимания сложных логических конструкций можно применять законы де Моргана:
В качестве инструмента по улучшению кода можно порекомендовать ReSharper, который справляется с улучшениями разной степени сложности.
Режим отладки
Режим отладки дает возможность проверить сделанные во время чтения исходников предположения. Чтение в режиме отладки предполагает использование таких инструментов, как точки останова (в том числе точки останова «по условию», например, срабатывающие только при определенном значении переменных), просмотр трассировки стека, пошаговое выполнение программы, просмотр и модификация значений переменных.
Общая картина
При чтении важно поддерживать общее представление о том, что происходит в разбираемом модуле, и уметь быстро перемещаться по разным местам «паззла».
Чтобы удержать в голове общую картину, можно использовать диаграммы, как уже существующие в проекте, так и новые. Некоторые диаграммы можно строить автоматически, особенно это актуально для SQL-запросов. В PL/SQL Developer, например, есть Query Builder, который показывает, какие таблицы участвуют в запросе и как они между собой связаны. Автоматизированно можно строить диаграммы классов, к примеру, в Visual Studio для этого применяется инструмент View Class Diagram. Однако чаще всего достаточно даже нарисованной от руки схемы.
Читать вызываемые методы удобно при помощи ReSharper, Inspect This или встроенного в Visual Studio View инструмента Call Hierarchy. В разделе про «черный ящик» эти инструменты уже рассматривались, но там исследовались места, из которых вызывается функция. Здесь же речь идет о просмотре методов, которые вызываются внутри функции. Inspect This и View Call Hierarchy дают целостную картину — вы видите дерево вызовов целиком — и позволяют быстро по нему перемещаться.
Для быстрых переходов по произвольным блокам кода можно закреплять вкладки (чтобы отличать те 5–10 классов, с которыми вы плотно работаете, от других 20–100, которые пришлось открыть в процессе работы), делать закладки в редакторе или записи от руки, например, выписывать названия классов и их членов.
Для быстрых переходов внутри файла будут полезны: в ReSharper — File Structure (отображает члены текущего класса), в Visual Studio — Member (аналог File Structure) или RockMargin (отображает уменьшенный исходный код на широкой полосе прокрутки, подкрашивает закладки и точки останова).
Итоги
Перед непосредственным чтением исходников важно обратиться к различным источникам вне кодовой базы: пообщаться с командой, почитать документацию, запустить приложение на выполнение. Это даст некоторое базовое понимание приложения, которое поможет в непосредственном чтении кода. Читать исходники можно как «черный ящик», анализируя названия методов, принимаемые ими параметры и т. д. как «белый ящик», производя разбор того, что находится внутри метода. Для облегчения восприятия кода его можно улучшить, например, расставить отступы. Запуск приложения дает возможность проверять сделанные предположения в режиме отладки. Наконец, при чтении важно удерживать общую картину в голове и уметь быстро перемещаться по разным частям исследуемого модуля.
Заключение
Поиск и понимание кода — важный этап в работе над программным продуктом. Поиск и понимание начинаются за пределами репозитория: с общения с командой, чтения документации, баг-трекера, запуска приложения на исполнение. Поиск и понимание необходимы как при доработке существующих модулей (чтобы доработать существующий модуль, надо понять, как он работает), так и при разработке нового функционала: да, новый модуль иногда можно разработать, не прочитав ни строчки кода, но в проекте, скорее всего, есть отдельные блоки, реализующие схожий функционал, которые можно взять в качестве шаблона для реализации функций и классов.
По моему мнению, чтение кода в широком смысле этого слова (то есть как поиск исходников, так и их понимание) должно выделяться разработчиком в отдельный этап работы над задачей. Результатом этого этапа является набор закладок в методах и файлах, который будет полезен при работе над задачей, а также общее представление о работе некоего блока кода. Уже в рамках непосредственного программирования поиск исходников необходимо продолжать. Например, так: встретил новый класс, нашел места, где он используется, обновил список полезных закладок. Возможно, подбор закладок можно выделить отдельной функцией в команде: технический лидер или ответственный разработчик составляет список полезных закладок, после чего программист берет задачу в работу.
Как для поиска, так и для понимания исходников важно знать соглашения об именах и способах упорядочивания классов (по папкам, пространствам имен). По опыту автора, такое понимание приобретается в процессе работы в проекте, однако соглашения можно формализовывать и сообщать новым разработчикам так же, как соглашения по оформлению кода (Code Style Guide).
Перспективным представляется разработка автоматизированных средств, выявляющих фактически сложившиеся соглашения об именах и способах упорядочивания классов. Как кажется, полезными будут средства, выявляющие наиболее часто встречающиеся названия папок, суффиксы, постфиксы и т. д.
При чтении кода, как и при чтении обычной книги, важно осознать и держать в голове цель чтения. Для чтения кода можно применять некоторые приемы из статей о способах чтения обычного текста (см., например: «Как улучшить свою способность понимать прочитанный текст?»).
Насколько можно оценить, поиск и понимание кода является темой, слабо затронутой в отечественной и зарубежной литературе. Надеюсь, что представленная статья была полезной в освоении приемов эффективной работы с кодовой базой.