Flutter-приложение легло после апдейта 1С: как архитектура это остановила
Мобильное приложение на Flutter, завязанное на 1С, ломается не от плохого кода, а от связи экрана напрямую с полями базы. Правильная архитектура — три независимых слоя: данные (обмен с 1С), бизнес-логика и интерфейс. Тогда обновление конфигурации 1С меняет один файл-адаптер, а не весь проект, и приложение не встаёт посреди рабочего дня.
как приложение легло в разгар дня
История типичная для дистрибьюторов: у клиента 30+ торговых представителей в регионах, каждое утро открывают Flutter-приложение, чтобы проверить остатки на складе, посмотреть карточку контрагента и оформить заказ через 1С прямо на выезде у клиента. Во вторник в 9:20 утра у половины команды список контрагентов перестал загружаться — вместо карточек пустой экран и красная плашка с ошибкой парсинга. Накануне вечером в 1С обновили конфигурацию: переименовали реквизит в справочнике «Контрагенты» и добавили новый обязательный атрибут статуса оплаты. Мобильное приложение ждало старые имена полей, получило новые — и не смогло их прочитать. Ни один торговый представитель не мог понять, баг это у него на телефоне или проблема на сервере, поэтому все звонили в поддержку одновременно, и линия оказалась перегружена в первый же час рабочего дня.
почему архитектура ломается при каждом обновлении 1С
В коде приложения экран контрагентов сам разбирал ответ от 1С: JSON из OData-запроса парсился прямо внутри build-метода виджета, оттуда же бралось поле для отображения статуса и остатка на складе. Отдельного слоя, который отвечал бы только за формат данных, не было — экран, бизнес-правило «показывать красным просроченную задолженность» и обращение к серверу жили в одном файле на триста строк. Разработчики знали, что это узкое место, но переписывать боялись: слишком много завязок на один файл, легко сломать ещё что-то в соседнем экране, который использует тот же виджет. Поэтому каждое обновление 1С било в одну и ту же точку, и правка растягивалась на несколько дней: сначала найти, что именно изменилось в структуре данных, потом поправить экран, потом протестировать вручную, потому что автотестов на UI-логику никто не писал — она была намертво сплетена с виджетами.
Пока шла правка, торговые представители не могли принять заказ через приложение и переходили на звонки диспетчеру. Диспетчер физически не успевал обработать поток заявок голосом, часть клиентов, не дозвонившись, отправляли заказ конкуренту с работающим сайтом. Разработчику пришлось откладывать текущую задачу по новой фиче и разбирать чужой код в экстренном режиме, а готовый патч всё равно проходил штатную модерацию в App Store и Google Play, которая занимает не часы, а дни — то есть даже исправленная версия доходила до пользователей не в тот же день. Для компании с оборотом в сотни заказов в день это не абстрактный риск, а конкретный сорванный рабочий день у половины полевой команды, перегруженная линия поддержки и разработчик, выдернутый из плана на неделю вперёд.
три слоя, которые остановили цепочку поломок
Решение — не переписать приложение с нуля, а развести код по слоям так, чтобы изменение в 1С задевало один файл, а не весь проект. В основе — стандартная для Flutter слоистая архитектура: data, domain, presentation, и чёткое правило, что слой выше не знает о деталях слоя ниже.
слой данных — единственная точка, которая знает про 1С
Всё общение с 1С — через интеграцию приложения с 1С по OData или REST — стянуто в repository и DTO-классы. Если 1С переименовала реквизит, правится один маппер: поле из ответа сервера превращается в поле доменной модели с фиксированным именем, которое дальше использует весь остальной код. Экраны и бизнес-логика об этом изменении даже не узнают, потому что видят только доменную модель, а не сырой JSON от 1С.
слой бизнес-логики — правила без интерфейса
Use case-классы описывают, что должно произойти — например, рассчитать итоговую сумму заказа с учётом скидки контрагента или проверить, не превышен ли лимит дебиторской задолженности перед созданием заказа, — но ничего не знают ни про 1С, ни про виджеты, ни про то, как результат отрисуется на экране. Эти правила можно протестировать юнит-тестами без запуска эмулятора и без обращения к серверу: подставляешь тестовые данные, проверяешь результат. Раньше это было невозможно, потому что логика была вшита в экран и требовала поднимать весь виджет, чтобы проверить один расчёт.
слой интерфейса и связка между слоями
Экраны получают уже готовые доменные модели и state от BLoC или Riverpod-провайдера и занимаются только отрисовкой: список, карточка, форма. Виджет не умеет и не должен уметь разбирать ответ 1С. Слои связаны через внедрение зависимостей — repository передаётся в use case, use case передаётся в BLoC, а не создаётся внутри виджета напрямую, поэтому в тестах любой слой легко подменить заглушкой. Даже если завтра часть данных переедет с 1С на отдельный сервис, интерфейс переписывать не придётся — поменяется только слой данных.
как тестируется каждый слой отдельно
Domain-слой покрыт юнит-тестами: правила расчёта скидок и лимитов проверяются на наборе сценариев, включая пограничные — нулевой остаток, просроченная задолженность, контрагент без привязанного менеджера. Data-слой тестируется на фиктивных ответах 1С: в тестах подставляется JSON с обычной структурой и намеренно «сломанной», чтобы проверить, что при отсутствии ожидаемого поля приложение показывает понятную ошибку, а не падает целиком. Presentation-слой покрыт widget-тестами на ключевые экраны — список заказов, форма создания заказа, экран синхронизации. Раньше тестов не было вообще, потому что протестировать логику отдельно от экрана было физически нельзя — весь код держался на ручной проверке перед каждым релизом.
BLoC, Riverpod или Provider — что поставили поверх слоёв
Все три подхода к состоянию решают одну задачу, но по-разному ведут себя на длинной дистанции, когда над проектом работает несколько разработчиков и модель данных меняется извне. Сравнение по проекту с интеграцией 1С:
| подход | объём кода на экран | тестируемость логики отдельно от UI | когда оправдан для проекта с 1С |
|---|---|---|---|
| Provider | минимальный | слабая — состояние легко смешать с виджетом | небольшой MVP, 3-5 экранов, без сложной синхронизации с 1С |
| Riverpod | средний | хорошая, провайдеры тестируются без контекста виджета | средний проект с офлайн-кэшем и несколькими источниками данных |
| BLoC | выше среднего, больше файлов | отличная — события и состояния описаны явно | B2B-приложение с очередью синхронизации заказов и сложными сценариями офлайн-режима |
| MobX | средний | средняя, реактивность скрывает часть логики | команда уже знакома с MobX по другим проектам |
Для распределённой команды торговых представителей с офлайн-очередью заказов выбрали BLoC: явные события «заказ создан», «синхронизация начата», «конфликт данных обнаружен» проще разбирать в логах поддержки, когда менеджер звонит и говорит, что заказ пропал. По логу видно, на каком именно событии остановился поток, а не приходится воспроизводить баг на живом телефоне торгового представителя, который уже уехал к следующему клиенту.
что изменилось после переезда на новую архитектуру
Проверка не заставила себя ждать: в марте 1С снова переименовали реквизит, на этот раз в справочнике номенклатуры. Правка ушла в маппер одного data-класса, юнит-тесты на domain-слой прошли без изменений, экраны не трогали вообще. Релиз собрали и протестировали в течение рабочего дня вместо нескольких дней разбора, где именно всё сломалось, и отправили в сторы с понятным списком изменений в одном файле, а не с диффом по десятку экранов.
Отдельно закрыли вопрос с офлайн-кэшем: в нём хранятся ФИО и телефоны контрагентов для работы без связи в удалённых точках, а локальное хранилище персональных данных подпадает под требования 152-ФЗ так же, как серверное. Кэш зашифровали на уровне базы на устройстве, а не полагались на то, что телефон торгового представителя сам защищён паролем экрана блокировки.
чек-лист — пора менять архитектуру, если это про ваше приложение
- ✓правка после каждого обновления 1С занимает больше одного рабочего дня, потому что приходится искать связанные файлы по всему проекту
- ✓бизнес-логику нельзя протестировать без запуска экрана на эмуляторе — расчёты и виджет живут в одном классе
- ✓в команде остался один разработчик, который «помнит», как всё связано, и без него правки останавливаются или растягиваются на недели
- ✓офлайн-режим периодически теряет или дублирует заказы после рассинхронизации с 1С
- ✓каждая новая фича требует правок в трёх разных местах вместо одного, потому что данные, логика и интерфейс перемешаны
Если хотя бы два пункта совпадают с вашим приложением — дешевле пересобрать слои сейчас, чем полгода латать одни и те же места после каждого релиза 1С. Мы делаем такой аудит и переносим B2B-приложение с 1С на слоистую архитектуру без остановки текущей версии в сторах: старое приложение продолжает работать у пользователей, пока новая версия проходит тестирование и модерацию. Стоимость разработки мобильного приложения с такой архитектурой с нуля — от 500 000 руб, для готового проекта миграция на слои обходится дешевле полной переделки; актуальные цены и тарифы — на отдельной странице.
❓ Частые вопросы
Сколько стоит переработать архитектуру уже готового Flutter-приложения?
Зависит от размера проекта и того, насколько перемешаны слои данных, логики и интерфейса. Разработка с нуля с такой архитектурой стоит от 500 000 руб, миграция готового проекта на слои обычно дешевле полной переделки — точную сумму называем после аудита кода.
Обязательно ли использовать BLoC, или подойдёт Provider?
Provider хватает для простого MVP на 3-5 экранов без сложной синхронизации с 1С. Если в приложении офлайн-очередь заказов и несколько источников данных, BLoC или Riverpod избавляют от путаницы в состояниях при росте проекта.
Как понять, что архитектуру пора менять, а не терпеть текущие правки?
Главный признак — правка после каждого обновления 1С занимает больше рабочего дня и требует искать связанные файлы по всему проекту. Если бизнес-логику нельзя протестировать без запуска экрана на эмуляторе, слои уже перемешаны.
Нужно ли останавливать текущее приложение в сторах на время миграции?
Нет, старая версия продолжает работать у пользователей, пока новая версия с обновлённой архитектурой проходит тестирование и модерацию в App Store и Google Play, а переход происходит через штатное обновление.
Как офлайн-кэш с данными контрагентов соотносится с 152-ФЗ?
Если в кэше хранятся ФИО, телефоны или другие персональные данные контрагентов, локальное хранилище на устройстве нужно шифровать — это требование распространяется и на офлайн-копию данных, а не только на сервер.
Или позвоните: +7 906 045-28-27 — в рабочее время с 9:00 до 19:00
Остались вопросы? Нужна помощь?
Менеджеры компании с радостью ответят на ваши вопросы, произведут расчет стоимости услуг и подготовят индивидуальное коммерческое предложение.
Бесплатная консультация

