Недавно в интернете наткнулся на мнение о том, что самодокументированного кода
не существует. И стало мне так обидно, что в интернете кто-то не прав, что я
решил написать статью на тему того, что такое самодокументированный код,
как его писать и зачем он нужен.
Для начала договоримся об определениях
Самодокументированный код
Это програмный код, при переводе которого на русский язык получается
хорошая техническая документация
Хорошая техническая документация
Техническая документация, достаточная для понимания кода
Сепульки
Сепульки — важный элемент цивилизации ардритов с планеты Энтеропия. См. Сепулькарии.
Операционная семантика
Понимание программы как последовательного набора инструкций. Иными
словами, код `a = b + c` имеет операционную семантику "теперь a это сумма b и c"
Давайте посмотрим на отделенный от документации код
Вроде бы все понятно
не смотря на обилие документации код
все равно не очень хорошо поддается анализу. Я не стал намеренно завышать
ABC-сложность, так как полезность метрик очевидна безотносительно подхода
к документации, поэтому разобраться в нем даже без документации
вполне доступно каждому. Отсюда, кстати, следствие: отстутствие технической
документации для простого кода — хорошая техническая документация. В то же
время иметь хорошую документацию для публичного API все равно не лишне,
поскольку в данном случае речь уже идет о контексте другого модуля.
Отсюда кстати очевидно следует, что самодокументируемость публичного API модуля
это хорошо, так как документация на API лежит вне контекста и ее надо отдельно
искать.
Посмотрим, как можно увеличить количество документации,
чтобы код стал абсолютно понятен
Мы, разумеется, не будем документировать каждую строку на тему того что там
происходит. Назовем это выраженной операционно документацией. Разумеется,
такая документация вряд ли является хорошей и в общем то непонятно является ли
документацией, однако для простых паттернов она вполне подходит.
Сформулируем это как Простой и короткий участок кода, соответствующий привычному паттерну, вполне самодокументирован
Мы уже умеем писать самодокументированный код
Разбиение кода на простые и короткие участки известно как процедурное
програмирование
мы избавились от определенного количества комментариев, но взамен получили
возрастание сложности, связанное с тем что наши процедуры требуют каких то
непонятных параметров, а типы данных недостаточно подробно обхясняют что в них
находится.
Добро пожаловать в структурное программирование!
Заметим, что код растет и становится менее эффективным. Это цена,
которую мы платим за само-документированность. Можно заметить, что мы идем
по пути эволюции паттернов программирования и это не случайно.
Потребность к само-документиации стимулирует нас использовать модульный подход.
Если посмотреть на итоговый алгоритм, то он стал гораздо проще для понимания,
ведь с одной стороны мы имеем классическую реализацию решета эратосфена
(с поправкой на ветер конечно же), доказательство корректности которой легко
выводится непосредственно из нашего кода: она умеет удалять простые числа
и в общем то все. На случай проблем, например, со строгостью неравенств всегда
можно написать простой тест
Второй модуль более сложный в плане доказательста корректности
(у нас там ТЕОРЕМА в комментариях), но сам по себе содержит очень мало кода
и при условии корректности работы модуля решета его корректность не сложно
вывести.
На этом в общем то в плане руби у нас все.
Является ли этот код само-документированным?
В моем понимании вполне. Доказательства теорем это еще не документация.
Остались пояснения назначения переменных и классов, но это связанно в
основном с разуменым ограничением на длину имени метода / класса.
Единственное что не удалось уложить туда это апроксимацию сложности алгоритма
Давайте называть само-документированный с таким допущениями код вполне самодокументированным. Отсюда
Вывод
Самодокументированный код все еще нуждается в небольшом количестве
документации. Это связано в первую очередь с ограничением выразительности
языка руби (фактически у нас есть только операционная семантика и
нету развитой системы типов). Используя, скажем, денотационную семантику
в языке с зависимыми типами, мы могли бы доказывать теоремы
за счет еще большего количества строк кода. Используя функциональную
парадигму мы бы избавились от избыточного количества переменных, которые надо
еще и документировать а код получил бы выраженную денотационно документацию
Напоследок,
проверим идею о том что функциональная парадигма нам поможет
Кстати, весьма лаконично, но сложно для понимания без знания паттернов.
Я сильно сомневаюсь что документация тут поможет улучшить понимание.
Кстати, было бы прикольно посмотреть доказательство корректности на зависимых
типах, то есть подобный код, который возвращает какой-нибудь PrimeInteger
вместо Integer. Мы ведь уже дошли до этой стадии развития языков?