Два лагеря спорят об одном и том же десятилетиями. Одни требуют комментировать каждую строку, другие гордо заявляют "мой код сам себя документирует" и оставляют после себя функцию из четырёхсот строк без единого пояснения. Обе крайности стоят дорого: в первом случае код зарастает комментариями-переводами, во втором знание о правилах живёт только в голове автора и умирает вместе с его отпуском. Стилевой стандарт Python PEP 8 существует с 2001 года и начинается с наблюдения Гвидо ван Россума: код читают гораздо чаще, чем пишут. Из этой строчки вырастает весь разумный подход к документированию: сначала сделать текст программы понятным, потом объяснить то, что в текст не помещается, и закрепить пояснения так, чтобы они не врали. У излишества и у молчания цена разная: первое тонет в шуме, второе в вопросах командного чата. Ниже разбор того, где проходит граница на практике.
Код читают чаще, чем пишут, и следствия для документирования
Число чтений одной строки за её жизнь измеряется десятками: автор перечитывает написанное, ревьюер проверяет, тестировщик разбирает сценарий, новичок изучает устройство, а через год автор возвращается к своему коду уже как чужой человек. Гвидо ван Россум заметил это в самом начале истории Python, и с 2001 года фраза о том, что код читают гораздо чаще, чем пишут, открывает официальный стилевой стандарт языка PEP 8. Гарольд Абельсон и Джеральд Сассман в классическом учебнике о структуре программ сформулировали то же самое жёстче: программы пишутся прежде всего для чтения людьми и лишь во вторую очередь для исполнения машинами. Мартин Фаулер в книге о рефакторинге 1999 года перевёл мысль в вызов: любой дурак напишет код, который поймёт компьютер, хороший программист пишет код, который поймёт человек. Следствие простое. Документирование не украшение после работы, а часть самой работы, и его качество измеряется не количеством комментариев, а скоростью, с которой новый читатель начинает понимать программу.
Экономика здесь безжалостна к обеим крайностям. Основная стоимость программы это не первый релиз, а годы изменений: правки, инциденты, доработки, миграции. Каждый час, потраченный командой на распутывание чужого кода, оплачивается по тарифу инженера, и сам потраченный час не двигает продукт. Новичок в первые месяцы почти только читает, и от качества прочитанного зависит, когда он закоммитит первую полезную правку: через три дня или через три недели. Документирование в широком смысле, имена, докстринги, тесты и пояснения, это ускоритель чтения, оплаченный однажды и работающий годами.
Скрытая статья расходов, вопросы. Каждое "как тут считается комиссия" в командном чате прерывает двоих: спрашивающего и того, кто отвечает по памяти, рискуя забыть деталь. Хорошо описанный код отвечает сам, и тишина в чате становится финансовым показателем.
Самодокументируемый код и его честные пределы
Самодокументируемый код это не лозунг, а набор конкретных приёмов. Имена говорят, что хранится и что происходит: pay_by_card вместо do_stuff, is_pensioner вместо flag1. Короткие функции делают путь чтения плоским, промежуточные переменные заменяют пояснение описательным именем, булевы литералы исчезают в именованных константах. Разница читается мгновенно:
create_order(user, True, False)
create_order(user, with_penalty=True, delayed=False)
Во второй строке вызов понятен без заглядывания в определение. Приёмы работают безотказно, но у них есть честный предел: имя объясняет, что делает код, и никогда не объяснит, почему код обязан делать именно так.
Пример предела. Возрастная скидка:
if user.age >= 65:
user.discount = 10
Читателю ясно каждое слово, но неясно главное: откуда взялись 65 и 10, из закона, из договора или из решения продуктовой встречи трёхлетней давности. Именованные константы уточняют смысл:
PENSION_AGE = 65
PENSION_DISCOUNT_PERCENT = 10
if user.age >= PENSION_AGE:
user.discount = PENSION_DISCOUNT_PERCENT
И всё равно источник правила остаётся за кадром. Самодокументируемость отвечает на вопрос "как", бизнес-правила живут в вопросе "почему", и в этот зазор текст программы не пролезает.
Комментарии объясняют причины, а не пересказывают операции
Комментарий нужен там, где заканчивается текст программы. Позиция зафиксирована давно: комментарий объясняет причину, а не переводит операцию. Стандарт PEP 8 требует, чтобы комментарии были законченными предложениями, и предупреждает прямо: комментарий, противоречащий коду, хуже отсутствия комментария. Плохой и хороший экземпляр различаются наполнением, а не длиной:
total = total + fee # прибавляем комиссию к итогу
total = total + fee # комиссия не входит в цену, пункт 4 договора
Первый пересказывает код и не сообщает ничего, второй несёт знание, которого в коде нет. Устойчивый фильтр из книги о рефакторинге звучит так: захотелось написать комментарий, сначала попробуй отрефакторить код так, чтобы комментарий стал не нужен. Осталось после фильтра, значит, комментарий настоящий: ссылка на пункт требования, предупреждение о неочевидном поведении, заметка о ловушке производительности или объяснение обходного пути сторонней библиотеки.
У полезных пояснений есть узнаваемые типы: ссылка на пункт требования или договора, причина неочевидного технического решения, предупреждение о поведении, которое выглядит ошибкой, но ею не является, пометка о временном обходном пути с номером тикета. Отдельный признак здоровой культуры в том, что команды не боятся удалять комментарии: строка, пересказывающая очевидное, обычно маскирует неудачную структуру, и в литературе о качестве кода её прямо сравнивают с освежителем воздуха. Код починен, пояснение больше не нужно.
Докстринги и стандарты описания публичных интерфейсов
Публичные интерфейсы документируют в специальном формате. Стандарт PEP 257 предписывает структуру: первая строка сжато отвечает на вопрос "что делает", за ней пустая строка, затем подробности, включая ограничения и то, что не вывести из сигнатуры. Докстринг скрипта работает как сообщение о правилах запуска и показывается при неверных аргументах.
def calc_penalty(amount: int, days_late: int) -> int:
"""Считает неустойку за просрочку платежа.
Правило из договора: один процент от суммы за каждый день
просрочки, максимум десять процентов. Округление вниз до копеек.
"""
Такие описания собираются в справочники автоматически: pydoc показывает их в консоли, Sphinx с расширением autodoc собирает сайт документации, rustdoc, javadoc и doxygen делают то же для своих языков. В Go принято начинать пояснение с имени сущности, а среди знаменитых поговорок языка есть строка "ясное лучше хитрого". Контроль покрытия описаниями доверяют линтерам pydocstyle и interrogate: они считают функции без докстрингов и ломают сборку в CI при снижении доли.
Внутрь подробной части кладут то, что нельзя вывести из сигнатуры: единицы измерения, миллисекунды или секунды, копейки или рубли, допустимые диапазоны, исключения и их причины, побочные эффекты. Пользователь интерфейса читает докстринг в редакторе по наведению курсора, и качественная первая строка закрывает большую часть вопросов без открывания исходника. Автосборка заодно дисциплинирует формат: у каждого описания появляются владелец, место и аудитория, справочник на сайте проекта отвечает интегратору, докстринг в редакторе коллеге-разработчику, пример в тестах новому инженеру.
Тесты как исполняемая документация поведения
Тесты документируют поведение надёжнее любого текста, потому что не умеют врать: устаревший пример падает, устаревший комментарий просто продолжает существовать. Читаемые названия превращают набор проверок в спецификацию:
def test_discount_zero_for_adults():
assert discount(30) == 0
def test_discount_ten_percent_for_pensioners():
assert discount(70) == 10
Модуль doctest из стандартной библиотеки Python идёт дальше и делает примеры в докстрингах исполняемыми:
def discount(age: int) -> int:
"""Процент скидки по возрасту покупателя.
>>> discount(70)
10
>>> discount(30)
0
"""
return 10 if age >= 65 else 0
Запуск командой python3 -m doctest file.py проверяет каждый пример, а pytest с ключом --doctest-modules включает их в общий прогон. Примеры перестают быть декорацией: изменение поведения сначала роняет докстринг и лишь потом чужой код. В сложных доменах та же мысль живёт в стиле "дано, когда, тогда": блоки подготовки, действия и проверки читаются как сценарий, и новый инженер изучает требования по тестам быстрее, чем по устаревшему описанию.
Работает и организационная сторона. Один тест проверяет одно поведение, шаги читаются сверху вниз, подготовка вынесена в понятные фикстуры, и файл тестов служит каталогом возможностей модуля. У исполняемых примеров есть и цена: они плохо подходят для проверок с побочными эффектами и внешними ресурсами, поэтому зрелые базы держат равновесие, простые функции получают примеры в докстрингах, сложные сценарии живут в обычных тестах с читаемыми названиями.
Реальная цена устаревших и лживых комментариев
У документации есть главный враг, и это не лень, а время. Код меняется каждую неделю, комментарий меняется, если о нём вспомнили. Строка, обещающая "здесь всегда блокировка", переживает три рефакторинга и продолжает обещать уже несуществующее. Стандарт PEP 8 формулирует жёстко: комментарий, противоречащий коду, хуже отсутствия комментария, а актуальность пояснений обязательна при каждом изменении кода. Цена измеряется часами: программист, поверивший лживой строке, строит на ней гипотезу, и опровергается она только отладчиком. Хуже единичной лжи разъедание доверия: прочитав два обманувших пояснения, инженер перестаёт читать любые, и команда теряет документацию целиком, сохранив её видимость. Отсюда рабочее правило: комментарий правится в том же коммите, что и код, а лживая строка приравнивается к багу.
Устаревание умножается копированием: пояснение переезжает вместе с кодом в три файла и врёт в каждом по-разному. Поэтому зрелые команды относятся к комментариям как к коду: у них есть ревью, стиль и право на удаление. Бесполезную строку вычёркивают без сожаления, ведь стоимость поддержки текста не ниже стоимости поддержки кода, а польза от мёртвой строки отрицательная.
Практический баланс для команды и кодовой базы
Командный баланс умещается в пять строк:
- сначала имена, структура и тесты, комментарии пишутся после того, как код уже стал понятным;
- публичные модули, функции и классы получают докстринг по структуре стандарта, с первой строкой-резюме;
- комментарии объясняют причины, ссылки на требования и ловушки, пересказ операций запрещён;
- примеры в докстрингах исполняются вместе с тестами и обновляются тем же коммитом;
- устаревший комментарий считается дефектом и чинится в том же тикете, что и код.
На ревью баланс проверяется одним вопросом: объясняет ли этот текст то, чего нет в коде. Если да, это документация; если нет, его место в корзине.
Измерить успех документирования можно одним числом: сколько дней проходит от прихода новичка до его первого осмысленного коммита. Команды с дисциплиной описаний укладываются в дни, команды с кодом-загадкой теряют недели и заодно узнают о скрытых правилах продукта из инцидентов.
Разумный итог не в выборе между лагерями, а в разделении труда. Код говорит, как устроена работа; докстринги говорят, что обещает интерфейс; тесты доказывают, что обещания выполняются; комментарии добавляют единственное, что не выразить иначе, причины и происхождение правил. Такой пакет не устаревает незаметно: падает тест или рушится пример, и документация сама требует внимания. Команде это экономит самый дорогой ресурс, часы понимания, а автору даёт тихую страховку: следующий читатель кода через год это он сам, и встреча пройдёт спокойно, если пояснения к тому времени не соврут.