18

物事を面白く保ち、私の最後の未解決の質問を締めくくるために、適切なアーキテクチャを使用して適切に整理された方法で以下の機能を実装するソリューションは、かなりの恩恵を受けます. 完全なコードは jsfiddle にあります。質問があればお気軽にどうぞ :)

クライアント側で非常にリッチな複雑な Web アプリケーションを通常どのように編成しますか。大規模なアプリでうまく管理されていない場合に陥りやすい混乱の種類を示すために、不自然な例を作成しました。この例を自由に変更/拡張してください - http://jsfiddle.net/NHyLC/1/

この例は、基本的に SO のコメント投稿の一部を反映しており、次の規則に従います。

  1. 複数のスペースが 1 つに切り捨てられた後、最低 15 文字が必要です。
  2. Add Commentをクリックしても、複数のスペースを削除した後のサイズが 15 未満の場合は、ポップアップにエラーが表示されます。
  3. 残りの文字数を示し、色分けして要約します。グレーは小さなコメント、茶色は中程度のコメント、オレンジは大きなコメント、赤はコメントのオーバーフローを示します。
  4. コメントは 15 秒ごとに 1 つしか送信できません。コメントの送信が早すぎる場合は、適切なエラー メッセージを含むポップアップを表示します。

この例で気付いたいくつかの問題。

  • これは、ウィジェットまたは何らかのパッケージ機能であることが理想的です。
  • 15 秒ごとのコメントや最小 15 文字のコメントなどは、各ウィジェット内に埋め込まれているのではなく、一部のアプリケーション全体のポリシーに属しています。
  • ハードコードされた値が多すぎます。
  • コード編成なし。モデル、ビュー、コントローラーはすべてバンドルされています。MVC がリッチ クライアント側の Web アプリケーションを編成するための唯一のアプローチというわけではありませんが、この例にはありません。

これをどうやって掃除するつもりですか?途中で少し MVC/MVP を適用しますか?

関連する関数の一部を次に示しますが、jsfiddle でコード全体を見た方がより理にかなっています。

/**
 * Handle comment change.
 * Update character count. 
 * Indicate progress
 */
function handleCommentUpdate(comment) {
    var status = $('.comment-status');

    status.text(getStatusText(comment));
    status.removeClass('mild spicy hot sizzling');
    status.addClass(getStatusClass(comment));
}

/**
 * Is the comment valid for submission
 * But first, check if it's all good.
 */
function commentSubmittable(comment) {
    var notTooSoon = !isTooSoon();
    var notEmpty = !isEmpty(comment);
    var hasEnoughCharacters = !isTooShort(comment);

    return notTooSoon && notEmpty && hasEnoughCharacters;
}

/**
 * Submit comment.
 * But first, check if it's all good!
 */
$('.add-comment').click(function() {
    var comment = $('.comment-box').val();

    // submit comment, fake ajax call
    if(commentSubmittable(comment)) {
        .. 
    }

    // show a popup if comment is mostly spaces
    if(isTooShort(comment)) {
        if(comment.length < 15) {
            // blink status message
        }
        else {
           popup("Comment must be at least 15 characters in length.");
        }
    }
    // show a popup is comment submitted too soon
    else if(isTooSoon()) {
        popup("Only 1 comment allowed per 15 seconds.");
    }

});

編集1:

@matpol ラッパー オブジェクトとプラグインの提案をありがとう。これは、既存の混乱を大幅に改善するものです。ただし、プラグインは独立したものではなく、前述のとおり、より大規模で複雑なアプリケーションの一部になります。クライアント/サーバー側のアプリケーション全体のポリシーは、コメントの最小/最大長、ユーザーがコメントできる頻度などを決定します。プラグインには、この情報をパラメーターとして供給することができます。

また、リッチ クライアント側アプリケーションの場合、データを html 表現から分離する必要があります。これは、アプリケーションがデータを認識し、物事をローカルに保存し、サーバー上で定期的に更新できるため、多くのサーバー ラウンドトリップを節約できるためです。 、またはアプリケーション自体内の興味深いイベント (ウィンドウが閉じられたときなど) が発生したとき。これが、プラグインのアプローチがあまり好きではない理由です。パッケージ化された表現を提供する場合と同じように機能しますが、それでもDOMを中心にしているため、アプリケーションにそのようなプラグインが20個ある場合、これは決してばかげた数ではありません.

4

4 に答える 4

23

私がこれを行う方法は3倍です。

  1. 名前空間内の明確に定義された小さなクラスに JavaScript をカプセル化する
  2. Javascript クラスには、依存関係として「注入」する必要がある HTML が必要であり、ブラウザー外での単体テストが可能です。
  3. クライアント側の機能を可能な限りサーバーに移動し、AHAH として知られる概念を使用します。

Javascript 名前空間

これは簡単に実現でき、次のような他の投稿で取り上げられています。

小さなカプセル化されたクラス

Javascript コードは、サーバー側のコードと同様に、まとまりのある小さなクラスとメソッドでカプセル化する必要があります。各クラスは個別のファイルに存在し、名前空間とともに名前が付けられます (例: MyCompany.SomePackage.MyClass.js)。各ファイルへの過剰な HTTP リクエストは、ビルド時にこれらのクラス ファイルを結合および縮小することで保存できます。

Javascript での依存関係の反転

したがって、次のように、クラス内で操作する必要がある要素を選択する代わりに、効果的に次のようにします。

var MyNamespace.MyClass = function() {
  var elementINeed = $('#IdOfElementINeed');
}

次のように注入します。

var foo = new MyNamspace.MyClass($('#IdOfElementINeed'));

var MyNamespace.MyClass = function(incomingDependency) {
  var elementINeed = incomingDependency;
}

この手法は、テスト可能な JavaScript と、コードのMVC スタイルのレイヤー化による関心の分離に役立ちます。

AHAH とクライアント側の単純化

AHAHは、Web 開発でかなり長い間使用されてきた非常に古い手法ですが、その純粋なシンプルさのために Web 愛好家の間で復活しています。ただし、この哲学はアーキテクチャの技術レベル以上のものを取り入れる必要があり、すべてのクライアント側 JavaScript の代わりとして使用する必要があります。たとえば、検証、動的コンテンツの表示/非表示、計算などです。

クライアント側の複雑さで onClick イベントを添付していた場所:

$('#someElement').click(function(){
  // insert complex client-side functionality here, such as validating input
  // eg var isValid = $(this).val() < minimumCommentLength;
  // update page based on result of javascript code
  // eg $('#commentTooLong').show();
})

これで、サーバーに ajax リクエストをトリガーして新しい HTML を取得し、関心のある要素のすべてまたは一部を次のように置き換えるだけです。

$('#addCommentButton').click(function(){
  $.ajax({ 
    url: "/comment/add", 
    context: document.body, success: 
    function(responseHTML){
        $('body').html(reponseHTML);
      }});
})

明らかにこれは些細な例ですが、効果的に使用すると、ページ上のすべての JavaScript イベントが単純に同一の ajax リクエストと HTML 置換を起動し、必要なクライアント側コードの量を大幅に削減します。効果的にテストできるサーバーに移動します。

ああ、否定論者は、これは Web サイトを実行する効率的な方法ではないと主張するでしょうが、私は 56k モデム アクセスのあるサイトや大規模な公開 Web サイトでこの手法を使用し、見てきました。結果はもちろん遅くなりますが、100 ミリ秒未満のラウンド トリップを生成できます。これは人間にとって実質的に瞬時です。

于 2010-06-13T10:04:45.830 に答える
4

Matpolは、提供された特定の情報に文字通りの解決策を提供しました。あなたの編集は、あなたがより仮説的な質問への答えを探していることを意味します。言い換えれば、あなたは「アプローチ」を探しています。

この方法で質問に答えます。あなたが与えた唯一の例は、少し赤いニシンです。これはアプリ全体の1つのアイテムにすぎず、「木から森を見る」ことを妨げます。では、森とは何ですか?そのように尋ねられた質問は、それを定義していません。しかし、定義のないプロジェクトに取り組むのは悪夢だと言うと、すべてのプログラマーが同意すると思います。それで、私はあなたの質問と答えを言い換えます、「プロジェクトを定義するためのプロセスは何ですか?」

実際、私のものは一連の質問をしています。

  • このアプリケーションの主な目的は何ですか?
  • いつ発売しますか?その時間の1/4で起動する必要がある場合、どの機能を維持しますか?
  • 後で必要になると絶対に確信している機能はどれですか?

多くの場合、これらの質問の根底に到達するために、私は他のビジネス上の質問をする必要があります:

  • あなたの聴衆は誰ですか?
  • なぜ彼らはこのサイトを気にするのですか?彼らが戻ってくるのを維持するために何が起こっているのでしょうか?
  • どのように収入を生み出すつもりですか?
  • あなたの行動への呼びかけは何ですか?すべてのユーザーを1つのパスに集めることができるとしたら、それはどれでしょうか。

うまくいけば、これらの質問が、コアと見なすことができる一連の基本的なコードになります。ご想像のとおり、コアはモジュラーアプローチに適合しない可能性があります。そして、あなたが特定したように、あなたはそのコアをモデル/ビュー/コントローラーレイアウトに分解したいと思うでしょう。

しかし、デザインの綿毛を追加する必要があることは避けられません。そして、これはあなたのコード例に戻ります-その綿毛。Fluffは、コアから分離されたプラグインに属しています。これは、すべてのプラグインを個別のjsファイルでユーザーに配信する必要があるということではありません...ただし、開発目的では、プラグインはモジュール式であり、コアコードベースから独立していると見なす必要があります。

于 2010-06-07T06:27:20.197 に答える
3

私はそれをjQueryプラグインまたは静的オブジェクトに変換します。

静的オブジェクトは、種類またはラッパーとして機能します。また、それをより小さな関数に分割します。

init()
checkLength()
checkTime()

したがって、次のような結果になる可能性があります。

Widget = {

init:function(){//setup events etc},
checkLength:function(){},
checkTime:function(){},
doMessage:function(){}


}
于 2010-03-18T08:46:55.437 に答える
1

現在のコードは良い出発点であり、ハードコーディングを回避し、わずかな変更で MVC を明確に分離する大規模なアプリに "スケーリング" することができます。

  • これは、理想的には、ウィジェットまたは何らかのパッケージ機能であるべきです

ウィジェットを使用すると、コメント機能の再利用が容易になり、さまざまなページ/アプリでの再利用が可能になります。関心のカプセル化と分離をプレゼンテーションだけでなく、ウィジェット モデルにも拡張します。コメント フィールドについて考えるとき、コンポーネントの状態をコメント テキストと考えるのは直感的ですが、その動作に影響を与えるすべてのパラメーターは、検証パラメーターを含め、そのモデルの一部にすることができます。したがって、コメント テキストに加えて、モデルには次のものが含まれます。

  • 文字数のサイズ カテゴリへのマッピング (小さすぎる、小さい、中程度、大きい、オーバーフロー)。
  • コメント送信の最大頻度 (15 秒)

ウィジェット モデルは、テキストが変更されるとサイズ カテゴリを更新します。ビューは size-category への変更と、テキスト クラスを更新するために使用される size-category 値をリッスンして、さまざまなコメントの長さの CSS スタイルを生成します。「コメントを追加」をクリックすると、サイズカテゴリもチェックされます。「小さすぎる」または「オーバーフロー」の場合、ポップアップが表示されます。Add Comment ハンドラーは文字数をチェックしないことに注意してください。これはモデル内で分離されています。サイズ カテゴリをチェックします。必要に応じて、"コメントの追加" コントローラーは、モデルがユーザーに役立つメッセージを生成するために使用するのと同じ文字数からサイズ カテゴリへのマッピングを使用できます。たとえば、「コメントは少なくとも 15 文字にする必要があります」の場合、サイズ カテゴリ マップから 15 が取得されます。

このモデルは、ウィジェットの UI を更新するために変更イベントが使用される「残りの文字数」プロパティも提供します。最大文字数は、文字からサイズ カテゴリへのマップからフェッチされます。

  • 15 秒ごとのコメントや最小 15 文字のコメントなどは、各ウィジェット内に埋め込まれているのではなく、一部のアプリケーション全体のポリシーに属しています。
  • ハードコードされた値が多すぎます。
  • コード編成なし。モデル、ビュー、コントローラーはすべてバンドルされています。MVC がリッチ クライアント側の Web アプリケーションを編成するための唯一のアプローチというわけではありませんが、この例にはありません。

多くの種類のコメント (コメントされているさまざまなアイテムなど) と、さまざまな種類のコメント ウィジェットが存在する場合があります。それらがすべて同じ最小/最大範囲を持つ必要がある場合は、コメントの検証を制御する同じモデル値ですべてパラメーター化する必要があります。これは、コメント モデルのデータを構築するときにサーバー側で行うのが最適です。その特定のコメントのコメント テキストが取得され、サイズとカテゴリのマッピングなどのコメント検証値がページまたはアプリケーション構成のデフォルトから取得されます。コンポーネント検証モデルを作成するための中心的なロジックを持つことで、新しいルールの追加がはるかに簡単になります。たとえば、「モデレーターは最大 1K のコメントを投稿できます」など、1 つのコードの変更になります。コンポーネント モデルをサーバー側で計算するもう 1 つのポイントは、モデルもサーバー側で検証する必要があるということです。JavaScript を無効にして、検証クライアントから独立して HTTP リクエストを作成できます。

要約すると、これの多くは、ウィジェット モデルのサーバー側の生産を組織化することと見なすことができます。これをサーバー側で行うことにより、サーバーは検証ルールを適用し、複雑なルールやアプリケーション全体の構成からウィジェットを保護できます。

このパターンは UI テクノロジに関係なくアプリケーションに有効であるため、jQuery やその他の UI テクノロジについては言及していません。パターンを適用する方法は、検証モデルをウィジェットに提供する方法や、リスナーをモデルに接続する方法など、ある程度 UI 固有になりますが、パターンの組織レベルは UI と直交しています。主な焦点はモデルにあります-検証の側面を含むようにモデルを拡張し、サーバー側で計算します。それが整ったら、組織の問題はほとんど解決されます。

于 2010-06-12T22:51:29.983 に答える