Skip to main content

Возвращение к источнику

  • Эта публикация - перевод статьи. Ее автор - Julian Squires. Оригинал доступен по ссылке ниже:

Если система должна служить творческому духу, она должна быть полностью понятна одному человеку. - Дэн Ингаллс

Я видел Эллен Ульман, рассказывающую о своей новой книге, и тема превратилась в обвинение Y2K - систем, от которых люди никогда не ожидали работоспособности в течение многих десятилетий, систем, которые больше никто не понимает.

Когда ядерная установка в Питерборо обратилась к ретро-компьютерным энтузиастам1, которые искали знающих ассемблер PDP-11, я подумал о серии Foundation (предупреждение: возможны спойлеры). Идея, которая была наиболее впечатляющей для меня в этих книгах: в конечном итоге общества, которые стали комфортно работать с передовыми технологиями, могут потерять знания о том, как эта технология работала (ядерная атмосфера 50-х годов). 2 Я встречаю людей, игнорирующих важность системного программирования (к сожалению, больше в Интернете, чем IRL), и это заставляет меня задаться вопросом: стараемся ли мы в этом направлении.

Ульман говорил о «возвращении к источнику» - извлечении утраченных знаний из кода, чьих авторов больше нет. Для этого не могло быть более благоприятного времени, поскольку я только что обсуждал достоинства (и подводные камни) чтения источника с моими коллегами-рекурсорами.

Я искренне полагаю, что код - источник правды в вычислительной технике (и под я также имею в виду машинный код, который также стоит прочитать, но успех в Compiler Explorer Matt Godbolt говорит мне, что я не одинок в своем мнении). Поэтому я пишу эту статью, чтобы уведомить вас прочитать код, написанный кем-то, кого вы не знаете, сегодня, чтобы сохранить будущее.

Зачем читать? Мастерство

Джон Бентли открывает свой первый программный перл о грамотном программировании следующим текстом:

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

(Мне нравится задавать этот вопрос в интервью, по обеим сторонам стола, не быть снобом, а открывать дискуссию о чтении кода.)

Я всегда вспоминаю это лучше через то, как Стив Макконнелл перефразирует Джона Бентли в Code Complete:

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

Цель ясна: вы можете развиться как ремесленник, читая шедевры программного обеспечения, так же, как писатели должны читать другие произведения 3 , а музыкантам нужно слушать другие выступления. Эмпирически проверять, правда ли это, к сожалению, вне моих возможностей, но я считаю, что я очень сильно выиграл от «чтения великих». 4

Одна вещь, чтобы уточнить из этих цитат, однако: они всегда делали мне картину, читая источник сверху донизу, и оказывается, что это не особенно эффективно.

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

Там есть продолжение: я думаю, что Пьер Байард «Как говорить о книгах, которые вы не читали», выражает это намного лучше, чем я могу, но я считаю, что самонадеянно полагать, что «прочитав код» является двоичным состоянием: либо вы читаете (и понимаете) все, или вы не «читаете». Погружение в кодовую базу - это только начало длительных отношений с этим кодом; вы можете продолжать возвращаться, к знакомым преследователям и неоткрытым территориям каждый раз.

Зачем читать? Личное мастерство

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

Как выглядит система, которая длится 10000 лет? Я не думаю, что это будет тот, который никто не может понять. Можно ли построить полные системы, которые могут быть поняты человеком? Кажется, что работа Исследовательского института точек зрения предполагает, что это возможно. До того дня, когда у всех нас будут свои персональные операционные системы 10kLOC 5, предназначенные для хранения памяти, модели Fahrenheit 451, системы чтения большие и малые, помогают справиться с характером сложности и найти с ним личные отношения.

И, прагматично, чтение ваших зависимостей помогает вам ответить на вопрос: сможет ли кто-нибудь понять это, когда он сломается? (И он сломается: из-за битрота, потому что предположения изменились.)

Зачем читать? Процедурная риторика

Эллен Ульман также говорила о том, как алгоритмы имеют предубеждения; программное обеспечение не является нейтральным 6 . Это напомнило мне концепцию процедурной риторики Яна Богоста, где взаимодействие с системами может быть убедительным, и может передавать идеи и мнения таким тонким образом.

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

Что стоит читать?

Вы могли бы задаться вопросом: «Где я даже начинаю?». Я думаю, что есть два класса кода, особенно заслуживающих внимания: код, который вы используете, и код, который замечательный. Последнее невероятно субъективно; Я составляю список того, что, на мой взгляд, является «шедеврами программного обеспечения», и опубликую его в какой-то момент, к большой критике, я уверен. 8

Тем не менее, первое прямо для всех: прочитайте свои зависимости. Теперь, когда мы живем в утопии бесплатного программного обеспечения (хаха) 9, вы, вероятно, имеете доступ к источнику подавляющего большинства библиотек, серверов, инструментов и систем, которые вы используете и зависите. Это богатство, которое часто растрачивается.

Грамотное программирование

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

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

Чтение о чтении

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

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

Эффективная работа Майкла Перса с устаревшим кодом - поистине замечательная книга, но я не помню, чтобы она имела много конкретных советов о фактическом чтении устаревшего кода. (Разумеется, я мог бы ошибаться.) Тем не менее, речь идет о тестировании, и один из замечательных способов прочитать кодовую базу - попытаться написать тесты для нее.

Бонус: напряжение комментариев

Я упомянул, что я считаю, что код является единственной истиной в системе. (Это ужасное упрощение, так как почти все системы также в некоторой степени управляются данными.) Поэтому неудивительно, что я согласен с советами Кернигана и Пайка о комментировании в «Практике программирования», которая часто неверно интерпретируется как «не пишите комментарии».

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

Однако у меня есть вопиющий пример Дарвина (macOS) osfmk/kern/thread_call.c:

if  ( cancel_all ) 
        result = _remove_from_pending_queue ( func, param, cancel_all ) |
                _remove_from_delayed_queue ( func, param, cancel_all ) ;
else 
        result = _remove_from_pending_queue ( func, param, cancel_all ) ||
                _remove_from_delayed_queue ( func, param, cancel_all ) ;

Я часто рыщу этот фрагмент, когда спрашиваю людей, где их порог для «слишком умного» кода. Для меня первая реакция на это: «Это опечатка», и только после того, как я снова посмотрел на нее, я понял, что она пыталась сделать, а затем еще долго думала о том, правильно ли она это сделала.

Но в последний раз, когда я пошел показать кому-то этот фрагмент, оказалось, что он был обновлен, включая добавление некоторых важных комментариев!

if  ( cancel_all )  { 
        / * исчерпывающе искать каждую очередь и возвращать true, если какой-либо поиск нашел что-то * / 
        result = _cancel_func_from_queue ( func, param, group, cancel_all, & group-> pending_queue ) |
                 _cancel_func_from_queue ( func, param, group, cancel_all, & group-> delayed_queues [ TCF_ABSOLUTE ] )   |
                 _cancel_func_from_queue ( func, param, group, cancel_all, & group-> delayed_queues [ TCF_CONTINUOUS ] ) ;
}  else  { 
        / * early-exit, как только мы что-то найдем, не ищите другие очереди * / 
        result = _cancel_func_from_queue ( func, param, group, cancel_all, & group-> pending_queue ) ||
                 _cancel_func_from_queue ( func, param, group, cancel_all, & group-> delayed_queues [ TCF_ABSOLUTE ] ) ||
                 _cancel_func_from_queue ( func, param, group, cancel_all, & group-> delayed_queues [ TCF_CONTINUOUS ] ) ;
}

Чтение этого кода дало мне признательность за какой-то комментарий, который в противном случае я бы уклонил.

Бонус: как читать программу на C

Я бы отказался не кончать это конкретными советами. Советы по чтению зависят от языка, но много кода, который я читаю, написано на C; как я подхожу к чтению программы на С?

Когда вы сомневаетесь, начинайте снизу. Иногда кто-то пытается бороться с естественным С-порядком определений путем форвардного объявления статических функций; это неестественно, и большинство кода написано не так. Вместо этого вы, как правило, увидите, что если вы хотите увидеть «сверху вниз», вы должны пойти в конец и работать в обратном направлении. (Кстати, это даже более верно для OCaml / Standard ML программ, где порядок декларации очень строгий.)

Используйте unifdef, чтобы избавиться от максимально возможного для вас, по крайней мере, для начального чтения. Избавься от тех путей, которые берутся только за Желуди и Атари.

Используйте ctagscscopeGNU global и любую другую поддержку, которую вы можете найти, чтобы быстро перейти к определениям идентификаторов и из них, в идеале также увидеть все места, которые относятся к этим идентификаторам. Для этого иногда подходят инструменты перекрестной ссылки, такие как LXR ( на ядре Linuxна MRI), хотя я часто нахожу их более громоздкими, чем использование моего редактора на локальной машине.

Посмотрите на заголовочные файлы, включенные; каковы структуры данных, которые используются все время? Иногда есть макросы с макросами, такие как макросы queue.h для интрузивных структур данных; он может помочь запустить препроцессор над файлом ( cc -E) или написать структуру вручную на бумаге и аннотировать ее.

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

Если вы читаете библиотеку, подумайте о том, чтобы начать с примера программы, проследив через вызовы API, в кишки библиотеки.

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

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

В конце концов, чтение кода не только хорошо для вас; это весело.

Примечания

  1. Вероятно, я должен дождаться, пока я прочитаю ее новую книгу, чтобы написать это, так как я уверен, что у нее есть отличная информация об этом, но я не могу дождаться.
  2. Тангенс: возможно, этого никогда не случится в программном обеспечении, потому что ничего не работает достаточно долго, чтобы кто-нибудь мог подумать, что мы можем избавиться от программистов.
  3. «Если у вас нет времени на чтение, у вас нет времени (или инструментов) для написания. Просто так». - Стивен Кинг.
  4. Я чувствую, что это совет, который обычно дается молодым математикам, но на данный момент я не могу найти источник для этого. Я думаю, что это должно произойти из этой цитаты Нильса Абеля.
  5. Чак Мур опережает игру на этом.
  6. Я считаю, что это присуще, потому что программное обеспечение составлено из решений.
  7. «Будущие мастера технологии должны быть беззаботными и умными. Машина легко овладевает мрачными и тупыми». - Маршалл Маклюэн
  8. Хорошо, друг убедил меня включить несколько мест, чтобы начать, если вы действительно в недоумении; так как я рассказываю о C в конце, как насчет некоторого кода C, который мне нравилось читать недавно: postgresчто-то cpercivaIllumossqlite. Некоторые из них довольно сложны, но обычно стилистически хороши и необычайно хорошо комментируются.
  9. Отчаянно отсутствует в этой статье, это признание того, насколько свободное программное обеспечение с открытым исходным кодом изменило мир, но я не знаю, как писать об этом. Тем не менее, начало программиста Дэвида Макивера в целом.