ツールとオーケストレーターを分ける — 個人用ソフトウェアエコシステムの設計原則

個人で使うソフトウェアは、年単位で増えていきます。最初は単独のスクリプト。次に、少し凝った CLI。やがて GUI を持つ、完成度の高いツール。そして、それらを束ねた一連の処理。こうして層を重ねて育つうちに、いつのまにか 「自分用ソフトウェア・エコシステム」 と呼べる規模になります。

この成長の途中で、見落とされやすい設計判断があります。エコシステムを構成する要素は、二つの異なる層に属している、という認識です。一つは、個別の問題を解く ツール層。もう一つは、ツール群を組み合わせて、目的の作業の流れを成り立たせる オーケストレーター層 です。この二つを意識して分けておくと、エコシステムは長持ちし、組み合わせやすくなります。

この分離は、本サイトの基礎記事 決定論的にではなく、相対的に で述べた 媒介性 を、エコシステムの規模で実装したものです。道具は目的と作業の「あいだ」に立つ媒介物で、何が見えるか・何ができるか・何が考えやすいかを決めます1。ツールを単一責務に閉じるのは、その道具が媒介する範囲を、わざと絞ることです。そうすれば、決まってくる「思考の形」を予測でき、差し替えもできます。エコシステムの設計とは、コードを書くことではなく、どこに媒介の境界を引くか を決めることです。この見立てが、本稿全体を通っています。

本稿では、この設計原則をはっきり言葉にします。そのうえで、個人用の道具立てでの実装パターンと、筆者自身のオープンソース・エコシステム2 を例にした具体的な構造を整理します。

二つの層の定義

ツール層とオーケストレーター層は、責務とインターフェースではっきり分かれます。

ツール層:
– 単一責務 ── 「動画にチャプターを刻む」「スライド画像の台形歪みを補正する」「LuaTeX で組版する」のような、一つの明確な目的を持つ
– データ形式の持ち主 ── 自身が出力する形式 (.vce.json / 補正済み PNG / PDF など) の正本を持つ
– 独立リリース ── バージョン番号、リリースサイクル、依存関係を、それ自身で管理する
– 配布経路の独立 ── pip 単独パッケージ、独自バイナリなど、配布チャネルが他ツールに従属しない

オーケストレーター層:
– 組み合わせが責務 ── 既存ツール群を データの流れで束ねて 目的を達成する
– ツール群を依存として呼び出す ── pip 依存、subprocess、CLI 呼び出しのどの形でも、ツールの実装を自分で抱え込まない
– 作業の流れの論理を担う ── 段階の順序、条件分岐、エラー処理、リトライ、ログを受け持つ
– 薄く保つ ── 厚くなるのは、ツール層を複製し始めたサイン。その時点で分け直す

両層の境界は、標準化されたデータ形式 で引きます。SRT、PNG、PDF、JSON、YAML。こうした長く安定した既存の形式が 層と層の境界 (インターフェース) として働いているかぎり、ツール層は自由に差し替えられます。オーケストレーター層も、実装言語を気にせずにツールを呼べます。

なぜ分離するのか

分けることの利点は、四つあります。

第一に、置換可能性。ツール層が独立していれば、ある段の実装を別のものに差し替える手間は最小で済みます。たとえば文字起こしツールを Whisper から別のモデルに切り替えるとき、オーケストレーター側は SRT という共通形式しか見ていません。だから、ツール層を差し替えるだけで済みます。これは、「正解のツール」を一つに決め打ちする設計とは逆向きです。媒介物は、他者の都合や技術の進歩で変わりえます。だから特定の道具に固定するのではなく、境界 (SRT) を固定して、道具のほうを相対的に差し替えられるようにしておく。決定論的にではなく、相対的に という態度が、最も具体的な形で現れたものです。

第二に、並行発展。ツールがそれぞれ独立したリポジトリにあれば、別々のリリースサイクルで進化できます。GUI の改良、フォーマットのバージョンアップ、性能チューニング。どれも、他のツールに影響を与えずに進められます。構造に余裕が生まれるのです。

第三に、外部再利用。各ツールは、元の作業の流れの外でも、単独で使えます。perspective-corrector は、会議録パイプラインの一部であるだけではありません。スマホで撮ったホワイトボード写真を整える、独立したアプリとしても役に立ちます。単一責務を徹底すると、思いがけない場面での再利用が生まれます。

第四に、保守責任の分散。オーケストレーター層は薄くなり、ツール層も単一責務に閉じます。どちらの保守も、層を混ぜた一枚岩を抱え続けるより、頭の負担の面でも、コードの面でも軽くなります。

インターフェースは標準を尊重する

両層の境界を引くデータ形式の選び方には、本サイトの既掲記事 記録を標準化する で論じた原則が、そのまま当てはまります。個別ツールが標準を発明するのではなく、既存の標準を尊重して繋ぐ、という原則です。

データの性質 採用する標準形式 理由
字幕・タイムコード付きテキスト SRT 1990 年代から定着、Whisper はじめあらゆる音声認識ツールが標準出力
画像 (整形済みスライド等) PNG / JPEG 仕様公開、複数実装、長期可読性
構造化メタデータ JSON / YAML 言語非依存、可読、git と相性がよい
組版可能ソース LaTeX / Markdown 開放形式、複数実装、30 年級の安定性
配布物 PDF/A ISO 19005 規格、長期保存設計
動画チャプター YouTube チャプター記法 / .vce.json 広く受容済み / プロジェクト固有

新しい形式を発明するのは、既存の標準では表現できない情報モデルを扱う場合に限定 します。これが境界設計の規律です。.vce.json は、数少ない例外です。チャプター + ソースファイル境界 + エンコーダ設定という video-chapter-editor 固有の情報モデルが、既存の形式に収まりません。そのため、新しく定義することを選びました。

ツール選定 ── 単一責務を徹底する

ツール層に属するソフトウェアの設計判断は、Doug McIlroy が 1978 年に Bell System Technical Journal で示した命題に集約されます3。

Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new “features”.

現場での使い方は単純です。あるツールに新機能を足したくなったら、新ツールとして独立させたら何が困るか を問います。困らないなら、独立させます。McIlroy の命題を実務の言葉に直すと、こうなります。

筆者がいま保守しているツール群を、この判断軸で整理すると次のようになります。

ツール 単一責務 所有する形式
video-chapter-editor 動画にチャプターを刻む / 編集する .vce.json (チャプター + 境界 + エンコード設定)
perspective-corrector スライド写真の台形歪み補正 補正済み PNG / A4 PDF
luatex-docker-remote リモート Docker 経由の LuaTeX 組版 入力 LaTeX → 出力 PDF

それぞれが「何をするか」を一行で言えること。これが単一責務の目安です。一行で言えなくなったら、二つのツールに分けるときです。

オーケストレーター層の実装

オーケストレーター層を何で書くかは、「Python か zsh か YAML か Makefile か」と、答えを一つに絞る形で問われがちです。けれども実際には、それぞれが異なる層で最も枯れた道具 です。共存させて、使い分けるのが筋です。

言語 / ツール 強み 役割
Make 1979 年以降の POSIX 標準4。ファイル間依存の宣言 + 冪等な 実行 パイプライン全体の骨格 (依存関係のグラフ)
Python テスト・デバッグ・例外処理・型ヒント。複雑な変換・分岐ロジック Make では辛い処理 (テンプレ生成、メタデータ変換)
YAML 宣言的、言語非依存、git と相性がよい 人手編集する設定 (エンコーダ設定、プロファイル)
zsh / POSIX shell コマンドを繋ぐ最も自然な記法 シェルラッパ、エイリアス、簡易ランナー

外部のワークフロー基盤 (n8n、Argo Workflows 等) の本来の用途は、サービス横断の統合 + イベント駆動 です。一直線の CLI パイプラインには過剰です。そうした基盤への依存を背負うのは、本サイトの既掲記事 腐らない資産を設計する で論じた 30 年級の耐久性から離れる選択でもあります。

典型的な Makefile (5 行で骨格が立つ):

report.pdf: report.tex
    luatex-pdf $<

report.tex: subtitles.srt slides_corrected/
    msw-report --srt subtitles.srt --slides slides_corrected/ -o $@

subtitles.srt: $(RECORDING)
    yt-srt $< -o $@

slides_corrected/: $(SLIDES_DIR)
    perspective-corrector $< -o $@

make report.pdf 一発で、足りない分だけが走ります。入力に変更がなければ、スキップします。オーケストレーター層の本質は、既存の優秀なツールをファイル依存で繋ぐこと です。それが、Make の 47 年安定した動作規約にそのまま乗ります4。複雑なロジックや条件分岐、API 呼出しが要るところは、Python に切り出す。設定値は YAML に外出しする。こうして層を重ねていけば、オーケストレーター自体でも「書かない設計」が成り立ちます。

現状から目指す構造へ

media-scribe-workflow は現状、ツール群とオーケストレーターが同じリポジトリの中に混在しています。GUI (media_scribe_workflow/ui/)、エンコード CLI (vce-*)、ユーティリティ群 (yt-srt、video-trim、video-chapters)、レポートパイプライン (msw-*) が、一つのパッケージに同居している状態です。

目指す構造は、次のとおりです。

独立ツール群 (各リポジトリ):
  - video-chapter-editor      (GUI + .vce.json 形式の持ち主 + vce-encode/split)
  - perspective-corrector     (画像補正、既)
  - luatex-docker-remote      (組版環境、既)
  - (将来) subtitle-utils      (yt-srt 等の小ツール)

オーケストレーターのリポジトリ:
  - media-scribe-workflow     (上記ツール群を pip 依存として呼ぶ薄いオーケストレーター)
    ├─ Makefile               (依存関係のグラフ=骨格)
    ├─ msw_pipeline/          (Python 補助 ── テンプレ生成、メタデータ変換)
    └─ profiles/*.yaml        (人手編集する設定)

移行の手順には、王道があります。git subtree split で、video-chapter-editor のコミット履歴を保ったまま新しいリポジトリに切り出します。共有モジュール (pipeline.srt_parser、utils の数本) は、共通ライブラリにするか、各リポジトリに複製します。一度に全部やる必要はありません。まず video-chapter-editor を分離し、運用しながら共通モジュール化の判断を積み重ねていけば、段階的にたどり着けます。


ここからは、この設計原則を、本サイトの既掲記事とのつながりで読み直してみます。

ツールとオーケストレーターの分離は、本サイトで論じてきたいくつかの主張の 構造的な統合点 です。

  • 決定論的にではなく、相対的に で宣言した態度は、道具を「正解の手順」にせず、媒介する範囲を明示して、状況に応じて差し替えられるようにすることでした。その最も構造的な実装例が、この二層分離です。境界 (= 媒介の範囲) を固定し、道具を相対的に置く という形で、全篇を貫いています
  • 偉大なプログラマは優秀なプログラマのコードを利用する で扱った再利用の原則は、オーケストレーター層が「書かない」を最大にするための設計原理として働きます。Whisper / Claude / LuaTeX / ffmpeg / Qt は、どれも他者が長く保守してきた優秀なコードです。オーケストレーターは、それらを束ねる接続部だけを書きます。これは「自分が書かない部分の媒介を、他者の優秀な実装に委ねる」という、媒介の選択でもあります
  • 記録を標準化する で論じた段階間の受け渡しの取り決めは、ツール層とオーケストレーター層を分ける境界そのものです。標準形式 (SRT、PDF/A、JSON) を尊重すれば、両層の置換可能性が保証されます。同時に、検証 (Verification)、つまり隣り合う二つの段階が一致しているかの差異検出も、機械的に行いやすくなります
  • 腐らない資産を設計する で示した 30 年級の耐久性は、ツール層が単一責務に閉じ、オーケストレーター層が枯れた基盤 (Make、POSIX、Python) に乗るとき、そのまま実現されます
  • Git の 陶器 (porcelain) と配管 (plumbing) 5 の分離は、本稿の主題そのものを、コマンド・ライン・ツールの世界で先取りした設計と言ってよいでしょう。「陶器」がオーケストレーター (人間に磨かれた表面)、「配管」がツール群 (機械的接続部) で、両者が安定した境界で結ばれています

エコシステムの設計は、コードを書くことではなく、媒介の境界を引くこと です。どこを単一責務に切るか。どの形式を共通の境界にするか。どの層で「書かない」を徹底するか。こうした判断が、年単位で積み上がる個人用ソフトウェアを 構造的に維持可能なエコシステム に変えます。ここが設計の核心です。オンライン講座の文脈でいえば、この境界設計の判断の過程こそが、特定のツールの操作よりもはるかに長く生きる教材になります。

参考文献


  1. 媒介性 / 差延 / 検証と妥当性確認 (V&V) の非対称性 の操作的な定義と理論的な扱いについては、本サイトの基礎記事 決定論的にではなく、相対的に の脚注、および著者の Zenodo プレプリント・シリーズ (レター版 DOI: 10.5281/zenodo.20096462) を参照。 ↩

  2. 本稿の例として参照しているオープンソース・ツール群:
    – mashi727/media-scribe-workflow ── 会議記録の自動化パイプライン (現状はオーケストレーターとツールが混在)
    – mashi727/perspective-corrector ── スライド写真の台形歪み補正 (独立済)
    – mashi727/luatex-docker-remote ── リモート Docker 経由の LuaTeX 組版 (独立済) ↩

  3. McIlroy, M. D., E. N. Pinson, and B. A. Tague. “UNIX Time-Sharing System: Foreword.” The Bell System Technical Journal, vol. 57, no. 6, July–August 1978, pp. 1899–1904. ── “Make each program do one thing well. To do a new job, build afresh rather than complicate old programs by adding new ‘features.’“ ↩

  4. Feldman, Stuart I. “Make — A Program for Maintaining Computer Programs.” Software: Practice and Experience, vol. 9, no. 4, April 1979, pp. 255–265. ── 1979 年に発表された Make の原典論文。ファイル依存の宣言と差分実行の組合せという設計が、47 年経過した現在も POSIX 標準として使い続けられている。 ↩↩

  5. Chacon, Scott, and Ben Straub. Pro Git, 2nd ed., Apress, 2014, Chapter 10 “Git Internals”. https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain ── porcelain / plumbing 用語の出典。 ↩