Почему я снова комментирую код приложений на Ruby/Rails

в 7:41, , рубрики: ruby, ruby on rails, комментирование, Программирование, метки: , ,

Здравствуйте, я — разработчик программного обеспечения на Ruby / Rails и я комментирую свой (а с недавних пор ещё и чужой) код. Голос из зала, вероятно, крикнул бы «Привет, разработчик!»

Много лет назад мне казалось очевидным устоявшееся мнение профессионалов и гуру разработки, которое обычно выражается примерно так: «Если код требует комментария — это плохой код, его нужно переписать/отрефакторить/упростить/уменьшить». Т.е. привести его к виду, комментариев и пояснений не требующему. В целом, этот подход достаточно универсален и работает во многих случаях. Многие мои знакомые веб-разработчики никогда не комментируют свой код и считают это вполне нормальным явлением, даже если работают в команде. Вероятно, сказывается миф о простоте Ruby, такой простоте, которая делает код понятным даже постороннему. Однако, мой личный опыт и некоторые эпизоды командной разработки веб-приложений убедили меня в том, что существуют ситуации и причины уделять комментариям и документированию кода больше внимания и времени, чем обычно уделяет разработчик.

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

Основным тезисом моего краткого рассказа будет: «О сложности кода может судить только его автор».

Итак, прежде всего нужно уточнить, когда же именно работает правило «Вместо комментирования измени код так, чтобы комментирование стало излишним». Оно работает всего лишь в нескольких случаях:

  • Когда код написан неквалифицированно: слишком длинно (возможно, разработчик плохо знает стандартную библиотеку и писал много лишнего кода сам) или слишком сложно (perl-style, однострочные цепочки функций длиной более 5-ти функций подряд)
  • Когда код включает в себя редкоиспользуемые или нехарактерные для данного ЯП методы и приёмы

И всё! В этих случаях, действительно, лучше такой код переделать. Переделать, убедится, что код стал короче, яснее, понятнее для коллег и… наконец-то написать комментарии! И вот я уже добрался до того места, где и буду пояснять свои идеи.

Пояснение для Идеи № 1: «О сложности кода адекватно может судить только его автор».

Представим себе команду программистов, состоящую, например, из 5-ти человек. С ними работает менеджер и пара дизайнеров. Команда программистов состоит из одного профессионала и 4-х программистов обычного уровня. Никто не комментирует код. Возможно, есть написанная кем-то краткая инструкция по развёртыванию проекта. Документации команда не ведёт, т.к. заказчик меняет решения и приоритеты и не очень хочет оплачивать время, затрачиваемое на составление документации в процессе разработки. Примерно таким образом работает множество среднего уровня студий веб-разработки.

Что же будет, если один или двое программистов уйдут из команды, в другой проект, в другую студию или просто в отпуск? Вероятно, на их место будут взяты один и два других разработчика, которым дадут код, дадут задачи и… и всё. Предварительно, HR-менеджер спросит у них, умеют ли они «разбираться в чужом коде» и «работать в команде», а они, конечно же, ответят, что умеют. И вновь прибывшие окажутся один на один с кодом и коллегами, которые быть может и рады отвечать на вопросы «а почему здесь так...» или «а зачем там это...», но это отвлекает от работы. Поэтому разработчик вынужден «разбиться с проектом». Количество рабочего времени, потраченного на «выполнение» своим мозгом чужого кода с целью пройти по нему и понять, что он делает — ужасает. Поясню на примере.

Представим себе функцию, вроде такой:

def update
   list = current_user.lists.update(params[:id], params[:list])
end

С точки зрения правила о простоте кода, здесь просто рай. Комментировать тут нечего, одна строка, совершенно никаких сложностей. Однако, представим себе, что params формируется не простой формой на странице, а с помощью кода на Javascript в Backbone.js, что lists — это на самом не lists, а оставшееся от прошлой команды название и модель эта теперь везде в тестах называется Things, что на before_save этой модели навешена функция, которая берёт некие поля и создаёт отложенное задание, которое парсит, согласно данным этих полей некие URL'ы (возможно, без контроля ошибок HTTP-протокола), чтобы потом сохранить полученные ответы в другой таблице. А иногда вызывает exception'ы и шлёт сообщения о них… куда-то… на сайт сбора ошибок, куда программисту дадут доступ, как только он сам напомнит. А совсем иной контроллер (API, например) отдаст значения этих полей ajax'ом в Backbone'овскую View. Кстати, можно ещё уточнить, что данная функция должна рендерить шаблон, сначала пропуская его через парсер RABL, формируя там JSON, совершенно непохожий на изначальное содержимое list, который Things. Ну и для полного комплекта уточним, что работать это должно на хостинге с какими-нибудь ограничениями, к примеру, без доступа к cron'у. И с качестве СУБД используется NoSQL.

Приведённый пример — это не выдумка, не специальное усложнение. В реальных проектах бывает и больше шагов в выполнении какой-то функции приложения. Но всегда только сам автор кода может знать, сложен его код или нет. Проблема в том, что человек, которому нужно реализовать в этом приложении новую функциональность неизбежно должен будет своим мозгом вместо интерпретатора «выполнить» почти всю имеющуюся базу кода. Либо он будет это сделать ДО начала написания кода, на что потратит время, которое менеджеру придётся как-то обосновать в отчётах, либо он будет делать это в процессе написания кода, что есть самый плохой вариант. Почему? А потому что результаты такой работы будут крайне низкокачественными и вернувшийся из отпуска автор всё равно всё переделает. А вы заплатите новичку за то, что он разбирался с проектом, а в итоге всё равно пользы не принёс.

Есть и другая часто встречающаяся проблема.

В проекте N функциональность M обычно реализуется с помощью XYZ. Не зная кода полностью или не прочитав документации к проекту, описывающей структуру и используемые XZY, разработчик не может знать, X, Y или Z используется ли уже или нет. И если нет — почему не используется. Не существует программиста, который может сразу же начать работать и создавать новое в незнакомом ему проекте, это миф о «крутости разработчика». Лучшее, к чему может привести подобная ситуация — разработчик сделает свою задачу так, как умеет, отдаст на code review и получит код обратно с комментарием «Зачем сделал так, ведь у нас для этого принято использовать [список каких-то технологий]» или «Зачем сделал так, ведь можно было так: [описание сущностей, выяснить существование которых самостоятельно невозможно (например, наличие триггеров или функций в БД на production-сервере]»

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

  • Описывайте то, как работает этот код. Обязательно, хоть и кратко, в начале каждого файла, содержащего класс, описывайте, что он реализует. Перед методами класса кратко описывайте, что метод получает и что должен создать в конце своей работы, коротко описывайте цепочку, по которой пройдут данные. Так же в файлах-модулях. Комментируйте вычисляемые автоматически значения и назначения создаваемых миграциями полей. В случае длинной цепочки вызовов функций (длиннее трёх) — описывайте цепочку, что вызывает что, хотя бы просто последовательность.
  • Ведите в каждом файле блок TODO, в одном и том же месте, хоть сразу после объявления класса или модуля.
  • Ведите в каждом файле блок IN_WORK (назовите как угодно Вам), в котором пишите о том, какие места в данный момент подвергаются переделке/рефакторингу/устарели и вместо них нужно использовать BLABLA из класса XYZ.
  • Обязательно описывайте все факты, наличие которых нельзя вывести из имеющейся документации!

Для последнего пункта приведу пример: если ваш проект несовместим, например, с MySQL, а разработчик потратил полдня, пытаясь развернуть проект именно на этой СУБД, не вздумайте сказать ему «Мы же не поддерживаем MySQL!». В ответ вы услышите в лучшем случае «А почему я об этом не знал?». И если вы скажете этому парню фразу «А почему ты не спросил?» — можете быть уверены. что в вашем проекте уже существуют большие проблемы с документированием и это уже наносит вам ущерб. Ведь никто из нас не знает точного списка всего, что он не знает!

Спасибо за внимание и пусть ваш код будет всегда ясен, прост и задокументирован.

Автор: Nimrodel

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js