新しいフロントエンドTinkoff.ruの開発方法

Tinkoff.ru







今年の4月に、tinkoff.ruを再起動しました。 銀行は金融スーパーマーケットになりました。 現在、銀行のクライアントだけでなく、すべての訪問者がモバイルの料金を支払い、税金をチェックし、住宅ローンを手配します-すべて1つのプラットフォームで。 この記事では、開発の年に私たちが訪れた経験と技術的解決策を共有します。







フロントエンド用のスタックは良好に機能しました。 次に、アーキテクチャの概念の一部として、問題を解決し、新しい要件に適応します。







1年にわたって、3,000のReactコンポーネントからなる350の独立したインターフェイスユニットを開発しました。 tinkoff.ruには月間700万人のユーザーがアクセスし、訪問者の数は常に増加しているため、ページの読み込みを最適化しました。 フロントエンドは30人を開発しており、才能のある開発者を常に探しています。







以前のインターネットバンク、ポータル、ウォレットの機能を組み合わせました。 したがって、最初に元のスタックについて説明し、次に現在のスタックに到達した方法を説明します。







以前のスタックの概要



ポータルおよびインターネットバンキング2011



オランダの会社の商用ソリューションに基づいて、内部リソースを備えた最初のバージョンを開発しました。 バックエンドは、重いJava / Springアプリケーションによって強化されました。 前面では、柔軟性と詳細なドキュメントの不足により、jQuery、Backbone、Handlebarsのスタックが形成されました。







メイヴンは前部と後部を収集しました。 Mavenはクライアントパッケージのビルドに適していないため、壊滅的な数のフロントプラグインがありました。 これにより、私たちは停滞しました。 幸いなことに、Gruntを使用してクライアントアセンブリをサーバーアセンブリから分離する方法を見つけました。







サーバーでテンプレートを使用し、クライアントで独自のロジックとアーキテクチャを持つ無関係のテンプレートを使用することは、標準と考えられていました。 サーバーUIとクライアントUIの2つのUIレイヤーをサポートする必要がありました。 大きなRIAがある場合-さまざまなプログラミング言語で記述された多くのロジックが複製されます。 例:ページルーティング、データ取得ロジック、または同じマークアップを持つパターン。







2013年の終わりに、Webアプリケーションを作成する同形アプローチが開発され始めました。 そして、サーバーとクライアントでテンプレートを複製する決定は、概念的に間違っていると見なされ始めました。







ウォレット2014



このプロジェクトは、2つの理由で興味深いものです。







  1. Tinkoff Mobile Walletは、銀行の顧客だけでなく、誰もが使用した最初のアプリケーションです。
  2. MVCアーキテクチャに基づいた同型アプローチを試みました。 出発点-Airbnbからの記事


スタックは、インターネットバンキングに似ていました:Node.js上のサーバーであるBackboneとHandlebars。 ビューの一部がサーバーにレンダリングされました。 アプリケーションは問題を解決し、1つのUIレイヤーさえも取得しました。 しかし、大規模なアプリケーションでは、このようなアーキテクチャが複雑さをもたらすことが明らかになりました。 ブラウザのデータモデルの強化に問題がありました。 サーバー側とクライアント側に別々のコントローラーを作成する必要がありました。







次のプロジェクトは、異なるパラダイムで開発されました。







オンラインバンキング2015



インターネットバンクは外部サイトから分離されており、単一ページアプリケーションでした。 オンラインバンキングにAngular.jsフレームワークを使用しました。 その結果、最新のインターネットバンキングインターフェイスが得られました。







2015年、ビジネスは開発戦略を変更し、Webアプリケーションの新しい要件を導入しました。 私たちはしなければなりませんでした:









新しいインターネットバンクには、クライアントのみにUIレイヤーがありました。 検索ロボットは、そのようなアプリケーションのインデックスを作成する方法をまだ学習していません。 そして、これがいつ起こるかは明確ではありません。 サーバー層の放棄に失敗しました。 既存のスタックを開発するいくつかの方法を見ました。







  1. 古いポータルと新しいオンラインバンキングを組み合わせます。 ポータルはサーバーUIレイヤーとして機能し、Angular.jsはクライアントとして機能します。 このオプションでは、根本的な問題は解決されません。
  2. JavaアプリケーションをNode.jsアプリケーションに置き換えます。 これにより、サポートを簡素化できますが、2つのUIレイヤーが残っていました。
  3. Javaを削除し、Angular.jsのみを残します。 そして、ヘッドレスブラウザーPhantom.jsでデプロイされたサーバーを使用してSPAをレンダリングします。 このようなスキームはデバッグが難しいため、このオプションは多数のページには適していません。


既存のスタックの開発経路を分析した結果、問題が解決されないことがわかりました。 その結果、彼らは根本的に異なるアプローチを選択しました。







プラットフォーム2016



Tinkoff.ruで利用できるようになったものをプラットフォームと呼びます。







このシステムの基礎として、2014年にFacebookのエンジニアが提案したFluxアーキテクチャを選択しました。 FluxはMV *とは異なり、同方向のパラダイムにより簡単に当てはまる多方向データストリームを持たないため、アプリケーションのデバッグを高速化できます。 Fluxアーキテクチャは、 CQRSデータベースモデルに基づいています。







単一のUIレイヤーを持つ同型アプリケーションのアイデアを実装しました。 テンプレートエンジンとして、仮想DOMサポートを備えたReact.jsライブラリが選択されました。 サーバー上で簡単にレンダリングされるテンプレートのおかげです。







現在のスタックは、SEOとSMMの問題を解決します。 Cookieの操作などの環境固有のコードを除き、ブラウザーとサーバーの間でコードを再利用します。 1つの開発者グループがすべてのタスクを解決できるため、作業が高速化されます。 1つのフレームワーク/ベンダーに依存しません。 アプリケーションは、小さな独立したモジュールから構築された一連のルールによって結合されます。 より適切な実装がある場合は、モジュールを交換できます。







ユニバーサルアプリケーション



融通性



Fluxの実装として、彼らはYahooのエンジニアからFluxibleフレームワークを選択しました 。 この実装は同形レンダリングに焦点を当てています。 選択したソリューションは、当社の要件を完全に満たしています。







アプリケーションを大きな依存関係にバインドしないようにするため、セットの2つのライブラリのみを使用します。







  1. ルーター -ページルーティング。 ライブラリは、エクスプレスのようなパスをサポートしています。 同形かつ高速です。現在、2000ページをローミングしています。
  2. Dispatchr-フラックスディスパッチャー。


階層化



アプリケーションアーキテクチャ







画像







サービス ブラウザまたはHTTP APIへのアクセス、外部システムとの相互作用。 ビジネスロジックの一部が含まれています。 サービスにはいくつかの実装があります:共有と同形、node.jsのサーバー、ブラウザーのクライアント。 結果をキャッシュできます。







アクション フラックスアクションクリエーターには、UIおよびビジネスロジックの一部が含まれています。 サービスにアクセスできます。







店舗。 UIロジックを含むデータモデル。







コンポーネント。 ストーリーのデータをHTMLでレンダリングします。







プログレッシブダウンロード



サーバーレンダーのおかげで、プログレッシブロードの効果とグラスまでの時間を短縮できます。 平均的なユーザーは、サイトのリクエストから600ミリ秒後に作業ページを見ます。 数秒後、スピーカーが初期化され、個人データが読み込まれます。







画像







サーバー上のすべてのデータをレンダリングでき、パーツをレンダリングできます。 また、サーバー部分を完全に無効にして、アプリケーションをSPAとして使用できます。 サーバーの負荷を軽減するために、すべてのユーザーの一般的なデータのみをレンダリングし、ブラウザーで個人データを操作します。







画像







コード例



サーバーで実行するもの、またはユーザーが特定のロールで実行できるようにするものは、アクションを作成する機能のレベルで定義します。







import { ACCOUNT_LIST } from '../actions';
import { CLIENT } from '../roles';

accountList.isServer = true; //        
accountList.requiredRoles = [CLIENT]; //     

function accountList(context) {
    return context.service('account/list') //             .    .
        .then(payload => context.dispatch(ACCOUNT_LIST, payload)); //      
}

export default accountList;
      
      





. , .









. , . :







image







.









import { LogoPure } from './LogoPure.jsx';

const UILogo = connect(
    ['config', 'brands'],
    ({
        brands,
        config: { brandsBasePath }
    }) => ({
        brands,
        brandsBasePath
    })
)(LogoPure);

export default UILogo;
      
      





connect ( redux), . – , . – , .







Higher-order Components



, — . , React.createClass.







. , . Mixins Are Dead. Long Live Composition.









: . .









– render. pure-render. render shouldComponentUpdate, (props state).







, . , , . pure-render . render , react-perf. :







image







, render-logger. , render:







image







- , onClick. bind render , render . - pure-render .







bind render, Eslint eslint-plugin-react jsx-no-bind.







Batched updates



React runtime. . , . .









, , . .







Tinkoff.ru , .







image image







JS. . , .







, . , .









React . , .







  1. ES6 Class, React.createClass ( - autobinding) NODE_ENV=production, . 4 .
  2. React. . +2% ( )
  3. Babel. :

    1. transform-react-constant-elements
    2. transform-react-inline-elements createElement . +10%
  4. stateless . 45%.
  5. React-dom-stream renderToString , (TTFB) 3-5. (TTLB) 55%.

    React 15. , React: https://github.com/aickin/react-dom-stream/issues/18 , , .


. HTML, .









:







  1. Nginx .
  2. Express-cache-on-deamand .
  3. Lru-cache .


lru-cache . TTL , . – . , . , .







, :







image









CI Teamcity. . Webpack. .







tar . Babel , – Babel .







– , .

Babel , .

. , Babel .







, – Webpack. , .

, . .







application runner PM2. PM2 .







  1. pm2 startOrGracefulReload processes.json, .

    processes.json:

    {
    "name": "portal",
    "script": "server/index.js",
    "instances": -1
    }
          
          



  2. , . Node.js . – Nginx. Nginx . PM2 . NODE_APP_INSTANCE: PORT: process.env.PORT + process.env.NODE_APP_INSTANCE


image









- , . React.js -. DOM - . Flux . Node.js .







, , , . , , . React.js, Flux Dream Team.







best-talents@tinkoff.ru.







:







image







image







!







PS: -, , FinTech. .








All Articles