作るべきものと向き合う ── ecspressoに見る、「やらないこと」を決める技術選定のトップ画像

作るべきものと向き合う ── ecspressoに見る、「やらないこと」を決める技術選定

投稿日時:
藤原 俊一郎(fujiwara)のアイコン

さくらインターネット株式会社 / ソフトウェアエンジニア

藤原 俊一郎(fujiwara)

Xアカウントリンク
本記事では、2026年2月26日に開催されたオンラインイベント「技術選定を突き詰める Online Conference ――逆境を乗り越える意思決定プロセス」内のセッション「作るべきものと向き合う」の内容をお届けします。

同セッションでは、さくらインターネット株式会社のfujiwara(@fujiwara)さんが登壇。Amazon ECSのデプロイツールecspressoの8年間にわたる開発を題材に、技術選定における設計判断の積み重ねと失敗からの改善プロセスについてお話しいただきました。ぜひ本編のアーカイブ動画とあわせてご覧ください。


fujiwara:これからお話しする「ecspresso」は、Amazon ECSのデプロイツールです。2017年11月に開発を始めてから、8年間ずっとメンテナンスを続けています。

今回のタイトルは「作るべきものと向き合う」ですが、このトークには前編にあたるものが2つあります。1つは昨年の設計ナイトで発表した「設計思想に至る道」、もう1つはYAPC::Fukuokaで発表した「正しい抽象の探求」です。

今回はこの2つの続編、そして完結編として技術選定についてお話しします。

ecspressoの特徴と設計思想

ecspressoの特徴は、ECSのサービスとタスク定義のみを管理する点にあります。

ECSのサービスが動くためには、ネットワークのVPCやロードバランサー、データストアも必要になりますが、それらはあえて管理しません。ECSのサービスとタスク定義だけに集中して操作できるようにしています。

この設計思想の背景には、以前のEC2環境での課題がありました。アプリケーション開発とインフラ管理が分かれている環境では、1つのEC2上で動作しているNginxやFluentdのようなミドルウェアをどちらが管理するかが難しく、作業が衝突することがあったのです。これを避けるため、ECSを導入した際に責任分界点を明確に分けました。ECSの上はすべてアプリケーションのデプロイ担当者が行うようにし、この時につくられたのがecspressoです。

ツールが責任を分担し、「ここはやらない」と決まっている方が、変更頻度の高いアプリケーションをデプロイする際に都合が良いと感じています。インフラを誤って変更する事故を防げるためです。

ecspressoの設計思想

正しい抽象化の探求

次に、「正しい抽象化の探求」というテーマについてお話しします。IaCツールとしてどのような抽象化レベルを選択するかという話です。

対比として挙げたいのが、AWS公式のECSデプロイツールである「AWS Copilot CLI」です。AWS Copilot CLIは独自の概念でECSや周辺リソースを一括で作成してくれるツールですが、5年間運用された後、2025年2月にメンテナンスが終了しました。

AWS Copilot CLIの抽象化がもたらした制約

AWS Copilot CLIは1つのYAMLファイルを書くだけでデプロイできるオピニオネイテッドな設計で、裏側でCloudFormationが自動生成されます。しかし、抽象化されているがゆえの制約がありました。

たとえば、ECSは1つのサービスに内部用と外部用の複数のロードバランサーを付けられます。しかしAWS Copilot CLIのDSL構造は、1アプリケーションにつき1ロードバランサーと強く結びついていたため、最後まで複数ロードバランサーをサポートできませんでした。また、対応していないリソースを使いたい場合はCloudFormationのテンプレートを自分で書く必要があり、複雑なことをやろうとすると制約が大きくなってしまいます。

世の中のあらゆるアプリケーションパターンを1つのYAMLファイルで網羅することは非常に難しいです。結果的にAWS Copilot CLIはメンテナンスが止まってしまいました。AWSが発表したサポート終了の記事でも、独自構文による学習コスト、可視性や拡張性の制約、トラブルシューティングの難しさについて触れられています。

ecspressoが採用した抽象化レベル

対照的に、ecspressoは抽象化レベルを意図的に絞っています。ECSのデプロイという操作は抽象化しており、複数のAPIを順番に実行する処理を1つのコマンドで実行できるようにしています。また、ロールバック機能のエミュレートや、変更差分を確認するdiff機能、デプロイ前に外部リソースの権限などを検証するverify機能といった便利な操作も抽象化して組み込んでいます。

ecspressoが採用した抽象化レベル

一方で、構造の抽象化は意図的に行っていません。AWS SDKのJSONをそのまま扱えるようにしています。これにより、ECSに新しい機能が追加されてAPIの構造が変更されても、ツールを大きく更新することなくそのまま新機能に対応できるというメリットがあります。ドキュメントもAWS公式のものを読めばそのまま使えるため、更新追従のコストが非常に低いです。

抽象化は難しく、「漏れのある抽象化の法則」という有名な概念がある通り、すべての非自明な抽象化には必ず漏れが生じます。AWS Copilot CLIのように高度に抽象化すると、隠された機能にアクセスするために結局ユーザーがCloudFormationを書かなければならない事態が起きてしまいます。

何を抽象化し、何を抽象化しないかを決めること、つまりやらないことを決めることが大切です。境界を見極めて、ここは抽象化せずに具象のままで良いという判断をすることが、少ないコストで長くメンテナンスを継続できるソフトウェアを生み出します。

ecspresso 設定ファイル記法の7年

とはいえ、ecspressoの判断がすべて成功したわけではありません。JSONに動的な値を注入するという小さなひとつの課題をめぐっても、小さな失敗と改善の歴史があります。

JSON+テンプレート記法の採用と衝突

設定ファイルの一部を書き換えるために、当初はGoの標準パッケージtext/templateを採用しました。単純に文字列を展開できれば良いと考えていたのです。しかし、これには課題がありました。

ecspressoの設定ファイル文法

たとえば、タスクの起動数を指定するdesiredCountは数値であるため、ダブルクォーテーションで囲めません。そこにテンプレート記法を直接書くと、JSONとしては壊れた状態になります。動くことは動くのですが、エディタの自動整形が機能しなくなるなどの不便さが生じました。ただし、大抵のユースケースでは文字列内に展開できれば十分だったため、致命的な問題ではありませんでした。

Jsonnet 導入と新たな制約

その後、JSONは人間にとって書きづらく、共通要素のインクルードなどもできないため、2020年頃にJSONを生成するための言語であるJsonnetを導入しました。最初は外部コマンドでJsonnetをJSONに変換してから読み込んでいましたが、2021年にgo-jsonnetをecspressoに組み込み、外部コマンド不要で直接処理できるようにしました。

しかし、Jsonnet化してもテキストテンプレートとの相性問題は解決しませんでした。むしろ制約が増えてしまったのです。Jsonnetは先に評価を行うため、テンプレート記法が含まれていると構文エラーになります。逆に不便なユースケースが増えてしまいました。

解決しないどころかJsonnet化で制約が増えた

回避策として、Jsonnetのext-strext-codeといった外部引数機能を使えば対処はできました。きれいではないものの、致命的ではなく回避できる範囲の制約でした。

Jsonnet native functionによる完全解決

この問題が解決したのは開発から7年経った最近のことです。2024年のv2.4で、Goの関数をJsonnet内で呼び出せるnative function機能を導入しました。これにより、テンプレート関数をすべてJsonnetの関数としても提供できるようになり、テンプレート記法を使わずに環境変数を読み出して数値に変換できるようになりました。

なぜこのような制約が生じたのか。最初にテキストのテンプレートで十分だと、課題を軽く見ていたからです。はっきり言えば舐めていました。世の中にはJsonnetやCue、HCLといった設定記述言語が多数存在しています。設定を記述するための言語の設計は複雑な問題であり、テキストテンプレートエンジンで簡単に解決できるものではなかったのです。

そもそもなぜこの制約が生まれたのか

ただし、これもトレードオフです。最初からJsonnetを強制していたら、学習コストの高さからユーザーに使ってもらえなかった可能性があります。リリース当時のecspressoはとてもマイナーなツールで、マイナーなツールに学習コストを割いてくれるユーザーは多くありません。「JSON + テンプレート記法」の組み合わせは誰にでも分かりやすかったため、知名度の低いツールとして普及に貢献した側面もあります。

致命的でなければ回避策を用意して改善し続けることができます。選択の結果を引き受けて、正解に近づけていく営みが重要だと考えています。

8年かけて磨いたものは何か

ecspressoの8年間で蓄積されたのは、コードだけではありません。操作範囲をECSに限定する、AWS SDKのJSON構造をそのまま扱う、構造は抽象化せず操作は便利に抽象化する。

こうした「何をやり、何をやらないか」という設計判断こそが、本当の資産です。

最近、ecspressoの設計思想やインターフェースを参考に、AWS Batch用のデプロイツールであるbatchaをつくったというブログ記事を見かけました。

ECSにおけるecspressoと同じように、AWS Batch向けにコマンド体系や関連機能を移植してつくられています。驚くことに、そのツールのコードはほぼClaude Codeが書いたものだそうです。作者は設計の方向付けと調整に徹したと述べていました。

私自身もlambrollなどのOSSを同じ設計パターンでつくってきましたが、この設計パターンが有用であることは過去8年間で実証されています。設計や方針がしっかり言語化されていれば、AIに「この通りにつくって」と指示するだけで、別サービス向けのツールを簡単につくれる時代になりました。逆に、言語化されていないものをAIにつくらせても、本当に使いやすいものができるかは分かりません。

まとめ

やはり「やらないこと」を決めることが、設計では非常に重要です。できることが多ければいいわけではなく、なんでも抽象化すればいいわけでもありません。境界を見極め、抽象化の範囲を明確に定めて言語化することが大切です。何でもできるように機能を追加したり、安易に抽象化してしまうと、細かい部分にアクセスできなくなり後々大変なことになります。

技術選定は初手で正解を当てなくても良いですが、致命傷は避ける必要があります。最初の選択で間違うこともありますし、結果的にそれが良かったということもあります。向き合い、改善し続けることが重要です。

そしてAI時代においては、設計を言語化できれば実装はAIに任せることができるようになってきました。だからこそ、「作るべきもの」を見極める力がより重要になってくると考えています。

アーカイブ動画・発表資料

イベント本編は、アーカイブ動画を公開しています。また、当日の発表資料も掲載しています。あわせてご覧ください。

▼動画・資料はこちら

※動画の視聴にはFindyへのログインが必要です。