Создание микросервисов — страница 40 из 69

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

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

Насколько продолжительными бывают тесты

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

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

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

Удаление тестов иногда чревато неприятностями, и я подозреваю, что становлюсь похожим на тех людей, которые хотят избавиться от конкретных мер безопасности в аэропортах. Неважно, насколько безрезультатными могут быть меры безопасности, любым разговорам об их отмене зачастую противопоставляется мгновенная отрицательная реакция с утверждениями о том, что при этом пострадает забота о безопасности людей, или ожиданием победы терроризма. Трудно вести взвешенный разговор о ценности тех или иных дополнений в сравнении с вызываемыми ими осложнениями. Также может быть довольно трудно найти компромисс между рисками и благодарностями. Поблагодарит ли вас кто-нибудь за удаление теста? Вполне возможно. Но вас, несомненно, начнут проклинать, если удаление теста повлечет за собой пропуск какого-либо изъяна. И когда речь заходит о тестовых наборах с обширной областью действия, то без такой возможности нам просто не обойтись. Если одну и ту же функцию проверяют 20 различных тестов, то, поскольку их выполнение занимает десять минут, возможно, от половины из них мы можем отказаться! Для этого требуется более четкое осознание риска, в чем люди пока не преуспели. В результате это разумное курирование и управление тестами, имеющими широкий функциональный охват и высокую нагрузку, происходит крайне редко. Желание заняться этим еще не означает реального проведения этой работы.

Сплошное нагромождение

Когда дело доходит до производительности труда разработчиков, проблема состоит не только в продолжительности циклов получения обратных результатов, связанных с проведением сквозных тестов. При длительном выполнении наборов тестов любой сбой требует времени на устранение, что снижает степень наших ожиданий относительно времени прохождения сквозных тестов. Если мы станем развертывать только те программы, которые успешно прошли все тесты (что, собственно, мы и должны делать!), это будет означать, что степени готовности к развертыванию для работы в производственном режиме достигнет только малая часть наших сервисов.

Это может привести к нагромождению невыполненных дел. Пока будут устраняться изъяны, вызванные сбоем теста интеграции, могут накопиться следующие изменения от взаимодействующих команд. Помимо того что это может усилить сборку, это означает увеличение масштаба изменений развертываемого кода. Эту проблему можно решить тем, чтобы не дать хода изменениям при сбоях сквозных тестов, но при наличии довольно долго выполняемого набора тестов это зачастую не представляется практичным. Попробуйте сказать: «Эй вы, тридцать разработчиков, не вздумайте поставить себе галочку, пока мы не потратим семь часов на отладку сборки!»

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

Метаверсия

По окончании сквозного тестирования вполне можно прийти к мысли: раз все эти сервисы данной версии могут работать вместе, почему бы их вместе и не развернуть? Вскоре это превращается в разговор о том, почему бы не воспользоваться номером версии для всей системы. Все по Брэндону Брайарсу (Brandon Bryars): «Теперь у вас 2.1.0 проблем».

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

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

И в этом нет ничего хорошего.

Тестируйте маршруты, а не истории

Несмотря на указанные недостатки, при использовании одного или двух сервисов многие пользователи все же смогут справиться с управлением сквозными тестами, проведение которых в подобных ситуациях представляется вполне разумным действием. А что, если используются 3, 4, 10 или 20 сервисов? Очень быстро эти наборы тестов станут весьма сильно раздутыми, что в худшем случае приведет к взрывному росту тестируемых сценариев.

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

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

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

Тесты на основе запросов потребителей, спасающие ситуацию

С какой из ключевых проблем при использовании упомянутых ранее интеграционных тестов мы пытаемся справиться? Мы стараемся гарантировать, что при развертывании нового сервиса для работы в производственном режиме внесенные нами изменения не внесут разлад в работу потребителей. Одним из способов добиться обозначенной цели без необходимости проведения тестов с участием реальных потребителей является использование контрактов, составленных на основе запросов потребителей (CDC).

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