Одной команде проще обсуждать предложения по внесению изменений и перестроению программного кода, и, как правило, у нее имеется высокоразвитое чувство собственности.
Теперь представим себе другой сценарий. Предположим, что вместо одной находящейся в одном месте команды, владеющей нашим сервисом каталогов, есть две команды в Великобритании и Индии. Обе они принимают активное участие во внесении изменений в сервис и при этом фактически коллективно владеют этим сервисом. Географическая разобщенность и разные часовые пояса затрудняют оперативное общение между этими командами. Они полагаются на контакты более общего плана через видеоконференции и электронную почту. Просто ли будет сотруднику команды из Великобритании уверенно выполнить небольшое перестроение кода? Издержки от общения географически удаленных друг от друга команд весьма велики, и поэтому высока и стоимость координации усилий при внесении изменений.
При увеличении стоимости координации внесения изменений случается одно из двух. Либо люди находят способы для сокращения стоимости координации и общения, либо прекращают вносить изменения. Именно последний вариант ожидает нас в случае использования объемных, трудоемких в обслуживании баз исходного кода.
Мне вспоминается один клиентский проект, над которым я работал, когда одним сервисом совместно владели две географически разделенные команды. Со временем каждая из сторон начала уточнять, какой работой она будет заниматься. Это позволило каждой из них завладеть той частью базы исходного кода, внутри которой предполагаются наименьшие расходы на внесение изменений. Затем команды вели дискуссии более общего плана о взаимосвязанности этих двух частей; фактически направление общения, ставшее возможным внутри организационной структуры, соответствовало API-интерфейсу, имеющему более общий характер, который сформировал границы между двумя половинами базы исходного кода.
Какое это имеет к нам отношение при рассмотрении того, как развивается конструкция нашего собственного сервиса? Я бы предположил, что географические границы между людьми, участвующими в разработке системы, могут стать отличным стимулом для разбиения сервиса на части и что в общем вы должны продумать возможность назначения собственником сервиса одной находящейся в одном месте команды, которая сможет поддерживать стоимость внесения изменений на низком уровне.
Возможно, в вашей организации решат, что требуется увеличить штат сотрудников, работающих над вашим проектом, открыв офис в другой стране. Тогда вам придется хорошенько подумать о том, разработку какой части вашей системы можно будет туда переместить. Возможно, это подстегнет вас к принятию решения о том, по каким стыкам выполнять следующие разбиения.
В связи с этим стоит также заметить, что, основываясь как минимум на наблюдении авторов ранее упомянутого отчета Exploring the Duality Between Product and Organizational Architectures, можно сказать: если организация, создающая систему, имеет менее крепкие связи (к примеру, она состоит из географически разобщенных команд), то создаваемые этой организацией системы будут, как правило, иметь более модульную структуру и поэтому, будем надеяться, обладать меньшей связанностью. Поддерживать в географически разбросанной организации тенденцию получения более тесной интеграции за счет того, что одна команда владеет сразу несколькими сервисами, очень трудно.
Что я подразумеваю под владением сервисом? В общем смысле это означает, что команда, владеющая сервисом, несет ответственность за внесение изменений в этот сервис. Команда должна иметь возможность свободно проводить реструктуризацию кода по собственному усмотрению, если только эти изменения не нарушат условий использования сервисов. Для многих команд права владения распространяются на все аспекты сервиса, от исходных требований до создания, развертывания и сопровождения приложения. Эта модель особенно широко распространена при работе с микросервисами: небольшой команде намного легче владеть небольшим сервисом. Возросший уровень владения приводит к росту автономности и скорости поставки. Когда одна команда отвечает за развертывание и сопровождение, это означает, что у нее есть стимул создавать сервисы, которые потом можно будет легко развернуть, то есть опасения насчет «перебрасывания чего-нибудь через забор» развеиваются, когда это что-то просто некому перебрасывать!
Конечно, это одна из тех моделей, которым я отдаю предпочтение. Она передает право принятия решений тем людям, которые могут справиться с этим лучше других, повышая тем самым эффективность работы и автономность команды, но и заставляя ее нести ответственность за свою работу. Мне приходилось видеть слишком многих разработчиков, передающих свои системы на тестирование и развертывание и считающих, что на этом их работа завершена.
Мне встречалось множество команд, принимавших на вооружение модель общего владения сервисами. Я не считаю эту модель оптимальной по причинам, которые уже были рассмотрены. Но думаю, что разобраться в мотивах, побуждающих людей к выбору общих сервисов, для нас очень важно, особенно в том смысле, что это, возможно, позволит нам присмотреть для себя ряд весьма убедительных альтернативных моделей, с помощью которых можно будет решить основные проблемы людей.
Вполне очевидно, что одной из причин, по которым вам может встретиться отдельно взятый сервис, находящийся во владении более чем одной команды, будет слишком высокая стоимость разбиения сервиса, или же в вашей организации могут не видеть в этом никакого смысла. Такое часто случается при работе с большими монолитными системами. Если это самые большие затруднения, с которыми вам пришлось столкнуться, то я надеюсь, что вы сможете воспользоваться некоторыми из советов, которые были даны в главе 5. Вы также можете рассмотреть вопрос объединения команд, чтобы привести их состав к более полному соответствию архитектуре системы.
Идея команд разработки функций, известных также как функционально ориентированные команды, заключается в том, что небольшие команды разрабатывают набор функций, реализующих всю функциональную нагрузку, которая потребуется даже при пересечении границ компонента (или даже сервиса). Цели, стоящие перед командами разработки функций, вполне обоснованны. Эта структура позволяет команде сконцентрироваться на конечном результате, гарантируя тем самым, что проделанная ими работа будет содействовать устранению ряда сложностей, возникающих при попытке скоординировать изменения, вносимые несколькими различными командами.
Во многих ситуациях команды разработки функций являются реакцией на работу традиционных IT-организаций, где структура команд выстраивается вокруг технических границ. Например, у вас может быть команда, отвечающая за пользовательский интерфейс, еще одна команда, отвечающая за логику приложения, и третья команда, работающая с базой данных. В этой среде команда разработки функций сможет оказать существенную помощь, поскольку она работает над предоставлением функциональных возможностей для всех этих уровней.
При повсеместном использовании команд разработки функций все сервисы могут считаться общими. Внести изменения в любой сервис, в любой фрагмент кода может кто угодно. В таком случае роль кураторов сервисов существенно усложняется, если только она вообще существует. К сожалению, мне редко приходится видеть работу кураторов там, где используется эта схема, и отсутствие этой работы приводит к возникновению тех проблем, о которых говорилось ранее.
Еще раз рассмотрим, что собой представляют микросервисы, — это сервисы, смоделированные по образцу не технической, а бизнес-области. И если команда, владеющая каким-либо конкретным сервисом, аналогичным образом соответствует какой-либо бизнес-области, то, скорее всего, она сможет сохранить ориентированность на клиента и разглядеть больше перспектив разработки, поскольку у нее есть целостное понимание и владение всеми технологиями, связанными с сервисом.
Могут, конечно, происходить и комплексные изменения, но их вероятность существенно снижена тем обстоятельством, что мы избегаем формирования команд по технологическим признакам.
Одной из основных причин, по которым люди стремятся к переходу на применение совместно используемых сервисов, является стремление избежать узких мест в вопросах поставки программных средств. Что делать, если в отдельно взятый сервис требуется внести сразу множество изменений? Представим, что мы предоставляем клиенту возможность видеть музыкальный жанр записи во всех наших товарах, а также возможность добавления совершенно нового типа материала — виртуальных музыкальных рингтонов для мобильного телефона. Команде сайта нужно внести изменения, чтобы отобразить информацию о жанре, а команде мобильной версии приложения — поработать над тем, чтобы позволить пользователям перемещаться по перечню рингтонов, запускать их предварительное прослушивание и покупать их. Оба изменения должны быть внесены в сервис каталогов, но, к сожалению, половина команды загрипповала, а другая половина застряла на выяснении причины сбоя сервиса при работе в производственном режиме.
Избежать подобной ситуации помогут несколько вариантов, не связанных с привлечением общих сервисов. Можно просто подождать и занять команды сайта и мобильного приложения чем-нибудь другим. В зависимости от степени важности функции или того, насколько долгой предполагается задержка, этот вариант вполне может нам подойти, но может и перерасти в весьма острую проблему.
Вместо этого можно будет усилить команду каталогов, чтобы они смогли быстрее справиться с работой. Чем стандартнее будут используемые в вашей системе технологический стек и идиомы программирования, тем проще будет другим специалистам вносить изменения в ваши сервисы. Разумеется, оборотной стороной медали, как уже говорилось, будет то, что стандартизация неизменно приводит к сокращению возможностей команд по выбору наиболее подходящего решения для выполнения своей работы и может привести к разнообразным малоэффективным решениям. Если же команда находится на другой стороне планеты, реализация такого варианта может стать невозможной.