Прокачайте навыки обратной разработки
Ричард Фейнман, один из величайших учёных и физиков нашего времени, однажды произнёс знаменитую фразу: «Чего я не могу воссоздать, того я не понимаю». Он имел в виду, что, начав с чистого листа бумаги и опираясь только на знания, которые уже есть в голове, он способен заново вывести любой теоретический результат. Именно эту способность Фейнман считал подлинным признаком понимания.
Я и сам твёрдо убеждён, что фундаментальные вещи знать необходимо. Хорошее владение существующими решениями типовых задач — абсолютно необходимое условие для того, чтобы придумывать новые. Нужно знать, как решается каждая уже решённая задача в той области, в которой вы работаете.
Но есть сложность — где взять такие знания? В сегодняшнем стремительном мире у авторов технологий почти не остаётся времени писать тексты, раскрывающие фундаментальные основы. Так что же делать? Я выступаю за обратную разработку.
Меня знают как человека, который занимался обратной разработкой Angular. Но Angular — не единственный фреймворк, который я разбирал детально. Я изучал Vue.js, Webpack, jQuery и множество других веб-библиотек и фреймворков. Сейчас я разбираюсь с React. И, как мне кажется, я накопил достаточно наблюдений, чтобы поделиться ими и помочь вам начать заниматься обратной разработкой.
Для меня процесс обратной разработки — это магия открытия нового. Это состояние увлечённости новыми находками и мышление хакера: постоянное любопытство. Надеюсь, это руководство поможет вашему уму прийти в то же состояние.
Свои наблюдения я разделил на две статьи. Эта статья описывает подходы и принципы, которыми я пользуюсь при обратной разработке. Вторая показывает практическое применение этих принципов на реальном процессе обратной разработки небольшой части React. В ней же демонстрируется несколько интересных приёмов отладки, которые ускоряют работу.
Но сначала давайте разберёмся, зачем вообще заниматься обратной разработкой.
ЗАЧЕМ
Признаем: обратная разработка — тяжёлый труд. Она отнимает много времени и обычно требует солидной базы знаний. Так зачем же за неё браться?
Большинство считает, что главная цель обратной разработки — углубить знания о технологии, чтобы найти работу получше. А поскольку срок жизни современных технологий довольно короток, вкладывать время в слишком глубокое погружение вроде бы бессмысленно.
Разбирая исходный код, вы почти наверняка получите отличное понимание технологии. Но это лишь одна из множества выгод.
По мере чтения исходников вы познакомитесь с новыми паттернами проектирования для решения типовых задач, которые потом сможете применять в работе. Я много раз убеждался в этом на собственном опыте. Например, разбирая Angular Router, я научился лениво загружать компоненты и модули — и это помогло мне построить платформу на основе плагинов.
Вы узнаете много новых возможностей языка. Разбирая Angular, я узнал о мономорфизме в JavaScript. Вы изучите API нижележащей платформы, потому что большинство технологий активно им пользуются. Вы найдёте новые темы для изучения и увидите их практическое применение, а не просто прочитаете о них в книге, гадая, где это может пригодиться.
А если вы решите поделиться находками с сообществом, это поможет вам выстроить публичный профиль. Это ситуация, выгодная всем: помогая другим, вы помогаете себе. Моя история успеха началась с Angular-In-Depth (AiD), когда я решил начать писать о своих находках. С тех пор AiD вырос в крупнейшее издание об Angular и заметно помог мне начать выступать на конференциях и найти отличную работу в ag-Grid. Углублённо изучая технологию, вы заодно демонстрируете умение решать задачи, целеустремлённость и любознательность. Именно эти качества инновационные компании ищут в кандидатах.
Ещё вы научитесь спокойно читать чужой код и осваивать новые кодовые базы. Роберт Мартин, известный как «дядюшка Боб», оценивает соотношение времени, потраченного на чтение и на написание кода, как более чем 10 к 1. Мы постоянно читаем старый код, чтобы написать новый. Именно с этого начинают все разработчики, приходя в существующий проект. И, практикуя обратную разработку, вы получите здесь преимущество.
Как видите, обратная разработка сделает вас более сильным инженером.
Знания, которые облегчают обратную разработку
Сначала посмотрим, что нужно знать, чтобы процесс обратной разработки шёл легче и быстрее. Потратьте время на изучение и освоение этих вещей. Знать нужно немало, и, скорее всего, сейчас у вас этих знаний нет. Ничего страшного. Выделяйте час-два в день на осознанное обучение и поставьте цель стать экспертом в этих областях. Вы дойдёте.
Уверенное знание нижележащей платформы
Первое требование для успешной обратной разработки — знать API нижележащей платформы. Если речь о фреймворках и библиотеках, работающих в вебе, вам нужно хорошо владеть следующим: JavaScript, DOM API и API браузера.
Уверенное понимание JavaScript — это не «я знаю, что такое замыкание и как разрешается this». Уверенное понимание означает знание большинства продвинутых вещей: дескрипторов свойств (их использует Vue.js), объектов Proxy или битовых масок (их использует Angular).
Что касается DOM и API браузера, недостаточно уметь создать и добавить DOM-узел или выполнить колбэк асинхронно. Нужно понимать, что произойдёт, если заново добавить уже существующий дочерний узел, или как браузеры работают с неизвестными элементами. Изучите существующие API для HTTP-запросов и их тонкости — например, когда именно вызывается колбэк ошибки в XHR.
Чтобы освоить JavaScript, я рекомендую книги Акселя Раушмайера. Чтобы освоить DOM и API браузера — MDN web docs и Google developers web updates. А если вы научитесь читать спецификации, это, конечно, идеальный источник: EcmaScript для JavaScript и WHATWG для браузерного окружения.
Инструменты отладки
Крайне важно знать инструменты разработчика вашего любимого браузера вдоль и поперёк. Мой любимый браузер — Chrome. Работая в Chrome, вы должны знать:
- что означает
$0, если набрать это в консоли - как работать с условными точками останова
- как остановиться перед исключением
- как пропустить часть кода или выйти из текущей функции
- как найти конкретный текст в загруженных исходниках и т. д.
Лучший ресурс по Chrome Dev Tools — это, конечно, Google’s Tools for web developers.
Распространённые паттерны проектирования и общие архитектурные концепции
Иногда технологии используют распространённые паттерны проектирования, поэтому их полезно знать. Например, Webpack опирается на паттерны асинхронного выполнения JS, реализованные в библиотеке async. Все фреймворки и библиотеки до появления ES-модулей использовали для распространения формат упаковки UMD. Чем больше фреймворков и библиотек вы изучите, тем лучше начнёте узнавать общие паттерны — и тем быстрее будете продвигаться по коду.
Концепции, относящиеся к конкретной технологии
Помогает и знание концепций, которыми оперирует фреймворк или библиотека. Например, прежде чем браться за обратную разработку современного фреймворка, стоит понимать, что такое компонент. Иногда эти концепции можно почерпнуть из документации, иногда — из углублённой статьи или проектного документа. Прочитайте всё, что найдёте, прежде чем лезть в код. Читайте о новых концепциях по мере того, как встречаете их в коде. Советую выбирать материалы с конкретными деталями реализации, а не сильно упрощённые версии для широкой аудитории. Доклады с конференций обычно не лучший способ узнать конкретику. Проектные документы на Github и продвинутые статьи гораздо полезнее.
Подходы к изучению исходников
Прочитайте следующую статью, чтобы увидеть, как я применял эти подходы, разбирая исходники React. Советую записывать крупицы знаний, которые вы обнаруживаете по ходу дела. Позже вы сможете сложить всё воедино и увидеть общую картину.
Определите ту часть технологии, на которой сосредоточитесь
Чаще всего меня спрашивают, с чего начать и куда поставить debugger в кодовой базе. На это отвечает ваша цель. Прежде чем начинать обратную разработку, у вас всегда должно быть представление о том, какую часть технологии вы хотите понять. Например, разбирая Angular или React, я в первую очередь хотел понять обнаружение изменений. Именно на этой части фреймворка мне нужно было сосредоточиться. Зная, как устроен современный процесс обнаружения изменений, я понимал, что суть его — в синхронизации изменений из экземпляра компонента в DOM-узлы. Значит, мне нужно было найти, где эти фреймворки хранят ссылки на созданные DOM-узлы. Это и было целью.
Мыслите как учёный
Я считаю, что научный метод — наблюдение, формулирование гипотез (предположений) на основе наблюдений и их экспериментальная проверка — самый эффективный способ получения знаний. Эту же модель я использую при обратной разработке. Основные шаги:
- Сделайте наблюдение и сформулируйте гипотезу.
- Сделайте прогноз на основе гипотезы.
- Проверьте прогноз.
Получив результаты, используйте их для новых гипотез и прогнозов. Повторяйте, пока не разберётесь в интересующей вас части.
Чтобы сформулировать гипотезу и сделать прогноз, пользуйтесь выводом по косвенным признакам. Такой вывод — это использование наблюдения и фоновых знаний для логического заключения. Например, если вы видите, как человек пробует новое блюдо и морщится, вы заключаете, что ему не понравилось. Или если кто-то хлопает дверью, можно заключить, что он чем-то расстроен.
Помимо того что это даёт структурированный подход к обратной разработке, я считаю, что предположения (гипотезы) и их проверка создают в памяти опорные точки, которые помогают дольше удерживать выученное и извлекать его при необходимости.
Чередуйте отладку, изучение реализации в исходниках и чтение комментариев
Обратная разработка — это не только чтение исходников. На самом деле я трачу лишь около 20% времени на проверку конкретной детали реализации в коде. Около 70% времени уходит на отладку тестового приложения. Поэтому я и считаю, что хорошее владение инструментами отладки незаменимо для эффективной обратной разработки. Оставшиеся 10% времени я трачу на чтение комментариев в исходниках или пояснений к концепциям, обнаруженным в коде. Обычно комментарии гораздо полезнее всего, что можно найти в интернете, так что никогда не отмахивайтесь от них как от чего-то незначительного.
Стройте поток выполнения приложения по стеку вызовов
Продвигаясь в отладке и расставляя точки останова в разных местах кода, регулярно заглядывайте в стек вызовов. Порядок вызовов функций даст вам представление о потоке выполнения приложения. Часто это же помогает найти в исходниках функции с нужной функциональностью.
Не расстраивайтесь, если гипотеза оказалась неверной
Готовьтесь к тому, что большинство ваших предположений окажутся ошибочными. Это нормальный и ожидаемый процесс. Иногда это значит, что стоит потратить больше времени на фоновые знания. Но часто это означает лишь, что паттерны, реализованные во фреймворке или библиотеке, — новые.
Не то чтобы вы совсем не будете расстраиваться. Будете. Но держите цель перед глазами, преодолевайте это и двигайтесь дальше. Ошибившись, вы только что узнали что-то новое.
Давайте себе время подумать над найденным
В книге «Думай как математик» Барбара Оакли рассказывает о двух чередующихся состояниях ума — сфокусированном и рассеянном. Оба необходимы, когда изучаешь что-то новое. Сфокусированный режим — это прямое решение задач с помощью рационального, последовательного и аналитического подхода. Рассеянный режим позволяет внезапно по-новому взглянуть на задачу, над которой вы бились, и связан с видением «общей картины». Рассеянный режим наступает, когда вы ослабляете внимание и просто позволяете мыслям блуждать. Поэтому не сидите часами перед компьютером: регулярно делайте короткие перерывы и обдумывайте найденное. Я просто хожу по квартире. И делаю так при любой творческой работе — например, когда пишу, — а не только при обратной разработке.
Начните с получения исходников и настройки тестового приложения
Чтобы разобрать фреймворк или библиотеку, вам понадобятся её исходники и тестовое приложение на этой технологии. Сегодня большинство фреймворков и библиотек живут на Github, так что просто клонируйте репозиторий. Изучать всегда нужно конкретную версию, поэтому зайдите во вкладку «releases» репозитория и посмотрите последний релиз. Клонировав репозиторий, переключитесь на этот релиз командой git checkout tags/[version].
Второй шаг — собрать тестовое приложение. Всегда старайтесь сделать максимально простую конфигурацию. Избегайте сборщиков вроде webpack и CLI-инструментов современных фреймворков. По моему опыту они заметно усложняют отладку. Идеальная конфигурация — обычная HTML-страница с кодом, подключённым из CDN, например с unpkg.com. Только убедитесь, что версия фреймворка или библиотеки совпадает с версией, которую вы переключили в исходниках.
Пара слов об удаче
Как и во всём в жизни, удача играет свою роль. Проходя раз за разом по одному и тому же участку функциональности, вы можете наткнуться на новый комментарий, проясняющий какую-то концепцию, или на вызов функции с говорящим именем, который раньше не замечали. Со мной такое случается часто. Поэтому советую несколько раз пройти отладчиком по тому куску кода, который вам непонятен. Или вернуться к нему позже. Не бросайте его совсем только потому, что сейчас не понимаете. Велика вероятность, что в следующий раз вы найдёте там что-то новое — потому что успели набрать новых знаний.