最初は、タスクは非常に線形に見えました。ここを見て、そこから優先順位に従って何かを受け取り、それを渡します。 しかし、その過程で、一部のタグは非同期に表示される可能性があるため、「待機」できる必要があります。
問題の複雑さにより、そのソリューションに含まれるコードを簡素化することが望まれました。
この投稿では、例としてこの問題の解決策を使用して、設計
タスク条件
探しているタグはUTMタグです。
タグのソースは、タグを探す場所です。 慣例により、それらには検索の優先順位があります。 このタスクでは、ソースは次のとおりです。
- GETリクエストパラメータ
- クッキー
- タイプdocument.referrerのHTTP要求ヘッダー。
ラベルを読み取るためのアルゴリズムは、ソースの優先度に依存し、最初は次のようになります。
解決策
開発されたアプリケーションでは、 依存性注入パターンが使用されるため、一部の予約を含むアプリケーションコンポーネントはサービスとして表示されます。 以下は、問題の解決に参加します。
- Cookieリポジトリ
- HTTP要求データリポジトリ(GETパラメーター、document.location.pathnameなど);
- そして、直接、タグを受け取るサービス。
それらをそれぞれcookies 、 query、およびutmと呼びます。
Cookieとクエリの機能が十分に明確な場合、utmはどうですか? ラベルを取得するためのアルゴリズムをutmまたはabstract内で直接実装し、アルゴリズムの実装をサービス外に実装することは価値がありますか?
次の場合、アルゴリズムを大幅に簡素化できます。
- 単一のインターフェースを持つ抽象データソースの概念を導入します。
- タグを必須とオプションに分けます。
したがって、ソースはCookieとクエリサービスである必要があります。
しかし、CookieゲッターにCookie値getCookieがあり、クエリgetterパラメーターがgetQueryParameterである場合はどうでしょうか。
つまり、 アダプターパターンを使用する必要があります。
その結果、次のラッパーサービスが表示されます。
- cookies-utm-adapter-検索を実行し、必要に応じて、Cookieに保存されているラベルをデコードします。
- query-utm-adapter-GETパラメーターで検索を実行します。
- query-utm-adapter-backside-HTTPリクエストの間接属性に基づいて検索を実行します。
utmサービスには、このソースのラベルソースインターフェイスと優先度を持つオブジェクトを取り込むaddSourceメソッドがあります。 また、サービス設計者は、サービスのデフォルト設定を拡張するjavascriptオブジェクトを受け入れます。
この図は、utmサービスとCookieリポジトリとの接続を示しています。
サービス設定では、これはすべて次のようになります。
cookies: path: '/src/service/cookies/cookies.js' query: path: '/src/service/query/query.js' cookies-utm-adapter: path: '/src/service/utm/cookies-utm-adapter.js' deps: calls: [['setCookieService', ['@cookies']] query-utm-adapter: path: '/src/service/utm/query-utm-adapter.js' deps: calls: [['setQueryService', ['@query']] query-utm-adapter-backside: path: 'src/service/utm/query-utm-adapter-backside.js' deps: calls: [['setQueryService', ['@query']] utm: path: 'src/service/utm/utm.js' deps: args: [ parameters: [ name: 'utm_source' required: true , name: 'utm_content' required: false , name: 'utm_term' required: false ] ] calls: [ ['addSource', ['@cookies-utm-adapter', 0]], ['addSource', ['@query-utm-adapter', 1]], ['addSource', ['@query-utm-adapter-backside', 2]] ]
*この例では、設定はcoffeescriptで表示され、@文字はサービスインスタンスへのリンクを意味します。 同様の設定形式がSymfony Dependency Injectionコンポーネントで使用されます。
このすべてを実装してコーディングしたと想像してください。 これですべてが動作しますが、同期して動作します。 いくつかのマークの「期待」をどうするか?
Async.js + jQuery.Deferred
実装に関するいくつかの言葉。
選択した構造ソリューションには、2つの論理レベルがあります。
- utmサービス内のソースをポーリングするロジック。
- アダプタロジックは、埋め込みリポジトリへの単純な呼び出しから、ラベルデータを取得およびフォーマットする最も洗練された方法まで、非常に異なる場合があります。
非同期ソリューションを実装するには、少なくとも最初のレベルで変更を加える必要があります。
utmサービスレベルで、ソース調査サイクルの実装を変更します。
- コレクションの基本的なメソッドを非同期スタイルで実装するasync.jsライブラリを使用して、ループを非同期にします。
- getメソッドの呼び出しに応答して、アダプターはラベル値またはその値の約束(約束)を期待します-アダプターがそれを待つか、どこかで要求する必要がある場合。 結果の処理は$ .whenメソッドにラップされ、正常に解決された場合、非同期コールバックループ関数を呼び出します。
アダプタレベルでは、待機する価値のあるラベルのプロミスリターンを追加します。 たとえば、ga.jsライブラリ(analytics.js)の初期化後に設定される__utmz Cookieは、いくつかのタグの定義を許可する場合があります。
おわりに
解決する問題の設計の最初に、その複雑さとすべての落とし穴を常に想像するとは限りません。 そしてそのような瞬間に、私はそれを可能な限り単純にしたいのですが、コードの過度の断片化は過剰エンジニアリングの考えを示唆しており、一般的には少し怖いです。 この場合、設計の「正確さ」が実を結び、アプリケーションロジックへのさらなる変更を大幅に簡素化しました。
ご清聴ありがとうございました! それが誰かを助けることを願っています。