web-dev-qa-db-ja.com

神のコントローラークラスを回避し、単一の責任の原則を守る方法は?

タスクは、OOP単一責任の原則)を使用して、古いDBから新しいDBに移行することです。

enter image description here

私の問題は、コントローラーを神のクラスにしたり、単一の責任を壊したりせずに、どうすればこれを作成できるかです。

これを実装する2つの方法を考えました

  1. 各プロパティ行を反復処理し、コントローラーのサブディビジョンと所有者にカスケードし、エンティティタイプごとに行移行を呼び出します

    • それはコントローラーにあまりにも多くの責任を与えており、それを神のクラスにするだろうと言われました
  2. 各エンティティ内に反復を追加します(例:プロパティはサブディビジョンを反復し、サブディビジョンは所有者を反復します)

    • 単一責任の原則に違反していると言われました

今のところ、私が考えることは、ルールを複雑にしすぎたり、破ったりしているように感じます。多分私は間違った原則を理解したか、または3番目の方法があります。

アップデート1

通常、これはスクリプトで行いますが、新しいDBが別のプラットフォームにあり、addAddress()およびaddOwner()ロジックがAPIコンポーネントにあるため、APIを使用する必要があります。

2
Stefan Rogin

OOPは常にETLタスクに最適な選択であるとは限らないため、ここでは「純粋」に固執しませんOOPここで。モデルが3つのテーブルのみの例に示すように単純である限り移行するには、これを過剰に設計することを避けます。3つのテーブルの移行を調整し、異なる「行移行」クラスを使用する1つのコントローラーがあるだけでは、コントローラーが「多すぎる」ようには見えません。責任」。

それにもかかわらず、責任を分散するためのいくつかのオプションがあります。 ETLプログラムの場合、移行の「E(xtract)」、「T(ransform)」、「L(oad)」の部分に責任を分割することをお勧めします。接続するのは「Extractor」クラスだけです。古いDBに移行し、移行するデータを提供します。「Load」クラスは新しいデータベースに接続する/ APIを使用する唯一のクラスであり、「Transform」クラスは変換作業を行いますが、ソースについては何も知りません。またはデータの宛先。さらに、例に示すように実際のモデルがはるかに大きい場合は、「Transform」クラスを小さな「サブトランスフォーマー」に分割することを検討してください。

2番目のオプションが理にかなっている場合、IMHOはエンティティクラスを移行コンテキストで排他的に使用するか、または異なるコンテキストで再利用および維持できるようにするかによって異なります。後者の場合、この非常に特殊なユースケース「移行」にのみ役立つビジネスロジックを追加しません。

4
Doc Brown

「コントローラー」は必要ありません。「サービス」が必要です。

Controllerは、ユーザー入力や下位層で発生するその他のイベントに基づいて、アプリケーションのフローを制御します。 Serviceは、言われたとおりにビジネスを行うだけです。

移行サービスオブジェクトには、古いスキーマからデータをプルし、必要に応じてWebサービスまたはまったく異なるAPIを介して新しいスキーマにデータを永続化するためのインテリジェンスがあります。このサービスには、ジョブを実行するための最小限の依存関係が必要です。

  • 各データベースのドメインモデルクラス
  • 各データベースのデータアクセスクラス
  • あるドメインモデルを別のドメインモデルにマップするメソッドまたは他のクラス

PropertyMigrationServiceには、次の責任があります。

  • どこからデータをプルするかを知る
  • データを保存する場所を知る
  • マッピングオブジェクトにアクセスして、あるドメインモデルを別のドメインモデルにマッピングする

必要なもの:

  • OldDataAccess-古いDBでのCRUD操作用のクラス
    • Property-古いDBの「プロパティ」のドメインモデル
    • Subdivision-古いDBのサブディビジョンのドメインモデル
    • Owner-古いDBの所有者のドメインモデル
  • NewDataAccess-新しいDB/WebサービスでのCRUD操作のクラス
    • Address-新しいDBのプロパティのドメインモデル
    • Owner-新しいDBの所有者のドメインモデル
  • PropertyToAddressMapper-古いDBのPropertyオブジェクトを新しいDBのAddressオブジェクトにマッピングする
  • SubdivisionToAddressMapper-古いDBのSubdivisionオブジェクトを新しいDBのAddressオブジェクトにマッピングする
  • OwnerToOwnerMapper-所有者オブジェクトをあるDBから別のDBにマップします

次のオブジェクト階層になります。

  • PropertyMigrationService
    • OldDataAccess
    • NewDataAccess
    • PropertyToAddressMapper
    • SubdivisionToAddressMapper
    • OwnerToOwnerMapper

移行サービスには、移行を実行するvoid migrate()という単一のパブリックメソッドを含めることができます。

従来のスキーマを扱ってきたので、どのような狂気と混乱に遭遇するかはわかりません。この方法でソリューションを設計し、データアクセスクラスにインターフェイスを実装させ、PropertyMigrationServiceにインターフェイスを介してこれらのオブジェクトを使用させることで、この移行プロセス全体をユニットテスト可能にすることができます。

これで、既知のエラー条件についてこれに一連のテストを実行し、これを実際に完全な証拠(十分な耐性)にすることができます。

これがサービスオブジェクトにラップされた後、いつ、どこで呼び出されるかについてある程度の柔軟性が得られます。

  • Webアプリケーションの「コントローラー」から
  • LinuxのcronジョブまたはWindowsのスケジュールされたタスクとして開始されたスクリプトから

移行プロセスは、プロアクティブ(ユーザーがWebページのボタンをクリックして移行を実行する)またはパッシブ(スケジュールタスクが深夜に実行され、これらのレコードをたとえば1,000のバッチで実行する)の両方になります。

4
Greg Burghardt