
Меня зовут Петр Боклашов, я руководитель группы разработки в Лиге Цифровой Экономики. В основном я занимаюсь backend-разработкой на стеке технологий Java, Spring Boot. Однако в этой статье хочу поделиться подходом к разработке на основе реального опыта.
В основном эта статья будет полезна именно разработчикам или их руководителям для построения процессов в команде и обучения младших разработчиков. Кроме того, на уровне управления проверкой материал способен помочь менеджерам под другим углом взглянуть на продукт, который делают разработчики. Текст — попытка систематизировать опыт и собрать практический чек-лист: что стоит проверить в микросервисе перед релизом, чтобы не столкнуться с типичными техническими проблемами уже в продакшене.
Про подход к разработке: два направления
Для начала разделю категории функций, которые выполняет сервис или микросервис (дальше буду называть просто сервис). Разделим их на два лагеря: бизнес-функции и технические функции.
Бизнес-функции — это то «хорошее», что должен делать сервис. Это не API, не структура БД, а то, для чего вообще решили делать сервис или целиком систему, частью которой он является.
Однако у сервиса есть и большой набор технических функций, которыми обрастают бизнес-функции: поддерживаемость кода, надежность его работы, полнота логов, наличие трассировок и даже скорость работы. Все это можно отнести к техническим функциям.

Это верно не только для микросервисов. Однако они добавляют большое количество технических функций. Заказчика, бизнес-аналитика, да и руководство не очень-то и волнует, что у вас за микросервисы и что есть проблемы с транзакциями, DLQ (Dead Letter Queue, очередь необработанных сообщений), retry (повторная попытка) ошибок и тому подобным.

Эти два набора функций развиваются параллельно росту сервиса. Важно понимать: текущий список бизнес-функций обычно неполный и предварительный — в процессе уточнения требований он будет меняться, какие-то функции могут скорректировать или вовсе убрать. Если под такой «сырой» набор сразу начинать реализовывать все связанные с ним технические функции, это съест огромное количество ресурсов. А по факту бизнес-ценность продукта изменится не сильно, потому что значительную часть работы, скорее всего, придется переделывать.
Чтобы этого избежать, мы составили чек-лист микросервисов: классифицированный набор технических функций, который лучше не делать сразу, можно отложить на более поздние этапы разработки и при этом про них не забыть.
Чек-лист: проверь себя
Каждый раздел этого чек-листа мы отнесли к этапу внедрения микросервиса в продуктивный контур. Разделы состоят из нескольких пунктов, которые можно рассматривать как набор примеров, на что обратить внимание. Это не попытка сделать какой-то стандарт — скорее подход и пример, исходящий из опыта работы в команде.
Технический долг призван исправить проблемные части кода, с которыми не хочется разбираться прямо сейчас, поскольку на «полет» сервиса это не влияет. Однако эти исправления достаточно важные или их исправление на поздних стадиях будет значительно сложнее. Поэтому техдолг нужно исправить до какого-либо релиза вообще, включая интеграционный либо тестовый релизы. (Интеграционный релиз — это когда вся система еще не готова, мы понимаем, что одна или несколько интеграций с другими системами может быть проблемной, и хотим проверить ее пораньше.)
Надежность — это то, насколько много проблем будет с сервисом. Много проблем никому не нужно, поэтому рекомендую пройтись по этому разделу чек-листа до начала даже первой, может, еще не такой активной эксплуатации сервиса или системы целиком.
Мы понимаем, что проблемы будут всегда, и должны быть к этому готовы. Они могут быть даже не у нас, но пальцем-то будут показывать именно на команду. Поэтому наблюдаемость в сервисе нужно улучшить до массовой эксплуатации, когда пользователей будет уже столько, что вылезут мелкие проблемы, которые сложно найти, а также проблемы производительности.
То, что раздел тестов оставлен в конце, может показаться спорным, особенно если вы приверженец жестких методологий, но давайте разберемся на практике.

Технический долг
Внедрение скриптов миграции БД
Если придерживаться принципа одной БД на один сервис, то сам сервис зачастую и создает структуру БД. Для этого используются библиотеки управления версиями структуры БД, например Flyway, Liquibase. Если начать вести версии БД сразу, то это затруднит разработку без особой выгоды. Изменение и добавление бизнес-функций зачастую сказывается и на структуре БД. Даже если ясны все процессы, то тот же атрибутивный состав может еще долго проясняться до конца. Если же вести версии БД сразу и формально, то, во-первых, могут потребоваться нетривиальные скрипты миграции. Во-вторых, не очень хочется, чтобы процесс разработки перетекал в прод, где все эти скрипты миграции должны быть успешно применены.
Для того чтобы не отвлекаться на структуру БД и скрипты миграции, можно использовать auto-ddl (автоматическое создание схемы БД), предлагаемый ORM фреймворками (Object-Relational Mapping, технология связывания объектов кода с таблицами базы данных), или вести один скрипт создания БД и при сложных изменениях просто создавать БД заново. Во время разработки сохранение данных на дев-стенде (тестовом стенде для разработки) не так нужно, достаточно просто предупредить аналитиков или тестировщиков. Из опыта — на один сервис обычно требуется одна зачистка данных при переходе на версионирование структуры БД и иногда — одно-два удаления данных в БД при сложных изменениях структуры.
Оптимизация доступа к данным
После перехода на версионирование структуры БД (или же вместе с этим) уже можно подумать и о том, насколько оптимально код использует БД, а также оптимизировать саму структуру БД. Во время разработки скорость работы с БД почти всегда неважна. Не стоит понимать это в разрезе архитектурных решений при большом количестве данных — скорее как «где можно сэкономить и на что можно не обращать внимания при разработке». Если вы для оптимальности не планируете, к примеру, использовать ORM фреймворк, то на этапе разработки он может вам сэкономить немало времени. Если иметь в приложении изолированный уровень доступа к БД, такое изменение будет достаточно быстрым, особенно когда понимаешь, что все основные бизнес-функции уже реализованы и большого количества изменений не предвидится.
Если ваш сервис будет использовать ORM фреймворк как целевое решение, то на этом этапе нужно его проверить. Даже зная все обо всех особенностях ORM фреймворка, ошибиться довольно просто. Чтобы этого избежать, достаточно включить логирование и посмотреть, сколько запросов выполняется и насколько они оптимальны. А после — просто привести их близко к оптимально возможному, чего достаточно для большинства сервисов.
TODO («сделать позже»)
Тут стоит вспомнить «плохой» код, который при нашем подходе оставляют специально. Под таким кодом я понимаю некие компромиссы со временем: а насколько важно сейчас пытаться сделать код красивым, читаемым, быстрым? Если на это уйдет немного времени, то лучше сделать сразу. Однако бывают случаи, когда разработчик в команде впадает в ступор и тратит много времени на какую-то задачу в том месте, где это ничего не даст с точки зрения бизнес-функций сервиса. Тем более что эта бизнес-функция может быть изменена значительно или вообще удалена. Поэтому в таких случаях лучше оставлять TODO и вернуться к ней на этом этапе.
Почему именно TODO, а не, скажем, задача в Jira? Не стоит себя обманывать: если что-то нельзя сделать просто и удобно, то увеличивается шанс, что это не будет сделано вовсе. В коде очень просто оставить TODO, оно сразу привязано к месту в коде, а текущие IDE (Integrated Development Environment, среда разработки) и статические анализаторы кода не устанут тебе напоминать их разрешить.
У меня был разговор с руководителем проекта, которому не очень нравились TODO. Разработчик выполнил задачу, но оставил TODO. С точки зрения руководителя задача вроде как выполнена, время затрачено, больше усилий прикладывать не нужно. Но по факту — не до конца. И вот для этого как раз нужно иметь задачу по разрешению всех TODO, а разработчиков просить оставлять их в коде.
Решение проблем от статических анализаторов кода
Статические анализаторы кода кому-то нравятся, кому-то нет, кого-то раздражают. Однако в среднем они дают достаточно информативные замечания по коду. Сразу бежать их исправлять смысла нет. Код под ними может быть временным, потому что такой бизнес-функции в сервисе не будет или она изменится. Или же мы знаем, что нужно что-то поправить, но для этого потребуется большая переработка — и, соответственно, это уйдет в TODO.
Но даже если исправлять все ошибки на лету (на некоторые время почти и не тратится), то закрепить то, что в сервисе их нет, и выборочно еще раз пройтись по списку будет всегда полезным.
Анализ логов запуска и работы
Статические анализаторы кода, каким бы странным это ни казалось, не помогут с ошибками запуска или работы сервиса. Однако зачастую библиотеки помогают нам с этим и пишут предупреждения (уровень логирования WARN) в лог. Очень странно бывает видеть сервис, которому уже немало месяцев на проде, но у него ворнинги в логах при старте или постоянно. Казалось бы, разработчики библиотек хотят нам помочь, а мы даже в лог не можем посмотреть. Один из примеров, если вспоминать Spring и JPA — «spring.jpa.open-in-view is enabled by default…». Поэтому нужно посмотреть, как работает сервис, желательно с интеграцией на дев-стенде, и убедиться, что в логах нет ничего подобного.
Надежность
На этом этапе код уже чище, но вот надежности может не хватать.
Если система или сервис написаны так, что для их работы нужно еще пять девопсов на постоянное поднятие всей системы или постоянные «корректировки» в БД, то что-то с сервисом не так. Дело в том, что эксплуатация и девопсы сами могут решить не все проблемы, а это и дополнительное время разработчиков с аналитиками, и нервы заказчика. Достаточно скоро экономия времени на плохой надежности сервиса перерастает в значительные затраты по ресурсам.
Обработка входящих сообщений
Каждый сервис в большинстве случаев обрабатывает какие-то входящие сообщения: из брокера сообщений, HTTP-запросы и тому подобное. Аналитики могут предусмотреть успешный прием сообщения или бизнес-ошибку в нем, однако это далеко не все, что может прийти к вам на вход. Сообщение может прийти нужное, но не той версии формата, могут затесаться неизвестные поля, обязательные технические поля — отсутствовать, или вообще придет картинка с JSON внутри.
Если отсутствует обработка таких случаев, то это может привести к ряду проблем:
-
будет ошибочная ситуация где-то глубоко в коде, а не понятное сообщение в логе вида «Забыли такой-то атрибут!». Причину такой ошибки можно долго искать;
-
страшнее, если ошибки вообще не будет сообщение обработается и переведет систему в кривое состояние;
-
если мы поняли, что пришло сообщение, с которым мы не можем работать, то что с ним дальше делать? Например, в некоторых брокерах сообщений будет бесконечный повтор, в некоторых — 10 повторов без малейшего ожидания между ними;
-
хорошо, поняли, что не можем обработать сообщение, продумали повторную обработку, а что в конце? Отправить сообщение в DLQ, где оно будет лежать мертвым грузом и только периодически эксплуатация будет спрашивать, а нельзя ли почистить DLQ, что-то занимает много места?
Понятно, что на этапе активной разработки такие случаи не важны. Все еще работает только на дев-стенде и ошибок везде навалом. Однако нужно обязательно проанализировать обработку входящих сообщений. Не уходя в конкретику используемых инструментов, можно выделить следующие моменты, на которые стоит обратить внимание:
-
как можно раньше в коде обработать сообщения на соответствие формату;
-
проверить в логике работы сервиса: если мы приняли сообщение, то его обязаны обработать, и нет кусков кода, которые будут падать на сообщение, которое прошло форматно-логический контроль на входе;
-
согласовать с другими сервисами и с аналитиками, что же делать, если сообщение мы обработать не можем.
Атомарность обработки сообщений
Небольшой вопрос, но если углубиться в проблему, то можно найти немало проблем. Если мы вернули потребителю ответ API, что запрос успешно обработан, то точно ли мы это гарантируем?
Простой пример:
-
сервис получил запрос;
-
получил что-то по нему из БД;
-
сохранил что-то в БД;
-
сохранил что-то в Файловое Хранилище (S3);
-
обновил после этого результат сохранения в Файловое Хранилище (S3);
-
ответил, что запрос обработан.
И простые вопросы:
-
а что, если второй UPDATE не прошел?
-
сохранение файла было не успешным?
-
отправка ответа не успешна?

Ответы на эти вопросы можно найти, это не так сложно. Важно понимать, что такого рода проблемы может никто и не обнаружить на дев-е, даже если будет хорошо стараться. Поэтому важно не забыть проанализировать код на предмет такого рода проблем и выработать решение. Среди того, на что стоит обратить внимание (далеко не полный список, сильно зависит от сервиса в разработке), я выделяю:
-
банально проверить, что там, где внешний сервис (БД, Kafka и т. п.) поддерживают транзакции, то они включены и используются, если это нужно;
-
поскольку организовать транзакцию между разными внешними сервисами может быть сложно, а иногда и невозможно (с нужной степенью гарантии), то, вероятно, стоит ограничиться одним источником. Для примера — паттерн transactional outbox, асинхронная обработка частей запросов и т.п.;
-
если что-то пошло не так, хотя бы попробовать откатить часть изменений.
Стоит обратить отдельное внимание на особенность вызова других сервисов системы. Для обеспечения атомарности обработки входящих запросов зачастую придется повторять внешние запросы. Гарантировать семантику вызова exactly-once достаточно сложно, особенно с учетом возможных технических и бизнес-повторов. Я бы даже сказал, что, если думаете, что гарантировали, то лучше еще раз проверить. Поэтому проще всем понять, простить, остановиться на at-least-once и просто быть к этому готовым.
Идемпотентность обращений к сервису
Идемпотентность — это что-то из математики. Нам важно другое. Если нет гарантии exactly-once при обращении в наш сервис (а почти никогда нет), то мы обязаны гарантировать, что при приеме того же бизнес-сообщения наш сервис будет в состоянии, как будто он принял сообщение только один раз.
Для того чтобы принять решение, что делать с сообщением, нужно его идентифицировать. Можно выделить два типа идентификаторов: технические и бизнес-идентификаторы. Технические идентификаторы — это, например, идентификаторы сообщений, проставляемые брокером сообщений автоматически. Бизнес-идентификаторы — это, например, идентификатор гражданина в ЕПГУ (Единый портал государственных и муниципальных услуг).
Процесс будет различаться от сервиса к сервису, но в основном:
-
сообщения с одним техническим идентификатором мы не должны обрабатывать повторно вообще;
-
про бизнес-идентификаторы нужно уточнить у аналитиков.
Надежность обращения в другие сервисы
Наш сервис возвращает ошибки качественные и понятные. Другие сервисы, возможно, тоже. А как мы работаем с этой информацией? От типа ошибки может зависеть дальнейший процесс в сервисе.
Для начала стоит прояснить API других сервисов в случае возникновения ошибок. Если это HTTP-запросы, то HTTP-статусы могут иметь специфичные для сервиса значения, а возможно, будет всегда статус 200 с определенным JSON. Как только мы смогли понять тип ошибки, то можно проработать, что с ними делать, например:
-
какие-то запросы можно повторять, а какие-то нет;
-
какие-то могут влиять на бизнес-логику работы;
-
какие-то приведут к откату транзакции, а какие-то нет.
Работа в несколько экземпляров
Микросервис всегда работает в несколько экземпляров, и эти экземпляры могут быть разных версий. Второе тут не важно — мы же пока только делаем первый релиз сервиса, а вот первое — вполне. Если в код закралась синхронизация потоков обработки, не предназначенная для разных процессов, то будут проблемы.

На дев-стенде, скорее всего, будет запущен только один экземпляр: не важна надежность, память и CPU (центральный процессор) в кластере не резиновые. Поэтому стоит обратить внимание на:
-
синхронизацию потоков — например, в Java, если есть Synchronize или Lock, то нужно понимать, что это только для одного экземпляра;
-
если что-то храним в памяти, например кэш, то это тоже будет только в одном экземпляре сервиса;
-
все процессы, включая те, что гарантированно выполняются в одном потоке в приложении, должны модифицировать записи в БД с блокировкой (проще всего с пессимистичной, но можно и оптимистичной).
Потоки и подключения
В этом пункте нужно решить следующую проблему: сервис не потребляет память, не потребляет CPU, но при этом медленно обрабатывает запросы. В сервисе могут использовать, напрямую или в библиотеках, различные ресурсы: треды, очереди обработки, пулы подключения и тому подобное. При достижении определенного количества входящих запросов некоторые из этих ограничений могут быть достигнуты, и сервис начнет медленно работать, но не потреблять ресурсов.
Для примера:
-
количество подключений к БД по умолчанию установлено в 10;
-
поменять нельзя или не ясно, как это сделать;
-
в продуктивном контуре запускается 20 экземпляров;
-
администратор БД видит откуда-то 200 подключений (и это только от одного сервиса).
Тут речь не идет о каком-то глобальном пересмотре принятых при разработке сервиса решений, а больше даже о том, чтобы в принципе позволить настроить эти ресурсы:
-
для различных библиотек — вынести в описание сервиса настройки этих ресурсов, чтобы эксплуатации лишний раз не искать для этого разработчиков;
-
для нашего кода, помимо описания сервиса, в принципе добавить переменные приложения для настройки этих ресурсов.
Наблюдаемость
Если надежность призвана сделать так, чтобы проблем было меньше, то наблюдаемость — помочь понять, что проблем нет или, если они все же появились, в чем их причина.
Логирование
Самый простой сигнал — это логи. Им много лет, с ними все работали, все понимают, зачем они. Вопрос обычно возникает в их количестве и распределению по уровням логирования. На дев-е нет ни персданных, ни большого объема запросов, поэтому там это неважно. Однако если не обратить внимание, то на проде это может быть выглядеть страшно.
2026-03-10T17:07:41.222+03:00 INFO 38373 --- [nio-8080-exec-5] [8c35933d4408620c879940c53062c286-dd03df68b0fa9785] r.p.research.controller.TestController : Получен запрос: TestRequestDto[fio=Петров Петр Петрович, birthDate=2000-03-10, documentNumber=1231212]2026-03-10T17:07:41.223+03:00 INFO 38373 --- [nio-8080-exec-5] [8c35933d4408620c879940c53062c286-dd03df68b0fa9785] r.p.research.controller.TestController : Запрос обработан успешно
Может быть, защита в БД персданных с маскированием и тому подобным, но в логах все будет видно наглядно, потому, что оставили персданные в info уровне.
Даже без персданных логов может быть просто очень много.
2026-03-10T17:17:46.356+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Получен запрос на обработку файла2026-03-10T17:17:46.357+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 02026-03-10T17:17:46.357+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 12026-03-10T17:17:46.357+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 22026-03-10T17:17:46.357+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 32026-03-10T17:17:46.357+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 42026-03-10T17:17:46.358+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 52026-03-10T17:17:46.358+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 6…2026-03-10T17:17:46.365+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 952026-03-10T17:17:46.365+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 962026-03-10T17:17:46.365+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 972026-03-10T17:17:46.365+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 982026-03-10T17:17:46.365+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Успешно обработана строка 992026-03-10T17:17:46.365+03:00 INFO 47390 --- [nio-8080-exec-5] [4415d946f5da745ef2ce24449c11d3cb-f24754f7976a9d23] r.p.research.controller.TestController : Завершена обработка
В противовес, на дев зачастую уровень логирования может быть debug, и на проде вообще не будет логов. Непонятно, работает сервис или нет.
В этом пункте важно еще раз взглянуть комплексно на логирование в нашем сервисе. Для простоты лучше выработать понятные показатели по тому, какой уровень логирования использовать. Понятно, что у разных команд он будет разный, но для примера наш:
-
Trace
-
персональные данные, если, к примеру, логируем все входящие сообщения;
-
очень подробный лог, тысячи сообщений за одну активность.
-
-
Debug
-
не стараться экономить на сообщениях логов;
-
подробная информация о начале и конце каждого процесса;
-
все ветвления;
-
все важные промежуточные точки;
-
добавить идентификаторы запросов, бизнес-идентификаторы;
-
запуск периодических задач.
-
-
Info
-
информация о начале работы важных процессов;
-
по логу должно быть понятно, что сервис работает, но их не должно быть очень много.
-
-
Warn
-
можем продолжить процесс и доведем его до конца, но произошло что-то странное.
-
-
Error
-
ошибка в процессе, не можем его довести до конца.
-
Формат API-ошибок нашего сервиса
В разделе об обработке ошибок внешнего сервиса я упомянул, что наш сервис возвращает понятные ошибки в случае возникновения проблем. Поэтому никуда не деться — другие команды мы достали этим, придется делать и нам. Из рекомендаций я обычно выделяю:
-
(java) для выбрасываемых нами исключений, предусмотреть коды ошибок;
-
в ответ включить как код ошибки (для автоматической обработки) и описание ошибки (для человекочитаемого сообщения);
-
кодов ошибок не должно быть много и они должны быть значимыми для потребителя API, так, чтобы ему не понадобилось вникать во внутренние детали нашего сервиса;
-
лучше добавить структурированный формат ошибок, чтобы проще было его обрабатывать.
Формат API-ошибок других сервисов
В разделе надежности я описывал важность того, что стоит понять API внешнего сервиса в случае ошибок для того, чтобы можно было принять решение, что с ними делать. Однако важно еще и видеть, что, собственно, произошло. Для примера, в том же логе можно видеть сообщения вида:
-
«что-то пошло не так» и далее stack trace;
-
«ошибка при вызове сервиса {service}»;
-
«При вызове сервиса {service} по адресу {host}:{port}, возникла ошибка {code}: {description}».
С учетом того, что мы и так уже разобрали сообщение об ошибке от внешнего сервиса, то залогировать это хорошо — уже мелочь. Понятно, что есть трассировки. Можно сказать — идите смотреть в другой сервис, но на практике это значительно упрощает разбор проблем без особых затрат в коде.
Метрики, дашборды и трассировки
Для большинства языков и фреймворков в разработке сейчас создание метрик — это очень простой процесс. Даже все сторонние сервисы обычно распространяются с метриками prometheus и дашбордами для Grafana. Поэтому метрики и дашборды для сервиса становятся такой же обязанностью, как и readme (файл с описанием проекта). Сервис обязан предоставить, помимо метрик от библиотек, еще и необходимые метрики на процессы сервиса и дашборды к ним. Это значительно сокращает поиск проблем и позволяет понять, что же происходит с сервисом, не только разработчикам.
Трассировки, так же как метрики — это очень просто. Opentelemetry в этом тоже помогает. Поэтому, скорее всего, для поддержания трассировок достаточно будет всего несколько небольших настроек и, возможно, добавления нескольких атрибутов для простоты поиска трассировок. Трассировки, как и логи, нужны нечасто, но когда возникает проблема, они позволяют значительно сэкономить время для поиска проблемного места.
Проверка работоспособности
До этого я больше писал о наблюдаемости состояния сервиса людьми. Сейчас микросервисы почти всегда идут рука об руку с тем, где они разворачиваются, а именно в k8s. Поэтому требуется еще и машинная наблюдаемость. В случает с k8s это readiness и liveness пробы (проверка готовности и работоспособности). Можно, конечно, пытаться определить это по доступности портов или другим способом, но лучше настроить и предоставить API для определения состояния сервиса. В том же Spring Boot это делается из коробки с небольшими настройками.
Помимо технической части, стоит еще задаться вопросом — а что же является для вашего сервиса liveness и readiness:
-
БД сервиса — скорее всего, да;
-
внешний сервис — возможно, уже нет.
Если сервис «не живой», то k8s может его рестартовать. Если он «не готов», то на него не будут направлены запросы. Поэтому стоит подумать, какое состояние сервиса должно приводить к первому, а какое — ко второму.
Покрытие тестами
По поводу тестов есть неудобный, на мой взгляд, факт, от которого не стоит прятать глаза, а лучше принять и понять, как с этим работать: заказчик или руководитель требует определенный процент покрытия, но не все тесты одинаково полезны.
Поэтому я выделяю два вида тестов:
-
первые, которые помогают в разработке кода: они тестируют логику, задают контракт внутреннего и внешнего API и т. п.;
-
вторые, которые повышают покрытие за счет тестирования неких технических структур сервиса: классов настроек (java, Spring Boot), структур по разделению на слои и т. п.
Первые виды тестов нужно писать сразу и, по сути, это неотъемлемая часть кода. А вот вторые могут быть даже вредными. Поэтому в этом пункте уже пишется второй вариант тестов.
Однако даже такая активность, как написание таких тестов, может быть полезной в развитии младших разработчиков:
-
они знакомятся с сервисами команды;
-
знакомятся с подходами к разработке сервисов в команде;
-
лучше начинают видеть плохой код, когда пишут на него тесты.
Подытожим
Еще раз хотелось бы подчеркнуть основной посыл статьи. Нужно быстрее и более эволюционно внедрять бизнес-функции сервиса. При этом — выделить технические функции, которые можно не реализовывать до определенного этапа разработки сервиса. После составления такого списка — четко понять и согласовать в команде, на что не тратить время сразу и что точно не забыть сделать потом.
Какие-то процессы по чек-листу можно и автоматизировать. Для примера — мы автоматизировали создание задач и подзадач в Jira по всему списку и на определенном этапе развития сервиса запускаем его прохождение.
Кроме того, как я отметил, тесты помогают младшим разработчикам вникнуть в особенности разработки, принятые в команде. Чек-лист целиком — это еще более интересное и эффективное средство обучения. Разработчик, проходя по нему, решает вопросы, о которых он мог даже и не задумываться.
Скачать чек-лист

ссылка на оригинал статьи https://habr.com/ru/articles/1028956/