Хабрахабр

[Перевод] Низкая связанность, архитектура и организация команд

Перевод статьи подготовлен специально для студентов курса «DevOps практики и инструменты».

В этой статье обсуждается взаимосвязь между структурой кода и структурой организации при разработке программного обеспечения. Я рассуждаю над тем, почему программное обеспечение и команды не могут легко масштабироваться, какие уроки мы можем подсмотреть в природе и Интернете, и показываю как мы можем уменьшить связанность программного обеспечения и команд для преодоления проблем масштабирования.
Статья основана на моем 20-летнем опыте создания больших программных систем и на впечатлении от книги “Accelerate: The Science of Lean Software and DevOps: Building and Scaling High Performing Technology Organizations” (Nicole Forsgren, Jez Humble and Gene Kim), в которой приводятся данные исследований для подкрепления большинства моих утверждений, приведенных здесь. Эта книга настоятельно рекомендуется к прочтению.

Программное обеспечение и команды не масштабируются

Часто первый релиз, возможно, написанный одним или двумя людьми, происходит удивительно просто. В нем может быть ограниченная функциональность, но он написан быстро и соответствует требованиям заказчика. Взаимодействие с заказчиком на этом этапе великолепное, потому что заказчик обычно находится в непосредственном контакте с разработчиками. Любые баги устраняются быстро, а новые фичи могут быть добавлены достаточно безболезненно. Через некоторое время темп замедляется. Версия 2.0 занимает немного больше времени, чем ожидалось. Исправлять баги сложнее, а новые фичи даются, уже не так-то просто. Естественным ответом на это является добавление в команду новых разработчиков. Хотя, кажется, что каждый дополнительный сотрудник, добавленный в команду, снижает производительность. Возникает ощущение, что по мере того, как растет сложность программного обеспечения, оно атрофируется. В крайних случаях организации могут столкнуться с тем, что используются программы с очень дорогой поддержкой, в которые практически невозможно внести изменения. Проблема в том, что вам не нужно делать какие-то “ошибки”, чтобы это произошло. Это настолько распространено, что можно сказать, что это «естественное» свойство программного обеспечения.

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

Существуют фиксированные когнитивные границы человека. По мере роста кодовой базы одному человеку становится все труднее ее понять. Как только команда вырастает до пяти или более человек, то для одного человека становится практически невозможно быть в курсе того, как работают все части системы. И, хотя, один человек может держать в уме детали небольшой системы, но только до тех пор, пока она не станет больше, чем его когнитивный диапазон. В большой сильносвязанной системе очень трудно понять влияние любых существенных изменений, поскольку результат не локализован. А когда никто не понимает всей системы, то появляется страх. Это еще больше усложняет систему, усиливая эти негативные тенденции. Для минимизации влияния изменений разработчики начинают использовать обходные пути и дублирование кода вместо выявления общих черт, создания абстракций и обобщений. Технический долг растет. Разработчики перестают чувствовать ответственность за непонятный им код и неохотно делают рефакторинг. Это также делает работу неприятной и неудовлетворительной и стимулирует «отток талантов», когда уходят лучшие разработчики, которые легко найдут работу в другом месте.

По мере роста команды коммуникации становятся все сложнее. Команды также не масштабируются. В игру вступает простая формула:

c = n(n-1)/2

(где n — количество людей, а c — количество возможных связей между участниками команды)

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

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

Но это несправедливо. Обычно в этих патологиях масштабирования винят неопытных разработчиков и плохое управление. Это то, что происходит всегда, если вы не обнаружите проблему на раннем этапе, не поймете точку отклонения и не приложите усилия для решения проблемы. Проблемы масштабирования — это “естественное” свойство растущего и развивающегося программного обеспечения. Поэтому, довольно часто, успешный и развивающийся продукт создается командой, не имеющей опыта крупномасштабных разработок. Команды разработчиков программного обеспечения создаются постоянно, количество программного обеспечения в мире постоянно растет, и большая часть программного обеспечения относительно небольшого размера. И нереально ожидать, что разработчики распознают точку перегиба и поймут, что делать, когда начнут проявляться проблемы масштаба.

Уроки масштабирования природы

Недавно я прочитал превосходную книгу Geoffrey West “Scale”. В ней говорится о математике масштаба в биологических и социально-экономических системах. Его тезис заключается в том, что все большие сложные системы подчиняются фундаментальным законам масштаба. Это увлекательное чтение и я его очень рекомендую. В рамках этой статьи я хочу сосредоточиться на его точке зрения, что многие биологические и социальные системы удивительно хорошо масштабируются. Посмотрите на тело млекопитающего. У всех млекопитающих одинаковые типы клеток, структура костей, нервная и кровеносная система. Однако разница в размерах мыши и синего кита составляет около 10^7. Как природа использует для организмов столь разных размеров одинаковые материалы и строение? Похоже, ответ заключается в том, что эволюция открыла фрактальные разветвленные структуры. Посмотрите на дерево. Каждая его часть выглядит как маленькое дерево. То же самое справедливо для кровеносной и нервной систем млекопитающих, они представляют собой разветвленные фрактальные сети, где небольшая часть ваших легких или кровеносных сосудов выглядит как уменьшенная версия целого.

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

Ответ очевиден — Интернет, глобальная программная система, насчитывающая миллионы узлов. Существуют ли программные системы, которые успешно масштабируются на несколько порядков? Подсети действительно выглядят и работают как уменьшенные версии всего Интернета.

Признаки слабосвязанного программного обеспечения

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

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

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

Признаки слабосвязанной организации

Мы можем масштабировать команды, следуя тем же принципам:

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

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

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

Команды сильно связаны, потому что для совместной работы им нужно делиться важными внутренними деталями. Коммуникационные барьеры между этими функциональными командами становятся основным препятствием для эффективной и своевременной поставки. Эти различные интересы могут привести к конфликту и плохому результату. Кроме того, интересы разных команд не совпадают: разработчики обычно получают награду за новые фичи, тестировщики за качество, поддержка за стабильность. Зачем тестировщикам заботиться о поставке, если они отвечают за качество? Зачем разработчикам беспокоиться о логах, если они их никогда не читают?

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

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

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

Перевернутый закон Конвея: структура организации должна моделировать целевую архитектуру

Как согласуются между собой слабая связанность программного обеспечения и слабая связанность команд? Закон Конвея гласит:

«Организации, проектирующие системы, ограничены дизайном, который копирует структуру коммуникации в этой организации».

Это основано на наблюдении, что архитектура программной системы будет отражать структуру организации, которая ее создает. Мы можем «хакнуть» закон Конвея, перевернув его. Организовать наши команды так, чтобы они отражали нашу желаемую архитектуру. Помня об этом, мы должны согласовать слабосвязанные команды со слабосвязанными программными компонентами. Но должны ли это быть отношения один-к-одному? Я думаю, что в идеале, да. Хотя, кажется, что хорошо, если небольшая команда работает над несколькими слабосвязанными сервисами. Я бы сказал, что точка перегиба масштабирования для команд больше, чем для программного обеспечения, поэтому такой стиль организации кажется допустимым. Важно, чтобы компоненты программного обеспечения оставались разделенными, с собственным версионированием и развертыванием, даже если некоторые из них разрабатываются одной командой. Мы хотели бы иметь возможность разделить команду, если она станет слишком большой, с передачей разрабатываемых сервисов разным командам. Но мы не сможем этого сделать, если сервисы сильно связаны или используют совместно процесс, версионирование или развертывание.

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

Возьмем снова пример с Интернетом. Взаимодействие между слабосвязанными командами, создающими слабосвязанное программное обеспечение, сведено к минимуму. При взаимодействии команд не должны обсуждаться внутрикомандные процессы разработки и реализации. Часто можно использовать API, предоставленное другой компанией, без какого-либо прямого общения с ней (если процесс прост и есть документация). Вместо этого должна обсуждаться функциональность, уровни обслуживания и ресурсы.

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

Слабосвязанные команды разрабатывают слабосвязанное ПО

Слабая связанность в программном обеспечении и между командами является ключом к построению высокоэффективной организации. И мой опыт подтверждает эту точку зрения. Я работал в организациях, где команды были разделены по функциям, по уровням ПО или, даже там, где было разделение по клиентам. Также я работал и в больших хаотичных командах на единой кодовой базе. Но во всех этих случаях были проблемы с масштабированием, о которых говорилось выше. Самым приятным опытом всегда было, когда моя команда была полноценным подразделением, самостоятельно занимающимся созданием, тестированием и развертыванием независимых сервисов. Но вам не нужно полагаться на мои истории из жизни. В книге Accelerate (описанной выше) есть данные исследований, подтверждающих эту точку зрения.

Если Вы дочитали этот материал до конца, советуем к просмотру запись открытого вебинара по теме «Один день из жизни DevOps».

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

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

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

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

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