9

システムで a に遭遇しgod objectました。このシステムはpublic service、クライアントに公開されている、middle office serviceおよびで構成されていますback office service

フローは次のとおりです。ユーザーがトランザクションを に登録しpublic service、マネージャーmiddle office serviceがトランザクションをチェックしてトランザクションを承認または拒否し、最後にマネージャーがトランザクションをback office service確定または拒否します。

という言葉を使っていますが、実際には、transactionのようなさまざまな種類の操作です ... 操作だけでなく、などの他の多くの操作も...CRUD on entity1CRUD on entiny2CRUDapprove/send/decline entity1make entity1 parent/child of entity2

現在、WCFサービス契約はシステムのこれらの部分に従って分離されています。したがって、3 つのサービス契約があります。

PublicService.cs
MiddleOfficeService.cs
BackOfficeService.cs

そして、それぞれの膨大な量の操作契約:

public interface IBackOfficeService
{
    [OperationContract]
    void AddEntity1(Entity1 item);

    [OperationContract]
    void DeleteEntity1(Entity1 item);

    ....

    [OperationContract]
    void SendEntity2(Entity2 item);

    ....
}

これらの運用契約数は、3 つのサービス全体ですでに 2000 であり、各サービス契約あたり約 600 です。ベスト プラクティスを破るだけでなく、サービス リファレンスを更新するだけでも時間がかかるため、非常に苦痛です。また、システムは日々成長しており、反復のたびにこれらのサービスにさらに多くの操作が追加されています。

そして今、私たちはこれらの神のサービスを論理的な部分に分割するにはどうすればよいかというジレンマに直面しています. 1 つのサービスには 12 ~ 20 を超える操作を含めるべきではないと言われています。他の人はいくつかの異なることを言います。黄金律がないことは承知していますが、これについていくつかの推奨事項を聞きたいと思います.

たとえば、これらのサービスをエンティティ タイプごとに分割すると、プロジェクトで約 50 のサービス エンドポイントと 50 のサービス参照を取得できます。この場合の保守性についてはどうでしょうか。

考慮すべきことがもう 1 つあります。これらのサービスをエンティティごとに分割するアプローチを選択するとします。例えば:

public interface IEntity1Service
{
    [OperationContract]
    void AddEntity1(Entity1 item);

    [OperationContract]
    void ApproveEntity1(Entity1 item);

    [OperationContract]
    void SendEntity1(Entity1 item);

    [OperationContract]
    void DeleteEntity1(Entity1 item);
    ....

    [OperationContract]
    void FinalizeEntity1(Entity1 item);

    [OperationContract]
    void DeclineEntity1(Entity1 item);
}

ここで、 と の両方でこのサービスへの参照を追加する必要がpublic clientありback office clientます。しかし、操作back officeのみが必要です。これが in の典型的な違反です。そのため、さらに、、 のような 3 つの異なるサービスに分割する必要があります。FinalizeEntity1DeclineEntity1Interface segregation principleSOLIDIEntity1FrontServiceIEntity1MiddleServiceIEntity1BackService

4

4 に答える 4

1

私は WCF の経験はありませんが、神のクラスとオーバーロードされたインターフェイスは一般的な OOD の問題のように思われます。

システムを設計するときは、データ構造や操作ではなく、動作 (またはビジネス ロジック) を探す必要があります。それをどのように実装するかではなく、クライアントがそれをどのように使用し、どのように名前を付けるかを見てください。私の経験では、メソッドに適切な名前を付けると、通常、オブジェクトとその結合に関する多くの手がかりが得られます。

私にとって目を見張るものは、 Robert C. Martin による「UML for Java Programmers」からの抜粋である、Mark IV コーヒー メーカーの設計でした。意味のある名前については、彼の著書「Clean Code」をお勧めします。

したがって、次のような個別の操作のインターフェイスを構築する代わりに:

GetClientByName(string name);
AddOrder(PartNumber p, ContactInformation i);
SendOrder(Order o);

次のようにします。

PrepareNewOrderForApproval(PartNumber p, string clientName);

これを行ったら、別のオブジェクトにリファクタリングすることもできます。

于 2015-07-06T12:24:23.110 に答える
1

あなたの問題は、サービス構成の問題であるため、神のオブジェクトの問題ではありません。God オブジェクトが問題になる理由は、crud ベースの巨大なサービス インターフェイスが問題となる理由とは異なります。

あなたが説明した 3 つのサービス契約が事実上管理不能な状態に達しつつあることに、私は確かに同意します。リファクタリングに関連する痛みは、これがインプロセス コードである場合よりも不釣り合いに大きくなるため、正しいアプローチを取ることが非常に重要です。したがって、あなたの質問です。

残念ながら、soa でのサービスの構成可能性は非常に大きなトピックであるため、ここで非常に有用な回答を受け取ることはまずありません。明らかに役に立ちますが、他の人の経験があなたの状況に当てはまる可能性はほとんどありません。

これについては以前に SO で書いたので、価値があるので、私の考えを含めます。

私は、サービスの運用がビジネス上の意味を持つレベルで存在できることが最善であると考えています。

これが意味することは、ビジネス担当者が操作名を教えられた場合、その操作を呼び出すことで何が行われるかを大まかに理解し、それに渡す必要があるデータを推測できるということです。

これを実現するには、業務がビジネス プロセスの全部または一部を実行する必要があります。

たとえば、次の操作シグネチャにはビジネス上の意味があります。

void SolicitQuote(int brokerId, int userId, DateTime quoteRequiredBy);

int BindPolicyDocument(byte[] document, SomeType documentMetadata);

Guid BeginOnboardEmployee(string employeeName, DateTime employeeDateOfBirth);

サービスの構成を考えるときにこのプリンシパルを使用すると、最適なパスからほとんど外れなくなるという利点があります。各操作が何をするかを知っており、いつ操作が不要になるかを知っています。

追加の利点は、ビジネス プロセスがほとんど変更されないため、サービス契約をそれほど変更する必要がないことです。

于 2015-06-25T11:00:33.343 に答える