Мессенджеры, приватность и интернет — изнутри

Интернет

Как паттерн адаптеров спас Angular-форму на 40 полей от 700 строк switch-case

Старший Angular-разработчик команды Klecks Дмитрий Чепайкин рассказал, как в AI-центре Т-Банка рефакторили сервис редактирования заказа. Форма разрослась до более чем 40 полей: цена, приоритет, теги, настройки перекрытия, GPT-опции, автобан, лимиты, типы устройств и десятки других. Вся логика жила в одном файле EditOrderFormService, который превысил 700 строк.

Для каждого поля требовалось инициализировать FormControl, преобразовывать значение из DTO в формат формы и обратно, настраивать валидаторы и сравнивать текущее значение с исходным, чтобы отправить только изменённые поля. Всё это было реализовано через множественные блоки switch-case, размазанные по методам конвертации, деконвертации и валидации. Тестировать такой сервис становилось тяжело: чтобы проверить поведение одного поля, приходилось поднимать контекст на десятки других.

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

Каждое поле получило собственный класс-адаптер с единым интерфейсом OrderFormFieldAdapter. Адаптер знает, как работать с конкретным полем: конвертировать DTO в FormControl и обратно, валидировать и определять, изменилось ли значение. Интерфейс включил ключ поля в DTO, путь к контролу в FormGroup, метод инициализации контрола, опциональные методы для валидаторов и реакции на обновление сохранённых опций, а также главные методы fromDto и toDto.

Зависимости адаптеры получают через контейнер AdapterServices, оставаясь обычными TypeScript-классами без декораторов @Injectable. Большинство полей ведут себя одинаково, поэтому появился BaseAdapter. Он берёт значение из DTO, кладёт в контрол, а при сохранении сравнивает с исходным и возвращает результат только при расхождении.

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

Вся эта логика теперь живёт в одном файле PriceAdapter, и тестировать её можно изолированно, не поднимая весь сервис формы. После рефакторинга сервис формы превратился в оркестратор, который лишь регистрирует адаптеры и запускает их методы в нужные моменты. Switch-case и «шумные» блоки исчезли.

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

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

разработка

Оригинал

Обсуждение

Комментариев пока нет.

Похожие новости