Я прочитал одно исследование о том, как мы читаем код. В статье описывается эксперимент с устройством, способным следить за направлением взгляда человека и определять зоны, на которых испытуемый фокусируется, когда ему предлагают для просмотра кусок кода. Каждый из участников эксперимента получил по шесть фрагментов кода, содержащих по ошибке. Задачей испытуемых было проанализировать код и найти соответствующие ошибки.
Вот выдержка из статьи:
Слева на картинке изображён код, который суммирует числа от одного до заданного максимума. В правой части - траектория движения взгляда во время чтения кода. Заметьте как глаза кодера сначала сканируют заголовки функций, затем кратко сканируют тело функции, а уже затем взгляд фокусируется там, где проблема скорее всего должна быть в реальном коде (цикл)
Чтение кода похоже на чтение Талмуда
Это напомнило очень старый пост Джоэля Спольского. Джоэль цитировал в нём Сета Гордона:
Тактика и техника чтения Талмуда, как мне кажется, могут быт полезны и для чтения кода.
Как полагается читать Талмуд:
- Работайте в парах, проговаривая вслух мысли друг другу.
- Аргументируйте и требуйте аргументации. Если ваш партнёр озвучивает какую-то идею X, и вы её не понимаете или имеете другую позицию, требуйте объяснений.
- Время от времени, когда вы имеете дело с каким-то участком текста, часто проще понять его содержание уже после того, как вы прочитаете текст целиком. Таким образом, если вы затупили в каком-то моменте, попробуйте пропустить его, поняв, что вы можете вернуться к нему позже. (Но так или иначе к нему надо будет вернуться).
- Читайте "изнутри" и "снаружи". Внутреннее чтение подразумевает перевод на английский (ну или любой другой язык, которым вы оперируете) фраз одну за другой, внешнее чтение предполагает перевод целого куска разом для осознания общего смысла. Если вы читаете только последовательно, вы можете потерять целое в частностях, при попытке осознать текст исключительно целиком по смыслу, вы теряете детали.
- Зависимость классов и интерфейсов: обратите внимание на классы, которые не зависят от других классов. Это обычно небольшие и довольно простые объекты, чьё предназначение заключается в первоначальной поддержке организации работы. Они могут выполнять какие-то вычисления, но обычно созданы для хранения данных и поддержки get-set функций. Это код Типа 1. Просмотрите их в первую очередь.После того как вы ознакомитесь с базовыми блоками, вы можете перейти к изучению управляющих классов. Чаще всего это здоровенные "мохнатые" классы, которые представляют собой фактически ядро программы. Это классы Типа2. Убедитесь, что вы поняли из названий функций, какая из них чем управляет.После чего вы можете углубиться в их изучение. Управляющие объекты обычно можно понять только в их взаимодействии друг с другом, соответственно вы должны иметь представление о том, как они спроектированы до того, как уже погружаться в их исследование. (Хинт: управляющие классы не всегда называются соответствующим образом. Обычно это классы, вызывающиеся из main()).
- Предполагайте. Предполагайте, что могут значить имена функций и переменных. Если бы вы писали код, что бы делала функция GetNetIndex? Предположите, что она делает как раз то, что вы думаете. Если из названия функции очевидно вытекает её предназначение, пропустите её. Вы к ней всегда сможете вернуться, если вам это когда-либо понадобиться. Зачем тратить время на то, что вам сейчас не нужно? Если вы начнёте в этом всём сейчас копаться, вы начнёте забывать то, что прочитали перед этим. Сконцентрируйтесь на значении и структуре, а не реализации.
- Отладка решает. Юнит тесты важны, но реальный код значит куда больше. Если вы действительно хотите понять, как работает код, быстрейший способ сделать это запустить его. Раскочегарьте ваш IDE и на скорую руку напишите грязную и примитивную демку того, как вы в целом планируете использовать код. Шансы на то, что это сработает, минимальны. Я буду удивлён, если всё заработает с первого раза. Это Ок. Начните отладку.Через неё вы поймёте особенности работы кода (и его баги) изнутри гораздо быстрее, и вы сможете сфокусироваться на тех частях кода, которые действительно для вас важны.
- Правильные имена функций решают: мы давно все всё это прекрасно знаем, но мы всё равно должны понимать, что именно имена мы читаем в первую очередь. Хорошее, правильное название функции - и вам не придётся лишний раз углубляться в её реализацию.
- Правильные имена переменных решают: опять-таки ничего нового. Вспомните, как часто глаза возвращаются к определению переменной и присвоению ней значений. Мы постоянно ищем в коде напоминания о значении переменной.
- Циклы - корень всех зол: конечно, не одни они, но они хуже всех других утверждений. Вспомните, что прояснение работы циклов, это самое затратное по времени занятие при разборе кода. В них и скрывается большая часть ошибок. (Да, в индексе их не сильно меньше или даже столько же, я забыл, да). Комментирование в каком-то роде помогает, но сохранение простоты и читабельности кода определяет. Упрощайте сложность циклов.
- Короткий код проще обрабатывать, поэтому достаньте свои тулы по рефакторингу из инструментария, время разделять функции.
- Мой любимый гайд по написанию читабельного кода - это книга дяди Боба Мартина "Clean Code: A Handbook of Agile Software Craftsmanship." Даже если в некоторых моментах она скучна и в ней хватает переусердствований, она остаётся отличным пособием для практикующего кодера, разбирая многие важные моменты написания читабельного кода и рефакторинга.
Релоцировались? Теперь вы можете комментировать без верификации аккаунта.