Как мы распилили монолит. Часть 2, Frame Manager / Хабр
Привет, меня зовут Стас, я работаю в команде Тинькофф Бизнеса. В прошлой статье мой коллега Ваня рассказал, как у нас устроена архитектура приложений. Несколько раз Ваня упомянул некий Frame Manager, который служит оркестратором приложений, и сейчас я расскажу про него более подробно.
Что такое Тинькофф Бизнес
Тинькофф Бизнес предлагает решения для малого и среднего бизнеса: зарплатный проект, расчетно-кассовое обслуживание, конструктор документов и еще порядка 20 других продуктов.
Все это реализовано в приложениях. Эти приложения разрабатываются отдельными командами и имеют свои релизные циклы. А еще все эти приложения работают с единой авторизацией, содержат общую часть бизнес-логики, вынесенную в отдельную библиотеку, и используют общие UI-компоненты.
Вернемся на 2 года назад
Типичное приложение Тинькофф Бизнеса выглядело примерно так:
Вверху — шапка с навигацией по приложению, а справа — сайдбар с навигацией по продуктам.
Тогда идея микрофронтенда еще не была такой популярной, но мы уже двигались в этом направлении: сайдбар представлял собой отдельное Angular-приложение. Основное приложение загружало сайдбар в iframe, что позволяло релизить приложения независимо.
Были у этого подхода и минусы: при переходе между продуктами приходилось ждать полной загрузки страницы с двумя Angular-приложениями. А из-за того, что большинство приложений используют одни и те же запросы к API бэкенда, пользователям приходилось ждать, пока они повторно отработают.
Идея Frame Manager
Мы жили с такой архитектурой, пока не появилась глобальная задача для всех приложений — редизайн. Тогда пришла идея: а почему бы не сделать своего рода инверсию контроля и вместо того, чтобы приложения загружали внутри себя сайдбар, сайдбар сам бы загружал приложения?
Это позволяло сохранить плюсы текущей архитектуры и избавляло от вышеназванных проблем (и приносило новые, ха-ха).
Начальный прототип
На начальном этапе мы создали прототип с минимальной функциональностью, необходимой для загрузки других приложений. На тестовом стенде был заведен отдельный домен. Поменялись роуты в nginx для статики приложений: раньше по путям /sme, /account, /salary и т. д. загружалась статика соответствующих приложений. Теперь же по всем путям отдавалась статика Frame Manager, а к роутам статики самих приложений добавился постфикс /static.
Чтобы стало понятнее, разберем пример: нужно загрузить приложение, находящееся на пути /some-app с каким-то роутом some-route. Отбросив детали, посмотрим, какой процесс происходит при загрузке /some-app/some-route/:
- Nginx по данному пути отдает статику Frame Manager.
- Frame Manager загружается. Основываясь на роуте, он понимает, что нужно загрузить приложение some-app.
- Создается iframe с src=‘/some-app/static/‘, в котором загружается основное приложение.

В самих приложениях при этом понадобились существенные доработки. Поэтому мы форкнули master ветки приложений и добавили туда необходимые изменения, после чего подняли отдельные экземпляры самих приложений с внесенными изменениями.
Первые проблемы
Так мы перевели 4 приложения во Frame Manager и убедились, что решение рабочее. Предстоял перевод всех остальных приложений. И тут мы столкнулись с проблемой: одновременно поддерживать обычную версию и версию для работы с Frame Manager оказалось слишком дорого.
Нам приходилось постоянно обновлять новые версии приложений на каждое изменение master’a старых версий, разрешать появляющиеся конфликты, часто ломалась уже существующая функциональность, затраты на регресс-тестирование увеличились почти вдвое — все это отнимало слишком много времени. Было понятно, что нужно новое решение.
Улучшения
Если бы одна версия приложения могла работать и с сайдбаром, и с Frame Manager, это избавило бы нас от многих проблем.
Давайте посмотрим, что можно сделать.Прежде всего нужно как-то определять, во Frame Manager ли запущено приложение. Сделать это довольно просто: нужно сравнить ссылки window.top и window.self. Если они окажутся не равны — значит, мы во фрейме, то есть во Frame Manager! Но, если есть приложения, которые по умолчанию открываются в iframe, нужно добавить дополнительную логику. Так, у нас было приложение-виджет, которое изначально открывалось во фрейме и стало считать, что оно всегда находится во Frame Manager’e, из-за чего ломалось в старом режиме.
Теперь рассмотрим подробнее, какие изменения необходимы в приложениях и как можно поддерживать работу в двух режимах:
- Синхронизация url. Так как приложение загружается внутри iframe, оно работает в отдельном изолированном контексте и переходы по роутам никак не отображаются в адресной строке браузера. Кроме того, при переходе по прямой ссылке на какой-то роут приложение будет считать, что текущий роут — это корень. Чтобы синхронизировать состояние url’а приложения и Frame Manager, нужен отдельный сервис.

В случае с загрузкой в старом режиме мы просто игнорируем данную логику. - Сервис для обмена данными. Сервис нужен для обмена данными между Frame Manager’ом и приложениями. Один из кейсов использования: шаринг данных между приложениями. Этот сервис у нас уже был и использовался для совместной работы сайдбара и приложений. В любом случае, реализуется это не сложно, есть много вариантов, у нас логика основана на post messages и custom events. Понадобились лишь небольшие доработки на стороне Frame Manager.
- Замена стилей. Так как изначально стояла задача редизайна, нужно заменить стили при загрузке во Frame Manager. Решается несложно, в Angular есть много способов для этого.
- Замена конфигов. Адреса эндпоинтов и другие переменные, необходимые для работы приложений, хранятся в глобальном объекте TCS, который определяется в отдельном скрипте config.js до инициализации приложения. В случае загрузки с Frame Manager некоторые переменные нужно переопределять.
- Замена base href. Так как изменились роуты в nginx, нужно было поменять base href для корректной загрузки скриптов и статики (добавить постфикс /static/). Кейс оказался не из легких: дело в том, что base href учитывается только первый раз при загрузке страницы, то есть в рантайме Ангуляра его не подменить. Как вариант, можно написать скрипт, который смотрит, в каком окружении запущено приложение, и подставляет соответствующий base href, и добавить его в каждое приложение в самое начало страницы.
- Авторизация. Для авторизации во всех приложениях используется отдельный скрипт, встраиваемый в index.html. В новом варианте этот скрипт встраивается во Frame Manager, и его повторное использование в приложениях будет приводить к ошибкам. Можно внести изменение в логику скрипта, чтобы она игнорировалась, если приложение загружено внутри Frame Manager.
Все это рабочие решения, но в них нет достаточной гибкости.
Добавились новые ветки с логикой, которую также нужно поддерживать в разных местах. Да и в целом все выглядит переусложненной и достаточно неустойчивой конструкцией.
Переизобретаем работу с iframe
Тогда появилась идея немного хакнуть процесс загрузки index.html приложения. Вместо того чтобы загружать приложение в iframe, указывая атрибут src, можно сделать xhr-запрос за index.html, получить страницу в текстовом виде, обработать ее и загрузить в iframe. Это даст полный контроль над загружаемым приложением: позволит определять base href, удалять ненужные скрипты, патчить стили, переопределять переменные и многое другое!
Да, mokey patching не приветствуется среди разработчиков и считается плохой практикой, но если уж команда Angular его использует в библиотеке zone.js, чем мы хуже? Могут возникнуть сомнения насчет производительности: парсинг html выглядит дорогой операцией. Но, как правило, начальная страница Angular-приложения не превышает 50 строк, а во всех браузерах (даже в IE 10!) есть удобный api DOMParser, позволяющий из строки получить DOM.
Давайте посмотрим, что делает Frame Manager в процессе загрузки приложения (сам Frame Manager уже загружен):
- Основываясь на пути, загружает index.html приложения.
- Парсит страницу, преобразуя ее в DOM, в памяти удаляет ненужные скрипты, подменяет base href, глобальные переменные с конфигами и стили.
- Создает iframe-элемент, куда записывает полученный документ (преобразованный обратно в строку) с помощью document.write().
- Прокидывает приложению роут, на который оно должно снавигироваться. Также прокидывает модели, необходимые для работы бизнес-логики, через сервис для обмена данными.
Таким образом, из вышеперечисленных шести необходимых изменений в логике только первое (синхронизация url) нужно реализовывать внутри приложения, все остальное берет на себя Frame Manager!
Что получили
Полностью изменили внешний вид приложения, практически не внося изменений в код самого приложения.
До. Сайдбар обведен красным. Встраивается в iframe
После. Красным обведен Frame Manager. В iframe загружено приложение
Получили возможность переопределять или добавлять глобальные переменные и стили.
Например, так выглядит конфиг стилей для приложения
export const business = {
'sidebar.b-main__sidebar': {
display: 'none'
},
'.b-main': {
'margin-left': '260',
position: 'relative',
display: 'block',
width: '1104px',
'min-height': '100vh',
margin: '0 auto'
}
};
А так — конфиг самого приложения
{
id: 'products',
name: 'Все продукты',
icon: 'products',
frameSupported: true,
applications: [
{
id: 'products',
path: '/products',
apiPrefix: '/products',
hasMenuConfig: true,
dynamicCompanyChange: true,
}
]
}
При этом конфиги лежат в репозитории, отдельном от Frame Manager, что позволяет менять некоторые параметры работы приложений безрелизно.
Также создали бесшовные переходы между приложениями, вынесли авторизацию во Frame Manager. Добились того, что благодаря шарингу данных между Frame Manager и приложениями не делаются лишние запросы.
Не обошлось и без проблем: некоторые chrome-плагины (КриптоПро, redux devtools) перестали работать в загружаемом приложении, так как при взаимодействии терялась ссылка на window. Понадобились дополнительные доработки.
В итоге в конце 2019 года мы успешно перевели все приложения на Frame Manager, а сайдбар канул в Лету. Но работа над Frame Manager продолжалась, и возник новый вопрос: можно ли как-то еще улучшить и оптимизировать работу фронтенда в Тинькофф Бизнесе? Оказалось, что можно! Но об этом — в следующей статье.
A-Frame
Мы создаем бренды, которые усиливают…
Мы здесь. Мы это ты.
Наши бренды и продукты предназначены в первую очередь для
решения проблем
Для тех, кто больше всего в них нуждается. Мы уделяем время тому, чтобы все, что мы строим, соответствовало нашему Сообществу, нашей миссии и нашим убеждениям.
Мы ставим People First
и руководствуемся эмпатией. Мы переосмысливаем то, как велся бизнес. Мы стремимся делать добро с
Лучшие практики
и
Удивительные люди.
Мы сторонники преобразования бизнеса. Мы наше сообщество, наши клиенты и наши партнеры. Мы — группа лидеров, мыслителей и строителей, которые увлечены переосмыслением того, чего мы можем достичь вместе. Мы
Ванесса Мотли-Коулман
Старший вице-президент по маркетингу, KINLO
Аванта Араччи
Главный операционный директор, A-Frame Brands
Ари Блум
Основатель и генеральный директор, A-Frame Brands
Eliana Alcantar
Менеджер по культуре и рекрутингу, A-Frame Brands
Martin Ekechukwu
Главный директор A-Frame Brands
Shena Clarke
VP Creative, A-Frame Brands
Roma Hassan
VP VP, A-Frame Brands
Roma Hassan 9000
VP VP VP, A-Frame Brands
Roma Hassan
VP VP, A-Frame Brands
Roma Hassan 9000
VP VP.
, Operations, A-Frame Brands
Kia Lowe
Президент по уходу за кожей John Legend
Миа Мичем
Президент, KINLÒ
Пэм Чоланкерил
Президент, PROUDLY
Caitlin Victor
Manager Ecommerce, Kinlò
Lindsay Mulsow
Старший менеджер по цифровому дизайну, A-Frame Brands
Jillian Beale
Координатор A-Frame Brands
Nellie Tovar
Seniortiste Associate, As-Frame Brands
Tovar Tovar
Associate, A-Frame Brands
Tovar
Associate, A-Frame Brands
Tovar
Associate, A-Frame Brands
Tovar
. Brands
Christina Rodriguez
Финансовый директор, A-Frame Brands
Анна Япор
Руководитель производственного проекта, A-Frame Brands
Майкл Эвинс
Старший дизайнер, A-Frame Brands
Сара Альварадо
Директор по разработке продукции по уходу за кожей John Legend
Амаль Мгареш
Старший менеджер, контролер, A-Frame Brands
Сарин Ласкар
Финансовый партнер, A-Frame Brands 20 0 Ditail 90 90 Sweat 90 20 Ditail или 9000 Менеджер, KINLÒ
Дженнифер Бетколия
Директор по бренд-маркетингу, PROUDLY
Дежа Брэггс
Сотрудник по социальным сетям, PROUDLY
Пейсли Симмонс
Сотрудник по контенту и копирайтингу, PROUDLY
Лорен Гудвин
Директор по электронной коммерции и цифровому маркетингу, PROUDLY
Имельда Лопес
Ассоциированный специалист по цифровому маркетингу, PROUDLY
Питер Кпере-Дайбо
Старший менеджер по разработке продуктов, PROUDLY
2 Маркетинг, уход за кожей John Legend
Эллен Ли
Старший менеджер по креативным услугам, A-Frame Brands
Д-р Наана Боакье
Медицинский директор
Это какой-то текст внутри блока div.
Это какой-то текст внутри блока div.
Это какой-то текст внутри блока div.
Это какой-то текст внутри блока div.
Vanessa Motley-Coleman
SVP Marketing, Kinlo
Avantha Arachchi
COO, A-Frame Brands
Ari Bloom
Основатель и генеральный директор A-FRAME
Eliana Alcantar
Culta -Бренды рамок
Martin Ekechukwu
Главный директор Brand, A-Frame Brands
Shena Clarke
Креативный директор VP, A-Frame Brands
Roma Hassan
VP, операции, бренды A-Frame
Kia Lowe
, Операции, бренды A-Frame
Kia Lowe
, Операции, бренды A-Frame
Kia Lowe
, Операции, Бренды A-Frame
Kia Lowe
. Средства по уходу за кожей John Legend
Миа Мичем
Президент, KINLÒ
Пэм Чоланкерил
Президент, PROUDLY
Кейтлин Виктор
Менеджер по электронной коммерции, KINLÒ
9 Линдсей0005
Старший менеджер по цифровому дизайну, A-Frame Brands
Джиллиан Бил
Координатор по персоналу, A-Frame Brands
Нелли Товар
Старший помощник по логистике, A-Frame Brands
Кристина Родригес5 Финансовый директор, A-Frame5
Кристина Родригес5 Финансовый директор,
Brands
Анна Япор
Руководитель производственного проекта, A-Frame Brands
Майкл Эвинс
Старший дизайнер, A-Frame Brands
Сара Альварадо
Директор по разработке продуктов, уход за кожей John Legend
Amal Mgaresh
Старший менеджер, контроллер, A-Frame Brands
Sarin Laskar
Finance Associate, A-Frame Brands
Dior Sweeney
Retail Manager, Brandlò
Jennifer Betkolia
, Brandlò
Jennifer Betkolia
, Brandlò
Jennifer Betkolia
, Brandlò.
Дежа Брэггс
Сотрудник по социальным сетям, PROUDLY
Пейсли Симмонс
Сотрудник по контенту и копирайтингу, PROUDLY
Лорен Гудвин
Директор по электронной коммерции и цифровому маркетингу, PROUDLY
Имельда Лопес
Специалист по цифровому маркетингу, PROUDLY
Питер Кпере-Дайбо
Старший менеджер по разработке продуктов, PROUDLY
Эшли Картер
Директор по электронной коммерции и цифровому маркетингу, уход за кожей John Legend 020 Lee Legend
El 900 Менеджер по обслуживанию, A-Frame Brands
Доктор Наана Боакье
Медицинский директор
Знакомьтесь с нашим советом директоров
Hill Harper
Соучредитель
Daria Burke
Alda Leu Dennis
Initialized Capital
Moise Emquies
Bob Fisher
Board Observer
Eurie Kim
Forerunner Ventures
Bryan Olson
Columbia Care
Hill Harper
Co-Founder
Дарья Берк
Алда Леу Деннис
Инициализированный капитал
Мойз Эмкиес
Боб Фишер
Наблюдатель Совета
Юри Ким
Forerunner Ventures
Брайан Олсон
Columbia Care
См.
наш совет
Основой нашей работы являются
людей и создание
возможностей увидеть себя в брендах, которые мы создаем. Мы не отворачиваемся
, мы копаем. Мы
здесь, чтобы изменить то, как бизнес и коммерция
влияют на сообщества .Последние новости
The Hollywood Reporter
Inside A-Frame, Hill Harper и Ari Bloom’s Incubator для звездных брендов
Глянцевая
Ари Блум, A-Frame Brands | Glossy 50 2022
Fast Company
Этот главный операционный директор надеется на видимость Trans в бизнесе
Retail Brew
Генеральный директор A-Frame Brands Ари Блум о важности физического рынка и о надвигающейся рецессии изменение его.

Fast Company
Объявление списка Queer 50 2022
Мы здесь.
Мы слушаем.
Legal
CAM Frame Manager
Менеджер кадров CAM
Взаимодействие с CAM Frame Manager
Установите зазоры для рамки настройки по умолчанию
Вставка альтернативных рамок
Вставьте папку с рамкой
Переименовать альтернативные кадры
Удалить альтернативные кадры
CAM-менеджер > Рамки >
Фреймы используются настройкой в качестве базовой плоскости для операций траектории инструмента. Они определяют зазоры инструмента и значения подвода/отвода относительно исходной точки оси Z настройки. Это называется кадром установки по умолчанию.
Локальные альтернативные кадры также могут быть введены с использованием формы Альтернативные кадры (см.
Вставка альтернативных кадров ниже). Эти альтернативные кадры переопределяют кадр настройки по умолчанию и могут быть выбраны для отдельных операций траектории инструмента. Альтернативные кадры (если определены) расположены под Кадры в дереве CAM Plan Manager.
Значения зазоров для кадра настройки по умолчанию определяются параметром Зазоры , расположенным в разделе Настройка в дереве менеджера. См. рисунок ниже.
CAM Plan Manager используется для взаимодействия с Frame Manager с использованием стандартных методов Object Editing . Щелкните правой кнопкой мыши Frames в дереве менеджера и выберите либо Вставить или Удалить все из всплывающего меню. Оба варианта обсуждаются на этой странице.
CAM-менеджер > Распродажа >
Каждая установка содержит три кадра по умолчанию.
Это плоскости XY, XZ и YZ из исходной точки установки. Плоскость XY установлена как рамка по умолчанию. Зазорные плоскости вдоль оси Z по умолчанию отображаются в виде двухосевых координатных фреймов. См. рисунок ниже.
Цвета, используемые для кадров настройки по умолчанию: зеленый для 0, красный для зазора, синий для отвода, светло-пурпурный для приближения и белый для альтернативных кадров. Эти цвета также используются для соответствующих режимов подачи в траекториях инструмента. Каждый кадр помечен своей высотой.
Вы можете установить зазоры для рамки настройки по умолчанию, выбрав Зазоры в дереве менеджера. Введите нужные значения в предоставленную форму.
Зазор [Setup1]
Очистить Z
Подход Z
Втянуть Z
Автоочистка
CAM-менеджер > Рамки > > Вставить рамку
Во время определения траектории движения инструмента можно создавать альтернативные установочные кадры и ссылаться на них.
Используя форму Alternate Frames Form , вы можете создать базовую плоскость и присвоить ей атрибуты CAM-рамы. Затем он становится альтернативным кадром.
Вы можете дать альтернативному фрейму имя, указать значения плоскости зазора и указать, следует ли записывать исходную точку фрейма во время вывода. В графическом окне имя альтернативного кадра отображается в его исходной точке, а также указываются значения его безопасной плоскости. Все альтернативные кадры белые.
После создания альтернативные кадры перечислены в разделе Кадры в дереве CAM Plan Manager . Вы можете щелкнуть правой кнопкой мыши кадр в диспетчере и выбрать из всплывающего меню параметров. 9Доступны 0401 Редактировать , Переименовать и Удалить . Редактировать отобразит форму Альтернативные кадры , заполненную значениями выбранного кадра.
Имя
Указывает имя альтернативного кадра.Это имя появляется в дереве менеджера и отображается рядом с исходной точкой кадра в графическом окне.
Прозрачный Z
Определяет расстояние зазора инструмента, измеренное от начала оси Z альтернативного кадра.Подвод Z
Задайте расстояние подхода инструмента, измеряемое от начала оси Z альтернативного кадра.Retract Z
Определяет расстояние отвода инструмента, измеренное от начала оси Z альтернативного кадра. Это свойство игнорируется, если установлен флажок Auto Clear (см. ниже).Головка
Здесь перечислены головные вложения, определенные в файле « HeadAttachments ». Если один из них выбран, он будет использоваться при выводе для всех операций, созданных в этом кадре. Дополнительную информацию см. в разделе «Насадки для головок для 5-осевых CAM-операций» .Автоочистка
Если этот параметр включен (т.е. отмечен), зазор отвода инструмента определяется заданным значением расстояния, измеренным от геометрии компонента (не от геометрии заготовки). Если над геометрией компонента есть припуск, введите значение расстояния, которое также обеспечит надлежащий зазор над припуском. Когда отключено, зазор отвода инструмента определяется Отвести значение Z , описанное выше.
Fixture Offset / Offset Register
Если этот флажок установлен, выбранный регистр смещения применяется ко всем компонентам прибора. Справочная информация: Станки имеют возможность устанавливать несколько систем координат. Это делается с помощью Fixture Offsets. Оператор станка устанавливает смещение приспособления , измеряя расстояние по каждой оси от исходного положения станка до положения обрабатываемой детали. Код ЧПУ, управляющий станком, должен вызывать это Fixture Offset зарегистрируйте, чтобы активировать его. Также см. CAM Machine Manager для связанного поля « Offset Registers ».Fixture Offset
При активации необходимо назначить Fixture Offset кадру . Установленное здесь значение будет выведено в файл CL (Расположение резака), чтобы постпроцессор преобразовал его в код ЧПУ.Смещение регистра
Вы можете вручную ввести значение в поле или нажать кнопку Регистр смещения , чтобы выбрать либо Авто , либо ранее определенное значение. По умолчанию выбрано Авто .Записать ORIGIN в выходной файл
Если этот параметр включен (т. е. отмечен), оператор ORIGIN записывается в выходной файл. Если для фрейма отмечена опция ORIGIN, его имя будет отображаться в графическом окне в квадратных скобках (например, [Frame 1]).Create Datum
Используйте этот параметр, чтобы создать новую базу для альтернативного кадра.Будет выполнена команда Вставить базовую плоскость . Это та же самая команда, которая используется в Part Level . Когда базовая плоскость создана, она становится альтернативной рамой с атрибутами, присвоенными ей формой альтернативной рамы .
Select Datum
Используйте этот параметр, чтобы выбрать существующую базовую плоскость для использования в качестве альтернативного кадра.
Создать папку под фреймами и использовать ее для управления всеми созданными фреймами. Нажмите и удерживайте левую кнопку мыши на выбранных кадрах и перетащите их прямо в папку.
Вы можете переименовать альтернативный кадр, щелкнув его правой кнопкой мыши в дереве CAM Plan Manager. Выберите Переименовать во всплывающем меню и введите новое имя. Имя обновится в дереве менеджера и в графическом окне рядом с исходной точкой фрейма.

Это имя появляется в дереве менеджера и отображается рядом с исходной точкой кадра в графическом окне.
е. отмечен), зазор отвода инструмента определяется заданным значением расстояния, измеренным от геометрии компонента (не от геометрии заготовки). Если над геометрией компонента есть припуск, введите значение расстояния, которое также обеспечит надлежащий зазор над припуском. Когда отключено, зазор отвода инструмента определяется Отвести значение Z , описанное выше.
Будет выполнена команда Вставить базовую плоскость . Это та же самая команда, которая используется в Part Level . Когда базовая плоскость создана, она становится альтернативной рамой с атрибутами, присвоенными ей формой альтернативной рамы .