mcpField
L
low-level-design

low-level-design

github.com/yahyabedirhan開発269 回インストール1 日前に更新
リポジトリ

low-level-design について

コードベースのモジュール、状態、責務、呼び出し関係、ファイル配置を設計・説明するスキルです。段階的な枠組みで要件と根拠に沿って設計し、不要な構造の追加を避けます。

主な機能

  1. 01要件から拡張性までの設計段階
  2. 02エンティティと関係の整理
  3. 03モジュールの状態と振る舞いの定義
  4. 04実装フローの草案と追跡
  5. 05将来の変更箇所の対応付け

活用シーン

  1. 01新機能のモジュールとファイルを計画
  2. 02既存コードの構成を説明
  3. 03具体的なコード設計上の判断を検討

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yahyabedirhan/skills --skill low-level-design

インストール後、Claude Code で/low-level-designを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
design-patterns.md
design-principles.md
layout.md
oop-concepts.md

詳細

低レベル設計

低レベル設計では、どのモジュールを用意するか、それぞれがどの状態やルールを担うか、互いにどのように呼び出し合うか、各ファイルをどこに配置するかを決めます。優れた設計なら、初めて参加した人がすべてを読まなくても、プログラムの開始地点、エンドポイントの追加方法、共通ロジックの場所、変更によって影響を受ける範囲を見つけられます。設計、説明、再設計のいずれの場合も、毎回のセッションで提供フレームワークを通じて作成し、提示してください。そうすれば、ユーザーはいつでも同じ場所で同じ情報を見つけられます。セッションの目的はユーザーが決め、回答の構成方法はフレームワークが定めます。ユーザーが設計に同意したら、そこで止めてください。実装は後で、チケットに基づいて行います。

よくある失敗は、必要になる前に構造を追加することです。たとえば、生成物が1つしかないファクトリー、実装が1つしかないインターフェース、関数ごとに1つのファイルを作ることです。要件を満たす最もシンプルな設計から始め、今日、2つ目の実装が必要な場合や、複数のファイルで同じ編集を繰り返す場合など、明確な理由があるときにだけクラス、インターフェース、パターンを追加してください。モジュールを設計する前に、プロジェクトにすでにある依存関係で実現できないか確認し、その差分だけを作成してください。

サービス、データストア、API、スケールのレベルでシステムを設計するには、/system-designを使用してください。コマンドラインインターフェースのコマンド、フラグ、出力、ヘルプを設計するには、/cli-designを使用してください。

手順

  1. **セッションの目的を1行で言い直します。**依頼とその文脈から読み取り、読み違いによるやり取りを減らします。新しいものの設計、既存コードの説明、再設計、1つの事項の決定、またはその組み合わせのいずれかを明確にします。
    • **プロジェクト内で指示なしに呼び出された場合:**そのプロジェクトの現在の設計を書き出します。
    • **目的が不明確な場合:**セッションで何をしたいのか、つまり新しい設計、既存コードの説明、変更のどれなのかをユーザーに尋ねます。コードが存在するかどうか、自分でも確認してください。
  2. 以下の提供フレームワークに沿って、各ステージを順に進めます。判断にあたって必要な場合は、原則、概念、パターンの参考資料を読みます。
  3. 提示し、フィードバックを受け、ユーザーが同意するまで修正します。
  4. ユーザーが希望する場所に設計を保管します。

セッションの目的に応じて、各ステージの進め方を決めます。以下はよくあるケースですが、これだけではありません。セッションでは複数のケースを組み合わせたり、説明から再設計へ移るなど、途中で別のケースに移ったりすることもあります。また、これら以外のケースもあるため、ユーザーの依頼に合わせてフレームワークを調整してください。

  • **新しいものを設計する:**ユーザーの仕様に基づき、すべてのステージを通して完全な初稿を作成します。
  • **既存コードを説明する:**変更を加えず、現状のコードを各ステージに沿って説明します。
    • 各ステージは根拠に基づいて作成します。既存の設計ドキュメントから始め、コードと照合してから、エントリーポイント、型、フォルダー、テストなどのコード自体を確認します。ユーザーの説明も根拠になります。主張ごとに、その根拠となるファイルを示してください。
    • 振る舞いやテストから読み取った要件には推定と明記します。選択の理由や今後の計画など、コードからはわからないことには不明と明記し、推測で補わず、ユーザーに尋ねてください。
    • 各ファイルが何を担うか、また、1つのファイルが複数の内容を混在させている場合は、その内容を示します。改善点は提案せず、観察事項として報告します。このセッションではコードを現状のままにするためです。
    • 追加の質問には、設計をたどりながら呼び出しの流れを追って回答します。
  • **既存コードを再設計する:**まず既存コードを説明し、その内容が正しいとユーザーの同意を得ます。その後、同じステージに沿って、再設計に必要な箇所だけを変更します。小さな変更なら影響するステージだけを実施し、構成の変更ならすべてのステージを実施します。フォルダーツリーを含め、変更した各ステージの変更前と変更後を示します。
  • 1つの事項を決める場合:「これはインターフェースにすべきか?」「このモジュールはどこに置くべきか?」など、その事項が影響する設計の部分、判断の背景にある要件、トレードオフを含む選択肢、おすすめの案を示して回答します。

デリバリーフレームワーク

Requirements → Entities and relationships → Class design → Implementation → Extensibility

各段階は一つ前の段階を土台にします。エンティティは要件から導き出され、クラスはエンティティに状態と振る舞いを与え、実装によってクラスが機能することを確認し、拡張性の検証によって次に起こり得る変更に備えます。現在の段階で、その成果物に挙げられたものがすべて揃ったら、次の段階に進みます。後の段階で不足が見つかった場合は、前の段階に戻ります。避けるべき失敗は二つあります。構造が明確になる前にコードを書くことと、細部を磨き続けて設計をまとめられなくなることです。

要件

リクエストや仕様を、設計の基準となる形に整理します。次の四つのテーマに沿って進めます。

  • 機能:システムがサポートしなければならない操作。
  • ルールと完了条件:成功と失敗を定義するもの、およびシステムが停止する、または状態を変えるタイミング。
  • エラー処理:無効な入力や許可されていない操作に対する応答。
  • 対象範囲:コアロジックやビジネスルールなど、含めるものと、UI、ストレージ、並行処理など、またはユーザーが明示的に除外したその他のものなど、対象外とするもの。除外項目によって、求められていない機能まで設計が膨らむのを防ぎます。

短い番号付きリストで示します。要件とモジュールの対応関係は、モジュールができた段階で小さな表にまとめるとよいでしょう。

エンティティと関係

要件から名詞を拾い出します。変化する状態を持つ、またはルールを適用する名詞はエンティティです。別のエンティティに付随する情報にすぎない名詞は、そのエンティティのフィールドです。これにより、設計が小さなオブジェクトに分割されすぎるのを防げます。

次に、エンティティ間の関係を決めます。どのエンティティがオーケストレーターか、どのエンティティが永続的な状態を所有するか、どれがどれを持つ、使う、または包含するか、そして各ルールをどこに置くかを決めます。

エンティティは短いリストで、関係は矢印(Game -> Board)で示します。形式的な UML は省略し、ボックスと矢印で十分です。

クラス設計

各エンティティをクラスまたはモジュールにします。オーケストレーターからトップダウンで進め、直感ではなく要件から状態と振る舞いを導き出します。

  • 状態:担当する要件を適用するために、保持しておく必要がある情報。
  • 振る舞い:呼び出し元が、そのクラスやモジュールに尋ねたり指示したりできること。それぞれの操作について、返す値と拒否する内容を定め、各メソッドが実際の操作や質問に対応する小さな API にまとめます。

各ルールは、その状態を所有するモジュールに置きます。これが「尋ねるのではなく指示する(tell, don't ask)」という考え方です。「今、実行できるか?」といったライフサイクルのルールはオーケストレーターに置き、「このマスは埋まっているか?」といったデータのルールはデータを保持するモジュールに置きます。そうすれば、何か問題が起きたときに、どのモジュールを確認すればよいかがわかります。layout.md に従って、モジュールをフォルダーに配置します。

フォルダーツリーを示し、各ファイルやフォルダーが何を担当するかを、行ごとにコメントで記載します。

実装

すべてのメソッドではなく、ロジックを担うメソッドをスケッチします。まずは正常系を示し、その手順、他のモジュールへの呼び出し、変更する状態を記述します。次に、無効な入力、許可されていない操作、誤った状態での呼び出しなどのエッジケースを扱います。プロジェクトで実際のコードが必要な場合を除き、擬似コードを使います。

その後、具体的なシナリオを一つ、各手順の後の状態とともに順を追って検証し、さらに拒否されるケースを一つ確認します。状態が設定されていない、ルールの確認が遅すぎるなど、トレースで見つかった問題を修正します。

所有するファイル名を各呼び出しの横に記載し、トレースしたフローを呼び出しツリーとして示します。

拡張性

次に起こりそうな変更を列挙し、それぞれについて、その変更を吸収する設計上の箇所と、変更内容を示します。すべての状態変更を一か所に集約する設計なら、元に戻す機能のような追加にも、構造を組み直さず対応できます。新しいファイル一つと登録だけで対応できる変更は、すでに吸収できています。同じ編集を複数のファイルで繰り返す必要がある変更には、拡張のための境界が必要です。現在の要件で必要のない変更に備えた設計は避けます。

変更内容を、小さな「変更 → 変更箇所」の表で示します。

提示と改訂

/show-me を読み込み、各段階を視覚的に提示し、選択理由だけを文章で説明します。

  • デザインの現行バージョンを1つ維持し、最初からやり直すのではなく改訂します。
  • 各改訂の冒頭で、変更内容とその理由を、変更したツリーまたはリストの変更前/変更後の diff として示し、その変更が影響するすべての箇所に反映します。
  • ユーザーが決定した点は、ユーザーが再び取り上げない限り変更しません。
  • デザインに妥当な選択肢が複数ある場合は、各選択肢のコストとともに番号を付けて並べ、推奨案を最初に示します。
  • コード、仕様、プロジェクトのドキュメントでは解決できないことだけを、一度に1つずつ質問します。それ以外は判断し、決定内容を伝えます。

デザインの保持

何をどこに保持するかは、ユーザーが決定します。デザインを調整している間は、リポジトリの規約に従い、プロジェクトの一時フォルダーまたはスクラッチフォルダーに下書きとして保存します。そうしたフォルダーがない場合は、保存先を尋ねます。説明は会話内に残してもかまいません。ユーザーが同意し、デザインを保持したいと望んだら、プロジェクトのドキュメントに記録します。ドキュメントを新たに追加するのではなく、既存のデザインドキュメントを更新し、プロジェクト内のデザインドキュメントを1つに保ちます。冒頭では新しいメンバーが最初に知っておくべきことを示し、その後、各段階に個別のセクションを設けます。

参考資料

原則、概念、パターン
参考資料内容
design-principles.mdKISS、DRY、YAGNI、関心の分離、デメテルの法則、SOLID
oop-concepts.mdカプセル化、抽象化、ポリモーフィズム、継承、コンポジション
design-patterns.md生成、構造、振る舞いに関するパターンと、それぞれが過剰な設計になる場合
layout.mdフォルダー、汎用コードとビジネスコード、命名、ファイルを分割するタイミング

出典:Hello Interview、Introduction、Delivery Framework。

コメント