web-dev-qa-db-ja.com

SPAでクライアント側モデルとサーバー側の同期を保つ

SPAにはほとんどのドメインロジッククライアント側があるため、ドメインモデルをバックエンドと同期させるにはどうすればよいですか?

たとえば、Entity Frameworkを使用してSQL Serverと通信する.NET WebAPI Webサービスがあり、私のクラスの1つがProductと呼ばれているとします。製品のドメインロジックのほとんどはクライアント側になります。

次に、ProductTypeテーブルをDBに追加し、ProductTypeID列をProductsテーブルに追加します。 EF ProductクラスにProductTypeIDという新しいプロパティが追加されました。 JSファイルに手動で移動し、Productの定義を見つけてProductTypeIDプロパティを追加しますか?

クライアント側はサーバー側の実装の詳細を知る必要はありませんが、モデルの形状を知る必要があります。それをサーバー側とクライアント側の間でどのように同期させますか?完全に手動ですか? JSのプロパティ名のタイプミスのようなエラーをどのように回避しますか?

7
Legion

通常、そうする理由がない限り、この方法で同期を維持することはありません。あなたの前提全体に欠陥があります。他のアプリケーションと同様に、SPAのほとんどのドメインロジックはサーバー内にある必要があります。クライアントには、ユーザーインターフェイスに関連するロジックのみを含める必要があります。

編集:

用語を明確にするために。 「ドメインロジック」とは、アプリケーションのコアビジネスロジックを意味するものだと思います。これにより、アプリケーションはリソースに対するCRUD操作だけではなくなります。アプリケーションで必要なのは、一部のデータの格納、取得、更新、および削除のみである場合がよくあります。その場合、すべての「ロジック」がクライアントにあると思います。

しかし、在庫アイテムがあり、ユーザーがショッピングカートにアイテムを追加して購入できる単純な購入システムを想像してみてください。次に、アイテムが在庫にあるか在庫がないかを知る必要があるとします。在庫がない場合、特定のユースケースでは、在庫切れのアイテムの購入は許可されていません。このシナリオでは、この要件チェックロジックがバックエンドにない場合、正しいことを行っているとは思いません。

アイテムが在庫切れの場合は、クライアントの[今すぐ購入]ボタンを無効にすることをお勧めしますが、進取的なティーンエイジャーがPOST curlを使用したリクエストは私には非常に間違っているようです。

理由商品が在庫切れであることをクライアントに知らせる異なるバックエンドがそれを知る理由から。クライアントはボタンを無効にするためにそれを知る必要がありますが、誤った請求を防ぐためにバックエンドはそれを知る必要があります。

システムの状態のクライアントのモデルには、購入可能なブール値だけが含まれる場合がありますが、サーバーのモデルは、アイテムが在庫にあるかどうかだけでなく、さまざまな理由を説明します。おそらく、アイテムが現在のユーザーの場所に発送できないか、現在のユーザーのアカウントに35%のクーポンがあり、アイテムのマージンが35%未満。アイテムが購入可能であるかどうかの理由がクライアントよりもサーバーにとって複雑である可能性が高く、ビジネスシステムがサイトのJSファイルをダウンロードできるすべての人がビジネスロジックを利用できるようにすることはほとんどありません(すべての訪問者!)。

おそらくその場合のサーバーは、購入可能なアイテムのクエリの結果のリストからアイテムを単に削除するだけです。クライアントは、アイテムが最初に存在することを認識していないため、このアイテムにビジネスドメインロジックを適用することはできません。

次にネイティブモバイルアプリケーションを展開する場合はどうでしょうか。新しいクライアントごとにビジネスドメインロジックをすべて再作成しますか?システムが非常に大きくなり、何百ものルールがある場合はどうなりますか?

経験豊富なソフトウェア開発者の重要なポイントの1つは、システムに複数のモデルが存在する可能性があること、および存在することです。

9
RibaldEddie

私はこの問題の醜いが実用的な解決策を持っています。より良いものを探しているときにこの投稿を見つけましたが、おそらく誰かを刺激するために私の投稿を投稿します。 PHPの外ではどのように機能するかわかりません。バックエンドではこれを使用します:

class BaseModel // All models extend this class
{
    // Returns an object with each property set to its own name as a string
    /* @return static */
    public static function getNameObject()
    {
        $obj = (object) get_class_vars(get_called_class()); // Note: Avoids calling constructor
        foreach (get_object_vars($object) as $key => $value) {
            $object->{$key} = $key;
        }
        return $obj;
    }
}

class User extends BaseModel
{
    public $id;
    public $name;
}

次に、PHP=をJavaScriptファイルに追加します。

<?php $u = User::getNameObject(); ?>

var user     = getUserFromServer();
var userId   = user.<?=$u->id?>;
var userName = user.<?=$u->name?>;

このようにして、IDEのリファクタリングコマンドを使用してモデルプロパティ名を変更すると、すべてのフロントエンドコードも更新されます。すべての* .js.phpファイルはビルドプロセス中に* .jsファイルになるように実行されるため、通常の静的JavaScriptとして提供できます。

1
Ben