Хабрахабр

[Перевод] Самодокументируемый код – это (как правило) чушь

Всем привет!

Нас настолько впечатлила развернувшаяся там дискуссия и 189 комментариев по состоянию на 19. Предваряя сегодняшнюю переводную публикацию, сразу отметим, что этот текст задуман как follow-up недавнему дискуссионному материалу "Прекратите усердствовать с комментариями в коде". 2019, что мы решили дать здесь слово и другому автору с портала Medium (Кристоферу Лейну), который практически по всем принципиальным вопросам полемизирует с тезисами Брайана Норлендера, автора первой статьи. 07. Посмотрим, что будет на Хабре… Отметим, что в оригинале данная статья вышла на месяц позже предыдущей (16 мая и 16 июня), но собрала практически вдвое меньше аплодисментов (706 против 1,5K на момент публикации перевода).

Снимок взят с сайта rawpixels.com от автора Pexels
Я внимательно прочел отличную статью Синди Чеунг о технической документации и о том, почему разработчики должны лучше объяснять собственный код – и должен сказать, что полностью с ней согласен.

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

Мой код самодокументирующийся — Заблуждающийся разраб

В теории код хорошего инженера должен быть настолько ясен и удобочитаем, что ни в какой документации просто не нуждается.

Знаете, это чушь… как правило.

Почему «самодокументирующийся код» — это чушь?

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

Позвольте изложить в деталях. Почему же я считаю, что самодокументирующийся код – это полная ерунда?

Причина 1: В программировании полно всяких приемчиков, которые не самодокументируются

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

Они куда лучше нас разбираются, что с ним делать, и именно для того, чтобы описать им это, у нас есть языки программирования. Но код пишут ДЛЯ машин. С людьми же нужно общаться на более человеческом языке, чтобы человек смог понять, что делает ваш софт.

В коде можно со всеми подробностями прописать, что в нем делается, но можно ли в таком случае называть его «самодокументирующимся»? Между «читаю код и вижу, что в нем происходит» и документацией – очень большая разница. Думаю, каждому понятно, что нельзя.

Я считываю файл, получаю его содержимое, а затем получаю кодировку файла при помощи StreamReader. Рассмотрим следующий простой блоб на C#.

var fileContents = “”;
Encoding fileEncoding; using (var reader = new StreamReader(filePath, Encoding.Default, true))

Тогда… помилуйте, а что делается в этой строке? Если абстрагироваться от возможных неясностей со StreamReader, в остальном этот код достаточно прост, верно?

reader.Peek();

Скажите, где тут самодокументация? Оказывается, считыватель должен совершить это действие, чтобы получить кодировку файла. Но достаточно потратить какие-нибудь 10 секунд, чтобы код стал гораздо понятнее.

reader.Peek(); //Вот так нужно заглянуть в файл, чтобы получить его кодировку.

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

Причина 2: Сложность по сути своей не самодокументируется

Одна задача за другой. Если вам доводилось писать файлы BASH или BAT, то вы знаете, что действия, изложенные в таком файле, выполняются последовательно. Файл напоминает коротенькую историю, которая читается от первой до последней строчки.

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

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

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

Причина 3: Синтаксис языков программирования в принципе не назовешь удобочитаемым

Просто взгляните на эту функцию jquery, вызывающую конечную точку API.

var myURL="https://some.url/path?access_token=my_token"; $.ajax({ url: myURL+"&callback=?", data: "message="+someOtherData, type: 'POST', success: function (resp) { alert(resp); }, error: function(e) { alert('Error: '+e); } });

Уф…

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

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

Для всех остальных язык программирования непонятен.

Что же делать?

Существуют некоторые приемы, пользуясь которыми, вы поможете неспециалистам разобраться в вашем коде.

Этап 1: Попробуйте написать документацию

Кощунственно звучит, верно? Написать документацию?! Ничего смешнее вы не могли придумать!

Но постарайтесь описать в технической документации основные действия, валидацию и обработку ошибок – простым последовательным стилем. Серьезно, никто и не требует от вас написать «Войну и мир».

  • Клиент вызывает конечную точку API /someurl/object/{id}
  • Контроллер API использует {id} (типа int), чтобы найти искомый объект в базе данных.
  • Если объект возвращает null, то контроллер API выдает клиенту HTTP-отклик 404 (файл не найден). API-контроллер логирует это в качестве предупреждения.
  • Если возвращенный объект — NOT null, то контроллер API преобразует этот объект в формат JSON и возвращает его вызывающей стороне с HTTP-откликом 200 (OK).

Если вам ближе боле эгоистичная мотивация, задумайтесь: если к вам то и дело будут обращаться за помощью и объяснениями, то вы сможете просто указать им на документацию, а не растолковывать раз за разом одно и то же. Едва ли это сложно сделать, но, написав такую документацию, вы кому-то облегчите жизнь.

Этап 2: Нарисуйте схемы

Если написать простую документацию для вас все-таки затруднительно, то, как минимум, попробуйте начертить самые необходимые схемы, так как они зачастую служат тем самым «клеем», который помогает человеку со стороны соотнести ваш код с тем, что в нем происходит.
Посмотрите сайт websequencediagrams.com, где в простом текстовом формат можно описывать отличные диаграммы последовательностей – и затем их создавать.

Текст

title Service one to service two
Service two requester -> Service two http client: Get Contract
Service two http client -> Service one REST API: GET /api/contracts/{123}
Service one REST API -> Service one app logic: get Contract with id 123
Service one app logic -> Service one REST API: Contract
Service one REST API -> Service one REST API: Serialise to JSON / XML / etc.
Service one REST API -> Service two http client: Serialised data
Service two http client -> Service two http client : Deserialise to Contract
Service two http client -> Service two requester: Contract

Диаграмма, которая из него получается

Красиво!

Подобные диаграммы и блок-схемы помогут не-программисту разобраться в поведении вашего приложения, и для этого ему нужно будет всего лишь внимательно изучить картинку. Избитая фраза о том, что одна картинка стоит тысячи слов – тем не менее, верна. Коллеги это оценят, а с вашей стороны это будет небольшая инвестиция в общее дело.

Этап 3: Называйте ваши классы и действия на Едином Языке (Ubiquitous Language)

Как известно, Единый Язык – это концепция из DDD (предметно-ориентированного проектирования), где команде и пользователям требуется выработать язык, который описывал бы все классы и их взаимодействия. Такой язык понятен неспециалисту, поэтому клиенты, тестировщики, инструкторы и представители бизнеса смогут на нем прочитать и понять, что именно делает наша программа и каким образом решает проблемы пользователя в данной предметной области.

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

/// <summary>
/// Клиент сам отвечает за собственный вход в систему/выход из нее, а также за извлечение информации из своего профиля и управление ею /// settings
/// </summary>
public interface ICustomer
{ Task<AuthenticationResult> Login(string username, EncryptedString password); Task Logout(); Task<CustomerProfileInformation> GetMyProfile(); Task SaveMyProfile(CustomerProfileInformation); Task<CustomerSettings> GetMySettings(); Task SaveMySettings(CustomerSettings);

Хотя, это просто фрагмент кода, над ним простым и общепонятным языком написано, что здесь происходит.

Этап 4: Просто напишите комментарии

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

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

Надеюсь, эти советы будут вам полезны

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть