同心円以上のレイヤー





この記事は、ソフトウェアアーキテクチャに関する一連の記事であるChronicle of Software Architectureの一部です。 それらには、ソフトウェアアーキテクチャについて学んだこと、それについてどう思うか、知識をどのように使うかについて書いています。 この記事の内容は、シリーズの以前の記事を読んだ方が意味があります。



シリーズの前回の記事で、コードのタイプ間の関係を示す概念マップを公開しました。



しかし、私には常にすべてがうまく反映されているわけではないように思えました。 共通のコアについてです。



さらに、この短い記事で概要を説明する考えがいくつかあります。



このシリーズの最後の記事のインフォグラフィックでは、ダイアグラムの中央に共通のコアがあります。 これは、ドメイン層の内部と、限られたコンテキストである円錐セクションの上にあるようです。







その位置にもかかわらず、私は、共通コアが残りのコードに依存している、または共通コアがドメインレベル内の別の層であることを意味しませんでした。



共通のコアとは何ですか?!



DDDの父である Eric Evansが定義した共通のコアは、開発チームがいくつかの限定されたコンテキストに分割することを決定したコードです。



[...] 2つのチームが一緒に使用することに同意したドメインモデルのサブセット。 もちろん、モデルのこのサブセットとともに、共通コアには、モデルのこの部分に関連付けられたコードまたはデータベースアーキテクチャのサブセットが含まれます。 この明らかに一般的な資料には特別なステータスがあり、別のチームに相談せずに変更しないでください。



- 「共通カーネル」 、ワードカニンガムのDDD Wiki


したがって、ドメインレベルのコード、アプリケーションレベルのコード、ライブラリなど、あらゆる種類のコードを使用できます。







ただし、概念マップのコンテキストでは、特定のタイプのコードとして、サブセットとして提示します。 私のコンセプトマップでは、共通コアにドメインレベルとアプリケーションレベルのコードが含まれており、制限されたコンテキスト間で通信できるように、限られたコンテキストで共有されます。



たとえば、これは、1つ以上の制限されたコンテキストでイベントが発生し、他の制限されたコンテキストでリッスンされることを意味します。 これらのイベントとともに、これらのイベントで使用されるすべてのデータ型を共有する必要があります。たとえば、エンティティ識別子、値オブジェクト、列挙などです。エンティティなどの複雑なオブジェクトは、イベントによって直接使用することはできません。キューから/へのシリアライズ/デシリアライズを行うため、汎用コードを広く配布すべきではありません。



もちろん、マイクロサービスの多言語システムがある場合、すべてのマイクロサービスが理解できるように、共通のコアはJSON、XML、YAMLなどで記述的でなければなりません。



その結果、この共通コアは、コードベースの残りの部分、コンポーネントから完全に分離されています。 コンポーネントは共通のコアに接続されていますが、互いに分離されているため、これは素晴らしいことです。 汎用コードは明示的に識別され、簡単に別のライブラリに取得されます。



また、モノリスとは別に、限られたコンテキストの1つをマイクロサービスに抽出することを決定した場合にも非常に便利です。 一般的なものは確実にわかっており、モノリスとマイクロサービスの両方にインストールされるライブラリに単純に共通のコアを抽出できます。



要約すると、私の概念マップでは、アプリケーションコアは、限られたコンテキスト間で共有されるドメインおよびアプリケーションレベルのコードを含む共通カーネルに依存しています。



言語が十分でないとき...



そのため、すべての同心円層を持つアプリケーションコードがあり、アプリケーションコアは、このすべてのコードの下にある共通コアに依存しています。



また、このコードはすべて使用するプログラミング言語に依存すると言うこともできますが、それを完全に無視する傾向があるのは明らかな事実です。



しかし、「言語構成要素が十分でない場合はどうすればよいのでしょうか?」という疑問が生じます。まあ、明らかに、私たち自身がこれらの言語構成要素を作成し、言語の欠点を補います。 しかし、フォローアップに関する重要な質問があります。「このコードの存在を正当化する方法と場所は? いつ、どのように使用するかをどのように明確に示すことができますか?



私が見たのは、UtilsまたはCommonsというパッケージで、このコードがある場所です。 しかし、最終的には、どこに置くべきかわからないすべてのコードをそこにダンプします! さまざまな目的と使いやすさのためのあらゆる種類のコード(直接使用されるアダプターにラップされています...)が最終的にそこにダンプされます。 パッケージには、概念的な意味、一貫性、一貫性、明快さ、あいまいさはありません。



UtilsおよびCommonsパッケージを放棄したい!



すべてのパッケージには概念的な凝集性が必要です! パッケージをいつどのように使用するかが明確になっているはずです! あいまいさはありません!



たとえば、アプリケーションが特別な方法でコマンドラインインターフェイスと対話する場合、名前空間「Acme / Util / SpecialCli」に配置する代わりに、「Acme / App / Infrastructure / Cli / SpecialCli」に配置できます。 これは、このパッケージがCLIに関連付けられており、Acme Appアプリインフラストラクチャの一部であることを示しています。 Appインフラストラクチャとの提携では、このパッケージが対応するアプリケーションのカーネルにポートがあることも示されています。



あるいは、このパッケージが言語自体に欠けているものと考えられる場合、適切なネームスペース(たとえば、「Acme / PhpExtension / SpecialCli」)に入れることができます。 これは、このパッケージを言語自体の一部と見なす必要があることを示しています。したがって、そのコードは他の言語構成要素と同様にコードベースで直接使用する必要があります。 もちろん、別の会社がこのパッケージに依存している場合、直接依存しない方が合理的かもしれませんが、他の会社と交換できるようにポート/アダプターを作成する方が安全です。 しかし、パッケージを所有している場合、それを言語の一部と見なすことができます。パッケージを別の代替品と交換するリスクはそれほど大きくないからです。 妥協は常に問題です。



言語の一部として考えられる別の例は、PHPの一意のUUIDです。 それらは言語の外で想像することはかなり可能です、なぜなら新しいバージョンが毎回あり、それがコードをサポートする悪夢だからです。



それでは、なぜUUID実装を作成してPHP自体の一部のように使用しないのですか?DateTimeオブジェクトをどのように使用するのでしょうか?! 実装を制御している間、欠陥は見当たりません。



Doctrine Query Language(DQL)はどうですか? (DoctrineはPHPのHibernateポートです)DQLをSQL、Elasticsearch QL、またはMongo QLのように見ることができますか?



おわりに



したがって、マクロレベルでは、4つの基本的なタイプのコードが表示されます。コードベースの構成で明確に示すことは、多くの汚れにならないようにするために重要だと思います。







私にとって、否定できない真実は、 アーキテクチャが常に存在するということです。唯一の問題は、それを制御するかどうかです。



それでは、アーキテクチャマップ(全体または一部) に従ってコードを明確に整理しましょう-私または他のコンセプトマップ。 主なことは、プロジェクトがコードの構造と編成を通じてそのアーキテクチャを明示的に報告するようにコードを編成することです。



All Articles