Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Атомарные SPA — Александр Китов, Альфа-Банк

AvitoTech
April 23, 2018

Атомарные SPA — Александр Китов, Альфа-Банк

AvitoTech

April 23, 2018
Tweet

More Decks by AvitoTech

Other Decks in Programming

Transcript

  1. Проблемы монолитных приложений • Сложно делать в параллель • Сложно

    тестировать • Большая вероятность что-то сломать • Единая точка отказа • Сложно релизить !3
  2. Что вообще это такое? • Небольшие, независимые приложения • Имеют

    собственное состояние, общаются с собственным API • Могут деплоиться/тестироваться независимо • Отказ одного не влияет на другие • С точки зрения пользователя выглядят как единое целое. Единый ux, сквозная общая навигация !6
  3. Встраиваемые приложения • iframe • WebComponents • Blackbox React Component

    • Специальные библиотеки типа single-spa • Свои велосипеды !10
  4. Как разделять? • Только одна доменная область. Платежи отдельно, тарифы

    отдельно • Объем кодовой базы • Необходимость распараллелить работу !14
  5. Общая конфигурация const struct = [ { title: 'Выписка', url:

    'eco/listing', alfaMetricsCode: 'Listing_btn_Menu', featureCode: 'EcoDashboard', isDisabledForBlockedOrganization: false, isNewTab: false }, { title: 'Сервисы', isNewTab: false, alfaMetricsCode: 'Services_btn_Expand', items: [ { title: 'Кредиты', url: 'external/ufr-credit-products', alfaMetricsCode: 'UfrCreditProducts_btn_Menu', featureCode: 'UfrCreditProducts', isDisabledForBlockedOrganization: true, isNewTab: false } ] } ]; !24
  6. Что делать? { "jsFiles": [ "//link.alfabank.ru/shared/main.07fed3df.js" ], "cssFiles": [ "//link.alfabank.ru/shared/main.07fed3df.css"

    ], "version": "0.1.15", "struct": [ ... // Описание структуры меню ] } /shared/getSharedResources !26
  7. Что делать? async function pageLoading() { ... const { jsFiles,

    cssFiles } = await services.getSharedResources(); return indexTemplate({ js: webpackAssets.js.concat(jsFiles), css: webpackAssets.css.concat(cssFiles), ... }); } !27
  8. Server-side render import vm from 'vm'; const source = await

    request('http://alfabank.ru/shared.js'); const sandbox = { react: require('react'), reactDOM: require('react-dom'), __CorporateAppHeader: null }; vm.createContext(sandbox); vm.runInContext(source, sandbox); !30
  9. Graceful degradation export default class HeaderFallback extends React.Component { static

    headerComponent = global.__CorporateAppHeader || (() => <Spin />); render() { return React.createElement( HeaderFallback.headerComponent, this.props ); } } !32
  10. Еще чуть лучше export default class HeaderFallback extends React.Component {

    static headerComponent = global.__CorporateAppHeader; async componentDidMount() { if (HeaderFallback.headerComponent) { return; } const loaded = await import( 'arui-private/corporate-app-header' /* webpackChunkName: 'app-header' */ ); HeaderFallback.headerComponent = loaded.default; this.forceUpdate(); // force, because we don't actually change state } render() { return HeaderFallback.headerComponent ? React.createElement(HeaderFallback.headerComponent, this.props) : <Spin />; } } !33
  11. Как мониторить? • Следим за состоянием серверов • Следим за

    состоянием контейнеров • Следим за состоянием баз данных • Анализируем логи !36
  12. Сложноуловимые проблемы • Проблемы с сетью • Косяки в конфигурации

    сервис-дискавери • Расхождение контрактов фронта/API • ... !39
  13. Jest+puppeteer test('desktop version', async () => { await page.setViewport({ width:

    1280, height: 800 }); await page.goto(`https://link.alfabank.ru/dashboard/?token=${token}`); await page.screenshot({ path: 'screens/dash_desktop.png' }); const companySelector = await page.$('.corporate-app-header__profile'); expect(companySelector).not.toBeNull(); }); !41
  14. test runner export async function runTests(): Promise<TestsResults> { return new

    Promise(resolve => { const spawned = childProcess.spawn( 'npm', ['run', 'test'] ); spawned.on('close', async code => { const resultOutput = await readFile( './test-results.json', 'utf8' ); resolve({ code, resultOutput }); }); }); } setInterval(runTests, TIMEOUT) !42
  15. Мониторинг • Видим то же, что и пользователь • Не

    зависит от самих приложений • Можем проверять сложные сценарии • Быстро видим интеграционные проблемы • Можем посмотреть что у нас вообще в бою) !45
  16. Итоги !46 • Дублирование загружаемых на клиент данных • Более

    высокий порог вхождения • Усложнение инфраструктуры • Необходимость синхронизировать вроде как независимые команды • Просто разрабатывать отдельные приложения • Можно деплоить независимо • Больше надежность • Меньше вероятность сломать всё • Проще масштабировать + -