設計テンプレートと筆者の記事の読み方
概要
筆者はすべてのサービスを同じ手順で設計しているので、ブログも同じように形式的に書きます。
当方のブログの構造とその理由についてここにまとめますので、一読してもらえれば他の記事が読みやすくなると思います。
なお、このテンプレート自体も改良を重ねており、記事の執筆時期が古かったりすると、テンプレートと完全に一致しない場合もあります。その点ご了承ください。
※本記事では、機械的な設計手順についてコードで表現している部分があります。また設計用語として数学的な表記も借用しています。少し特殊に見えるかもしれませんが、より正確な説明のための工夫としてご理解ください。
ブログテンプレート
# 概要
興味を引く概要、あと画像とかで実際どうなるかを最初に示す
# インフラ
docker-compose.yamlを示したり、aws構成図などを用いてインフラの説明などを行う
# 構成
mermaidとかでドメインとかアダプタの図を書いとく
必須ではない、ドメインに含めてもよさげ
# ドメイン
プロジェクトの中核となる「ドメイン」は、特定の技術([TECH_EXAMPLE_1]や[TECH_EXAMPLE_2]など)に依存しない、純粋なビジネスロジックを表現する部分です。
たとえば「[CORE_FUNCTIONALITY]」という機能は、[PREREQUISITES_LIST]ことだけを前提に設計できます。[IMPLEMENTATION_DETAILS]は、この時点では考えなくて良いのです。
このように技術的な実装から切り離すことで、仕様変更に強く、テストが書きやすく、コードの意図が明確になります。以下のコードは、そのドメインレイヤーの実装です。
``go
type UserRepository interface {
FindByEmail(email string) (User, error)
}
``
# アダプタの実装
前章で示したドメインを、実際の技術を使って実装していきます。ここでは具体的に:
[TECH_IMPLEMENTATION_LIST]
使用しています。
先ほどのドメインレイヤーで定義したインターフェース([INTERFACE_LIST])に対して、それぞれの具体的な実装([CONCRETE_IMPLEMENTATION_LIST])を提供します。この方式のメリットは、例えば[EXAMPLE_REPLACEMENT]に置き換えたい場合、新しい[NEW_IMPLEMENTATION_CLASS]クラスを作るだけで、他のコードは一切変更する必要がないという点です。
また、これらの実装を[INTEGRATION_POINT]として統合することで、[BENEFIT_DESCRIPTION]。以下が各実装のコードです:
``go
type SqlUserRepository struct {
db *sql.DB
}
func (r MysqlUserRepository) FindByEmail(email string) (User, error) {
return user, nil
}
``
# まとめ
全体のまとめと考察
設計手順
1. PoC作成
いきなりドメイン作成は難しいのでPoCを書いてイメージを掴みます。
2. ドメイン作成
1. インデックス化
入力コーパスをTextUnit(テキストユニット)に分割します。これらは、プロセスの残りの部分で分析可能な単位として機能し、出力において詳細な参照を提供します。
LLMを使用して、TextUnitから全ての実体(エンティティ)、関係性、重要な主張を抽出します。
Leiden手法を用いてグラフの階層的クラスタリングを実行します。これを視覚的に確認するには、上記の図1をご覧ください。各円は実体(例:人物、場所、組織)を表し、大きさはその実体の次数を、色はそのコミュニティを表しています。
各コミュニティとその構成要素のサマリーをボトムアップで生成します。これによりデータセットの全体的な理解を助けます。
2. Proof Tree作成
最上位のドメインを再帰的にサブドメインに分割します。
構成図では、ドメインの内容を木構造で表します。
from typing import List
class Lemma:
"""補題を表現するクラス。
各補題は、他の補題(self.lemmas)が証明済みであることを前提として
証明を構築することができます。
Attributes:
statement: 補題の内容を表現する文
lemmas: この補題の証明で前提として使用する補題のリスト
"""
def __init__(self, statement=None):
self.statement = statement
self.lemmas = []
class SolutionArchitect:
def __init__(self, context_repository):
self.context_repository = context_repository
def build(self, theorem: Lemma) -> Lemma:
"""証明木を構築する。
与えられた定理を基本補題まで再帰的に分解し、proof treeを構築します。
構築後は、基本補題から順に証明を行うことで、全体の証明が完成します。
Args:
theorem: 証明したい定理・補題
Returns:
証明木が構築された定理
"""
if self.is_primitive(theorem):
return theorem
for lemma in self.decompose(theorem):
theorem.lemmas.append(self.build(lemma))
return theorem
def is_primitive(self, lemma: Lemma):
"""
基本補題(primitive lemma)かどうかを判定
- 他の補題から導出されない基本的な命題
- これ以上分解すると本質的な意味が失われる
- 公理や定義から直接証明できる
などの条件を想定
"""
...
def decompose(self, lemma: Lemma) -> List[Lemma]:
"""
補題をより基本的な補題に分解
- 結合された命題の分離
- 証明のステップへの分解
などの分解方法を想定
"""
...
# TODO: 前述のGraphRAGを利用したContextの取得が可能なリポジトリが必要
context_repository = ...
theorem = Lemma("Complex theorem statement")
proof_tree = SolutionArchitect(context_repository).build(theorem)
proof treeができたら、すべての基本補題をMockを用いて実装し、それらを組み合わせて原理実証を行います。
3. インフラ準備
データベースや外部サービスなどのインフラを準備します。
例えば、docker compose up
したりawsのインスタンス建てたりします。
4. アダプタ作成
ドメインで定義したインターフェースに従って、実際のインフラ(データベースや外部サービス)を使用した実装を行います。すべてのMockを置き換えたら完成です。
Discussion