Избавьте себя от головной боли и документируйте соглашения правильно

Избавьте себя от головной боли и документируйте соглашения правильно

17 февраля 2023 г.

Соглашения являются неотъемлемой частью разработки программного обеспечения. Они снижают затраты на разработку и облегчают жизнь разработчикам. Но есть проблема — они часто усложняют дело, потому что не документируются должным образом и не передаются по команде из уст в уста, как старые сказки. При распространении соглашения меняются. Внезапно появляются новые детали, а старые исчезают. В конце концов, у каждого члена команды есть своя картина соглашения в голове, и даже эта картинка иногда тускнеет.

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

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

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

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

Можно придумать множество способов классификации соглашений. Я разделю их по уровню абстракции:

* соглашения на уровне кода; * соглашения на уровне архитектуры; * соглашения на уровне процессов.

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

Соглашения на уровне кода

Цель этих соглашений — сделать код единообразным, всеобъемлющим и удобочитаемым. Вот несколько примеров:

* Мы используем двойные кавычки вместо одинарных. * Мы не вызываем ENV напрямую из кода, кроме как в классе Config, где мы оборачиваем эти вызовы в методы. * Сервисные объекты имеют постфикс Service и один общедоступный метод call.

Эти типы соглашений созданы, чтобы снизить когнитивную нагрузку читателя и помочь ему быстрее привыкнуть к неизвестному коду. Как сказал Мартин, код читается в 10 раз чаще, чем пишется.

Несмотря на ваше мнение о фреймворке Ruby on Rails, в его основе лежит невероятный принцип соглашение важнее конфигурации, который позволяет любому разработчику Rails открыть чужой проект и сразу же довольно хорошо ориентироваться в нем.

Итак, как задокументировать эти соглашения? Линтер инструмент! Если нет подходящего правила линтера, напишите свой линтер. Почти каждый линтер позволяет это сделать: вот пример на языке Go, а вот для Ruby.

Использование линтера для таких соглашений дает вам три преимущества:

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

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

Соглашения на уровне архитектуры

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

* Мы используем Python для написания обычных сервисов и Elixir в высоконагруженных частях системы. * Бэкенд возвращает ошибки в описанном формате. * Каждый сервис должен отправлять метрики в prometheus, на конечной точке /metrics порт для отправки метрик настраивается переменной среды PROMETHEUS_PORT.

Такие соглашения не только снижают когнитивную нагрузку, но и решают еще три проблемы:

  1. Снижение эксплуатационных расходов. Если сервисы запускаются одинаково, с одинаковым форматом логов, публикуют одни и те же метрики, то поддерживать сервис и справляться с инцидентами намного проще.
  2. Снижение затрат на проектирование. Разработчику не нужно каждый раз проектировать архитектуру с нуля — вы подумали заранее, и теперь ему нужно спроектировать только конкретную функцию или сервис, не заботясь о базовых вещах.
  3. Снизить расходы на связь. Если ответ сервера или формат события в Kafka предопределены, разработчикам не нужно каждый раз обсуждать свое взаимодействие, вместо этого они могут просто ссылаться на соглашение.

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

Шаг 1. Опишите

Запись решения по архитектуре (ADR) — это инструмент для документирования таких соглашений. Его прелесть в том, что он фиксирует метаинформацию вместе с соглашением: почему такое соглашение было принято; какие альтернативы обсуждались; когда он последний раз редактировался; соглашение еще в силе?

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

ADR состоит из нескольких основных блоков:

  1. Какую проблему решает соглашение?
  2. Какие варианты решения проблемы рассматривались, и каковы были их плюсы и минусы?
  3. Какой вариант был выбран в итоге?

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

АДР удобнее вести в системе, где можно посмотреть историю изменений и обсуждений. Мой выбор — Github и Notion, каждый со своими плюсами и минусами. Преимущество Github в том, что у него есть встроенный инструмент для просмотра и история версий. Notion может стать хорошим решением благодаря удобству работы с базами данных и тегами. А еще — с этим легко справятся не разработчики.

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

Шаг 2. Автоматизация

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

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

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

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

Соглашения на уровне процессов

В каждой компании существует множество соглашений о процессах, например:

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

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

Идея позаимствована у Виталия Шароватова. Он предложил аналогичный ADR инструмент — Process Decision Record (PDR). Единственное отличие состоит в том, что вместо архитектурных решений он описывает решения о процессах. Кроме того, он предложил указать в каждом PDR «дату переосмысления» — дату, когда вы вернетесь к документу, чтобы убедиться, что он по-прежнему решает ваши проблемы наилучшим образом, через n месяцев после принятия (согласно то же самое можно сделать и с ADR ).

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

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

Итак, каков результат?

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

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

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

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

Каждый новый тип соглашения проходит те же три этапа:

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

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

:::информация Также опубликовано здесь.

:::


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE