mcpField
U
uncomplect

uncomplect

github.com/joelhooks開発3787 回インストール5 日前に更新
リポジトリ

uncomplect について

開発者やコーディングエージェント向けに、置き換えを前提としたソフトウェア設計を導く推論スキルです。コードや実行時の証拠に基づき、関心事の分離、複雑さの削減、モジュールの交換可能性を重視します。

主な機能

  1. 01コード、テスト、実行時の証拠に基づく提案
  2. 02絡み合った関心事の整理
  3. 03小さなインターフェースと純粋な決定ロジックの設計
  4. 04置き換え、削除項目、ガードの計画

活用シーン

  1. 01大規模な書き換え前のシステム設計レビュー
  2. 02状態、ポリシー、インフラの結合箇所の特定
  3. 03実証済みの振る舞いを保つ置き換え計画

インストール

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

$npx skills add https://github.com/joelhooks/skills --skill uncomplect

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

同梱ファイル

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

evals/
benchmark.md
evals.json
trigger-evals.json
references/
resilience-and-durability.md
source-map.md

詳細

もつれを解く

現在のシステムは機能するプロトタイプとして扱います。重要な振る舞いを証明するものであり、その構造が正しかったことを証明するものではありません。振る舞いと根拠は保ち、偶然できあがった構造は手放しましょう。

目標は行数を減らすことではなく、絡み合った関心事を減らすことです。型を追加して特殊ケースを3つ削除する置き換えは、よりシンプルです。レイヤーを追加して何も削除しない置き換えは、そうではありません。

まず読む

コードについての推測に基づく提案は、存在しないシステムを修正しがちです。ですから、提案はすべて、実際に読んだ内容に基づけてください。プロジェクトに最も近い指示、決定事項、ソースコード、テスト、実行時の記録、現在発生しているインシデントから読み始めます。

状態機械のコードでは、機械、永続化された状態、復元経路、呼び出されるアクター、ガード、遷移テストを読みます。エフェクトシステムのコードでは、プロジェクトで固定されているバージョンと、既存のサービス、エラー、再試行、トランザクションの境界を読み、API がそのバージョンのソースと一致するか確認します。

すべての提案について、根拠となる事実、維持する振る舞い、削除する複雑さを明示できたら完了です。

Hickey:絡み合ったものを分離する

複雑化とは、独立した2つの関心事が織り合わされ、どちらも単独では変更できなくなることです。それらを表にまとめます。

関心事何が絡み合っているか?独立した値分離の方法

よくある絡み合い:

  • 値と時間が混在している;
  • 識別情報と変化する状態が混在している;
  • 振る舞いとストレージまたはトランスポートが混在している;
  • 振る舞いと、それにアクセスするインターフェースが混在しているため、CLI、HTTP ルート、エージェントツールごとに同じルールを書き直している;
  • ポリシーとメカニズムが混在している;
  • 現在の真実と過去の事実が混在している;
  • ライフサイクルの状態とドメインデータが混在している;
  • 再試行ポリシーと業務上の失敗が混在している;
  • 1つの汎用ステータスが、異なる事実を覆い隠している。

不変の値と純粋関数を優先します。入力、出力、失敗を型で定義して振る舞いを一度だけ定義し、その定義から各インターフェースを導きます。過去の事実はそのまま真実ですが、報告するものであり、次に何が起きるかを決めるものではありません。

Ousterhout:奥行きのあるインターフェースを作る

奥行きのあるモジュールは、小さなインターフェースの背後に難しい問題を隠します。設計は、変更の波及範囲、認知負荷、未知の未知によって評価します。

提案する型、状態、サービス、インターフェース、設定値ごとに、次の点を確認します。

  1. この要素はどのような複雑さを取り除くか?
  2. 小さなインターフェースの背後に難しい問題を隠せるか?
  3. API によって、偶発的なエラーや特殊ケースを存在しないものにできるか?
  4. 複雑さを1つのモジュールに集約するか、それともポリシーを呼び出し側に広げるか?
  5. これを追加した後、何を削除できるか?

依存関係や不明瞭さを取り除かずに名前だけ増やすインフラは、システムを読みにくくします。そのため、取り入れないようにします。

影響の大きい置き換えでは、設計を2通り行います。実質的に異なるインターフェースを2つスケッチし、選択する前に、呼び出し側の負担、隠れた知識、依存関係、失敗の意味、そしてそれぞれが削除するものを比較します。

Young:削除を最適化する

Greg Young のソフトウェアを破壊する技術は、モデルが現実に合わなくなったときに置き換えられる、小さなプログラムを提唱しています。置き換えを安価にできるのは、単位が必要なものをすべて内包し、ほかのものがその内部に立ち入らない場合に限られます。

次の点を確認します。

  1. このモジュールは、契約、テスト、記録をもとに、およそ1週間以内で書き直せるか?
  2. できない場合、どの依存関係、隠れた不変条件、共有状態が置き換えを危険にしているか?
  3. この単位は設定、ストレージ、インフラを自ら管理しており、これを削除すればそれらもすべて削除されるか?
  4. これを取り外しても、残りはビルドでき、使っていた箇所すべてをコンパイラーが示してくれるか?
  5. 同じ接続点の背後で、新しい実装を古い実装と並行して動かせるか?
  6. 切り替え後に、何を削除できるか?

1週間という期間は、プレッシャーテストです。小さく置き換え可能な単位は、1つのプロセスと1つのリポジトリを共有できます。サービスを分割するかどうかは別の判断です。

DDD:適切な境界に権限を置く

ストレージの用語ではなく、ドメインの用語で境界づけられたコンテキストとその信頼境界に名前を付けます。

次の点を特定します。

  • 各不変条件を所有する集約。
  • 不変の事実と、現在の判断。
  • コマンド、イベント、ポリシー、読み取りモデル。
  • 上流と下流の契約の所有者。
  • コンテキスト境界での変換。
  • 複数のドメイン上の意味を隠している用語。

読み取りモデル(DDDのプロジェクション)は判断を報告できますが、不変条件を所有する集約だけがその判断を下します。ダッシュボードやキャッシュが判断を始めると、真実を所有する場所が2つになります。

ワークフローは、明示的なイベントを生み出すコマンドと現在の事実としてモデル化します。純粋なワークフローはイベントを返し、イベントの公開と永続化はそれぞれ独立した作用です。

型付きエフェクト:純粋なコアを純粋に保つ

エフェクトシステムは、エフェクトが必要な境界でこそ力を発揮します。純粋なルールをエフェクト構文で書くと、実際以上に高度に見え、単純さが隠れてしまいます。

  • ドメイン上の判断は、タグ付きの値を扱う純粋関数として保ちます。
  • 信頼できない入力は境界でデコードし、内部では解析済みのドメイン型だけを扱います。
  • データベース、ネットワーク、ファイルシステム、時計、設定、プロバイダーとの処理は、名前付きサービスの背後に置きます。
  • 予測可能な失敗は型付きエラーとしてモデル化し、欠陥とは分けます。
  • 再試行するのは、型付きの一時的な失敗に限り、操作が冪等であると証明できる場合だけにします。
  • 権威あるデータベーストランザクションの外でプロバイダーを呼び出します。
  • 1つのワークフローでは、エフェクトシステムのバージョンを1つに揃えます。

この境界で互換性のあるエフェクトシステムがプロジェクトにない場合は、言語標準のコードを使うほうがシンプルです。簡素化として提示されるフレームワークの移行は、別のプロジェクトです。

ライフサイクル:重要な時間を見えるようにする

モードによって許可されるイベントが変わる場合や、作業にキャンセル、再試行、再開、子タスクが必要な場合は、明示的な状態機械を使います。解析、検証、一度限りの移行には通常の関数を使います。

  • 状態は、許可されるイベントが異なるモードを表します。
  • コンテキストには、状態ラベルの複製ではなく、最小限のアクターデータを保持します。
  • ガードは純粋かつ同期的にします。
  • エフェクトは、呼び出されるアクターまたは境界サービスに置きます。
  • 永続化された状態は、現在の権威を持つ前に正規化します。
  • 一時的な計算に永続状態は必要ありません。
  • 復元テストでは、バージョン境界とデプロイ境界をまたいで検証します。

クラッシュからの復旧、配信の繰り返し、過負荷、リプレイには、回復性と耐久性に関する用語を使います。実行、永続化された状態、安全な繰り返し、復旧の責任を分けておきます。

検証済みのドメイン値を受け取る小さな状態機械のほうが、生の行を解釈する大きな状態機械より優れています。

エージェントに適したコンテキスト:分離を定着させる

エージェントは、見つけたパターンをコピーします。分離がレビュアー1人の頭の中にしかなければ、次の変更でまた絡み合います。Lauren TanのDuneは、「近道、つまり簡単な道こそが、エージェントにとって正しい道」であるように作られています。修正を置く場所について彼女が示す段階は、難しい順に、コードベース、静的解析、ルール、スキル、スタイルガイドです。

提案する分離ごとに、次のことを行います。

  1. フォルダー、パッケージ、型など、それぞれの関心事を名前付きの場所に置きます。そうすることで、コードがどこで実行されるか、どのインポートが許可されるかがツリーから分かります。
  2. 対応できる最も上位の段階を選びます。まず、絡み合ったコードを書けなくする型または API を使い、次にリンタールールまたはインポート境界を使い、それから初めて文書化されたルールを使います。
  3. 整備された道筋を1つに保ちます。同じことをする方法が2つある場合は、片方を削除します。

1つのファイルへの小さな編集で、システム全体の正しさが保たれるようにします。それができない場合、エージェントに必要なコンテキストが大きすぎるのであり、それは設計上の問題です。

置き換えの検討

次の順に検討します。

  1. 本質的な振る舞い:プロトタイプが何を実証しているか、また維持すべきものは何か。
  2. 複雑性の対応表:現時点で何が絡み合っているか。
  3. ドメインマップ:コンテキスト、集約、不変条件、コマンド、イベント、読み取りモデル。
  4. 深い継ぎ目:避けられない複雑さを隠せる、最小の公開操作。
  5. 副作用の境界:純粋なコア、型付きエラー、副作用のあるアダプター、トランザクションの境界、リトライの責任者。
  6. ライフサイクル:時間を明示できる、最小の状態機械。
  7. 書き換えの見通し:この単位を約1週間以内に置き換えられない要因。
  8. 削除リスト:置き換えによってなくなる状態、フラグ、例外、運用者の手順、モジュール。
  9. 境界の固定:各分離が再び崩れないようにする型、リンタールール、または境界。
  10. 導入経路:2つの権威ある情報源を持たずに行う、トレーサー、シャドー比較、切り替え、ロールバック。
  11. 未知事項の台帳:既知の事実、既知の未知、未知の既知、未知の未知と思われるもの。

これは推論のチェックリストです。1つの表や型定義で根拠を示せる項目はまとめ、レビューの規模は判断のリスクに応じて調整してください。

出力

まず、次のいずれか1つの判定を示します。More complicated locally, simpler overall または More machinery, no net simplification。

続いて、ソースに基づく複雑性の対応表、提案するドメイン用語、深いインターフェース1つ、純粋な判断用型、副作用とライフサイクルの分離、旧方式と提案方式の状態数、書き換えの見通し、削除リスト、分離ごとの境界の固定方法、リスクと重要な質問1つを記載します。

何が不可能になり、何が明らかになり、何がなくなるかを報告してください。称賛は不要です。削除リストで根拠を示してください。

簡潔な呼び出し

Treat the current system as a functional prototype, not an architecture to preserve. Keep its proven behavior. Find what is complected. Separate values from time, policy from mechanism, behavior from the interfaces that reach it, and facts from read models. Define accidental errors out of existence. Draw the domain boundaries and aggregate invariants. Keep effects at effectful boundaries and state machines on essential lifecycle. Make each unit carry its own infrastructure so it can be deleted whole. Enforce each separation with a type or lint rule so the next change cannot braid it again. Propose the smallest deep replacement, show what it deletes, and name the remaining unknowns.

ソースマップと各レンズが担う役割については、references/source-map.mdを参照してください。これらの原則に基づくスタックについては、rat-stackを参照してください。

コメント