Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
作るべきものと向き合う - ecspresso 8年間の開発史から学ぶ技術選定 / 技術選定c...
Search
FUJIWARA Shunichiro
February 26, 2026
Technology
1
10
作るべきものと向き合う - ecspresso 8年間の開発史から学ぶ技術選定 / 技術選定con findy 2026
技術選定を突き詰める Online Conference ――逆境を乗り越える意思決定プロセス
https://findy.connpass.com/event/380974/
FUJIWARA Shunichiro
February 26, 2026
Tweet
Share
More Decks by FUJIWARA Shunichiro
See All by FUJIWARA Shunichiro
さくらのクラウドでのシークレット管理を考える/tamachi.sre#2
fujiwara3
1
260
Amazon ECS デプロイツール ecspresso の開発を支える「正しい抽象化」の探求 / YAPC::Fukuoka 2025
fujiwara3
13
9.2k
パフォーマンスチューニングのために普段からできること/Performance Tuning: Daily Practices
fujiwara3
8
6.3k
alecthomas/kong はいいぞ
fujiwara3
7
2.2k
ecspressoの設計思想に至る道 / sekkeinight2025
fujiwara3
12
3.4k
さくらのIaaS基盤のモニタリングとOpenTelemetry/OSC Hokkaido 2025
fujiwara3
3
2.9k
監視のこれまでとこれから/sakura monitoring seminar 2025
fujiwara3
11
5.7k
k6による負荷試験 入門から日常的な実践まで/Re:TechTalk #01
fujiwara3
2
490
困難を「一般解」で解く
fujiwara3
10
4.1k
Other Decks in Technology
See All in Technology
【2026年版】生成AIによる情報システムへのインパクト
taka_aki
0
160
EMから現場に戻って見えた2026年の開発者視点
sudoakiy
1
370
AI活用を"目的"にしたら、データの本質が見えてきた - Snowflake Intelligence実験記 / chasing-ai-finding-data
pei0804
0
270
Intro SAGA Event Space
midnight480
0
140
Agent Skills 入門
puku0x
0
860
"共通化"と"Embed"のブレンドでスケール可能な運用を!M&Aを支えるGENDA SREの実践 / GENDA Tech Talk #3
genda
0
230
生成AI素人でも玄人でもない私がセイセイAIチョットワカルために勉強したこと
wkm2
2
310
Oracle Database@Azure:サービス概要のご紹介
oracle4engineer
PRO
3
800
GoとWasmでつくる軽量ブラウザUI
keyl0ve
0
130
Claude Codeはレガシー移行でどこまで使えるのか?
ak2ie
0
200
Amazon Bedrock AgentCoreでブラウザ拡張型AI調査エージェントを開発した話 (シングルエージェント編)
nasuvitz
2
110
AWSが推進するAI駆動開発ライフサイクル入門 〜 AI駆動開発時代に必要な人材とは 〜/ introduction_to_aidlc_and_skills
fatsushi
7
4.5k
Featured
See All Featured
Digital Ethics as a Driver of Design Innovation
axbom
PRO
1
200
Product Roadmaps are Hard
iamctodd
PRO
55
12k
<Decoding/> the Language of Devs - We Love SEO 2024
nikkihalliwell
1
140
The Limits of Empathy - UXLibs8
cassininazir
1
230
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
190
Agile that works and the tools we love
rasmusluckow
331
21k
Believing is Seeing
oripsolob
1
67
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
340
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
122
21k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
1.9k
Context Engineering - Making Every Token Count
addyosmani
9
680
The Invisible Side of Design
smashingmag
302
51k
Transcript
作るべきものと向き合う ecspresso 8年間の開発史から学ぶ技術選定 2026-02-26 技術選定を突き詰める Online Conference ― 逆境を乗り越える意思決定プロセス 藤原俊一郎
(@fujiwara)
自己紹介 @fujiwara (X, GitHub, Bluesky) @sfujiwara (hatena, mixi2) 2011〜2024 面白法人カヤック
2025-02〜 さくらインターネット ISUCON 優勝4回 / 運営(出題)4回 github.com/kayac/ecspresso github.com/fujiwara/lambroll github.com/fujiwara/apprun-cli
kayac/ecspresso 1050+ Amazon ECSデプロイツール 「エスプレッソ」と読みます 2017/11〜 8年間継続開発中 国内企業で広く利用されている 50名以上のコントリビュータ 普段の開発とメンテはほぼ一人
(GitHub Sponsorsお願いします!) github.com/sponsors/fujiwara
今日のテーマ「作るべきものと向き合う」 今日の話は「設計思想に至る道」 「正しい抽象化の探求」の続編(完結編)です speakerdeck.com/fujiwara3/sekkeinight2025 speakerdeck.com/fujiwara3/yapc-fukuoka-2025
ecspresso の特徴と設計思想 Amazon ECSの管理と操作を行う デプロイ(IaC)ツール deploy rollback status verify diff
scale ... ECS「タスク定義」 「サービス」を AWS SDK / AWS-CLI と同じ構造の JSONで管理 それ以外のリソース(VPC、LBなど)は あえて管理しない
ecspressoの設計思想「操作範囲をECSに限定する」 EC2上での協業で開発とインフラ管理の責任が曖昧になり双方が苦労した経験から 「ECSとそれ以外の管理を分ける」提案 → 結果として生まれたのが ecspresso 責任範囲 システム構成 アプリケーション Consul,nginx,Fluentd...
EC2 OS IAM, VPC, LB, RDS... 👥 カヤック 👥 MSP → 責任範囲 システム構成 ECS App,nginx,Fluentd... IAM, VPC, LB, RDS... 👥 カヤック 👥 MSP 思想として言語化したのは3年後のことなので実は後付け
「ecspressoの設計思想に至る道」とは 教訓:設計とは「どこで切るか」 適切な境界線は組織構成によって異なる 責任範囲と操作する範囲を一致させることが重要 変更頻度が少ないインフラ(VPC, LBなど)は Terraform / CloudFormation などで管理
変更頻度が高いアプリケーション(ECSタスク定義、サービス)は ecspresso で管理 インフラ要素のIDは tfstate, CFn Outputs/Exports, SSM から参照 それぞれの管理はチームが分かれることも多い お互いの変更による影響を最小限に抑え、開発効率と安定性を両立
「正しい抽象化の探求」 IaCツールの抽象化レベルの選択 AWS Copilot CLI ECSを独自概念で包んだツール Application/Environment/Serviceという抽象レイヤーでVPC・ALBなども全て一括管理 最終的には CloudFormation に内部で変換されてデプロイされる
2019年11月リリース、2025年2月メンテナンス終了(約5年) ecspresso AWS SDKのJSON構造をそのまま扱う ECSのリソース以外は管理しない
AWS Copilot CLI Opinionated な設計 サービス全体の関連リソースを manifest(YAML) で一元管理 これだけでECSで動くアプリケーシ ョンをデプロイできる
ALB, VPC, Subnet, NAT Gateway, Security Group...すべて自動作成 最終的には CFn に変換されて実行
ecspresso JSON + テンプレート記法 JSON は AWS SDK と同じ構造 テンプレート記法
{{ }} を使って動 的な値を注入できる {{ must_env }} : 環境変数を参照 {{ tfstate }} : Terraformで作成し たリソースをtfstateファイルから参照 {{ ssm }} : SSMパラメータストア から参照
AWS Copilot CLI の抽象化がもたらした制約 例: (ECSがサポートしている) 複数LBをサポートできない → DSLの構造が1アプリケーション ==
1LBだったため 例: 対応していないリソース、対応していても高度な設定はDSLでは表現できない → CFnテンプレートを直接記述 / 自動生成されたCFnにYAML patch 世の中のすべてのアプリケーションを「簡単に」抽象化するのは不可能 簡単に始められる → 複雑な要件に対応できない、というトレードオフ ECSのアプリケーションが必要とするリソースを全て管理するのは無理 → 究極的には CFn/CDK/Terraform と同じものを別に作ることになる
ecspresso が採用した抽象化レベル 操作は便利に抽象化 deploy タスク定義の登録とサービスの更新、待機を一括で 複数のAPIを実行 ECS Rolling, B/G, CodeDeploy
どのデプロイ方式も同じコマンドで rollback ネイティブなロールバック機能が最近までなかったのを当初から提供 diff タスク定義、サービス定義の差分をわかりやすく表示 verify デプロイ前に妥当性(依存リソースが存在するか?など)をチェック
ecspresso が採用した抽象化レベル 構造は抽象化しない ECSが新しい機能を出してもSDK更新程度の低コストで対応できる 高度な設定にもそのまま対応できる AWSのドキュメントがそのままユーザードキュメントになる ECS以外は管理をしない CFn/CDK/Terraformが作ったリソースのIDを参照する機能を提供 tfstate, CFn
Outputs/Exports, SSM などから参照できる 「ECSの管理、デプロイツール」としての責務を明確に
「正しい抽象化の探求」とは 教訓:なんでも抽象化すればよい、というものではない できることが多ければいいわけではない 抽象化の選択によっては大きな制約を生む 抽象が破れたところからは具象が漏れ出す 何を抽象化し、何を抽象化しないかの判断が重要
ここまでのまとめ — やらないことを決めるのが設計 境界を見極める 抽象化レベルを見極める やらないことを見極めることで、長く使い続けられる、 少ないコストでメンテナンスを継続できるソフトウェアになる
ecspresso 設定ファイル記法の7年 「JSONに動的な値を注入する」という小さな一つの課題 判断に成功してきたように見えるecspressoにも 小さな失敗と改善の歴史がある
ecspressoの設定ファイル文法 デプロイするたびに変わる要素(例: イメージタグ)を注入する必要がある 2017〜 JSON + text/template記法 { "family": "myapp",
"containerDefinitions": [ { "name": "myapp", "image": "myapp:{{ must_env `IMAGE_TAG` }}", ... } ] } 「 『JSONに値を埋めるだけ』 — Go の text/template で十分だね」 github.com/kayac/go-config を作って ecspresso にも採用
テンプレート記法とJSONの衝突 — 文字列の外では壊れる 例: desiredCount (希望するタスクの数) は数値 文字列以外を注入するには "" を外す必要がある
{ "desiredCount": {{ must_env `DESIRED_COUNT` }}, "networkConfiguration": { ... これはJSONとしてはinvalidな構造( {{ ) ecspresso はテンプレート展開 → JSONパースの順で処理するため 動くことは動くがエディタでの自動整形などが壊れる ただし「そこまで致命的ではない」問題 大抵のユースケースでは文字列内に展開できれば十分だったため
2020年 Jsonnet導入による設定ファイル運用の改善 ECSのタスク定義はそこそこ複雑な(大きな)JSON構造 生のJSONで書くのはちょっと辛い 末尾 , やクォートまわり コンテナや環境変数などの定義を共通化したい JSONではincludeや共通化が表現できない 「Jsonnet
を外部コマンドとして使えば良いのでは?」 1. Jsonnetで設定ファイルを記述しておく 2. jsonnet コマンドでJSONファイルを作成 3. ecspressoはJSONを読み込む 2020年ごろからこの運用を始めた(自分もecspressoユーザーなので)
Jsonnet jsonnet.org Google発のJSON生成言語 JSONの上位互換(JSONはそのままvalidなJsonnet) 変数、条件分岐、関数、importによるファイル分割が可能 末尾カンマOK、キーのクォート不要、 // コメントが書ける 評価結果は常にJSON local
name = "myapp"; { family: name, // クォート不要、末尾カンマOK containerDefinitions: [ { name: name, cpu: 256 }, // 変数で値を共通化 ], }
Jsonnet + テンプレート記法 local envs = import 'envs.libsonnet'; // 共通の値の読み込み
{ containerDefinitions: [{ image: "myapp:{{ must_env `IMAGE_TAG` }}", // テンプレートはそのまま使える environment: envs, // 読み込んだ値をここに展開 ↓ jsonnet ecs-task-def.jsonnet > ecs-task-def.json { "containerDefinitions": [{ "image": "myapp:{{ must_env `IMAGE_TAG` }}", "environment": [ {"name": "ENV1", "value": "value1"}, {"name": "ENV2", "value": "value2"}, Jsonnetで共通化や記述の簡略化ができるようになった ただしテンプレート記法はそのまま (Jsonnetには環境変数やtfstateの読み込み機能はない)
2021年 go-jsonnetをecspressoに組み込み (v1.7) google/go-jsonnet をecspressoに組み込んで外部コマンド不要に *.jsonnet はecspresso自身がJsonnetとして読み込んでJSONに変換 → テンプレート展開 →
JSONパース という処理順 外部コマンドが不要になって便利! しかし 「JSONに文字列以外の値を注入する」際の課題は解決していない
解決しないどころかJsonnet化で制約が増えた // これはJSONとしてもJsonnetとしてもinvalid { desiredCount: {{ must_env `DESIRED_COUNT` }} }
最初に Jsonnet として処理されるため、そもそもパースできない=使えない (JSONならテンプレート展開後にパースするので一応動いていたのに) 「文字列として埋めた後に std.parseInt で数値に変換すれば?」 { desiredCount: std.parseInt('{{ must_env `DESIRED_COUNT` }}') } テンプレート展開はJsonnetの「後」なので、最初に std.parseInt でエラー
処理順の比較 — なぜ制約が増えたのか v0 (JSON + text/template) .json → template展開
→ JSONパース {{ }} がinvalidでも展開後はvalid → 一応動く(エディタは壊れる) { "desiredCount": {{ must_env `DESIRED_COUNT` }} } ↓ テンプレート処理 { "desiredCount": 3 } v1.7 (Jsonnet組み込み) .jsonnet → Jsonnet評価 → template展開 → JSONパース {{ }} がJsonnet構文を壊す → パースできない Jsonnet評価が先に来るため、テンプレート記法の制約が悪化した しかし処理順は互換性のため変えられない
「致命傷ではなかった」が、不便ではあった 埋め込みたい値はほとんどのユースケースで文字列なので困る可能性は低い Jsonnet の --ext-str , --ext-code (外部引数機能) を使えば回避はできる ecspresso
deploy --ext-code DESIRED_COUNT=3 ... { desiredCount: std.extVar('DESIRED_COUNT') } きれいではない、不便だが回避はできる制約
2024年 — Jsonnet native functionによる完全解決 (v2.4) go-jsonnetのnative function機能を使い、 テンプレート関数(=Goの関数)をすべてJsonnetの関数としても提供 local
must_env = std.native('must_env'); // Goの関数をJsonnetから呼び出せる { // must_envは環境変数を文字列で返す // std.parseIntは文字列を数値に変換する desiredCount: std.parseInt( must_env('DESIRED_COUNT') ), } Jsonnetの文法で完結するのでテンプレート記法が衝突しない 文字列外への値展開も自然にできるようになった 2017年(v0)→2024年(v2.4) 制約を完全に解消するまでに気がつけば7年
そもそもなぜこの制約が生まれたのか 「 『JSONに値を埋めるだけ』 — Go の text/template で十分だね」←←← 設定ファイルを構築する、JSONに値を埋めるという課題を軽く見ていた はっきりいえば「舐めていた」
世の中には設定記述言語(Jsonnet, Cue, HCL…)が多数存在している 餅は餅屋、JSONに値を埋めるのはそこまで単純な問題ではない テンプレートで自作という選択が小さな制約を生み、完全解決までに7年かかった
選択はトレードオフ 不完全な「JSON + text/template」と完全な「Jsonnet + native function」 しかし最初の選択も、そこまで悪いものでもなかった(と思う) ほとんどのケースではうまく動く 実際今でも
JSON で十分便利に使っている利用者も多い 「JSON + テンプレート記法」は馴染みやすい構文だった リリース当時の ecspresso はとてもマイナーなツール マイナーなツールに学習コストを割いてくれるユーザーは少ない go-jsonnetは2016年〜(初めてタグが打たれたv0.10.0は2018年10月) 2017年のリリース当初はそもそも自分は知らなかった…
失敗と向き合い、改善し続けることが重要 実際はそこまで「大きな失敗」ではない、途中の制約も回避策があった 失敗が致命的であればそもそも生き残っていない可能性も高い とはいえ、技術選定の結果生まれた制約は不便なものであったことも事実 選択の結果を引き受けて、正解に近づけていく営みが重要
8年かけて磨いたものは何か ecspressoの8年間で蓄積されたのはコードだけではない 操作範囲をECSに限定する AWS SDKのJSON構造をそのまま扱う 構造は抽象化しない、操作は便利に抽象化する 「何をやり、何をやらないか」という設計判断が本当の資産 この設計判断が言語化されていると何が起きるか?
2026年2月12日 こんなツイートが https://x.com/mathematics154/status/ 2021769823479554485
batcha github.com/kyosu-1/batcha ecspressoと同じ構造でAWS Batchの ジョブ定義を管理するツール テンプレートエンジンに kayac/go- config、Terraform state の参照に
fujiwara/tfstate-lookup を利用しており、 ecspresso と同じエコシステムの上に構築 しています。 ecspresso と同様に、変更頻度の高い Job Definition の管理に特化し、ジョブキュー やコンピュート環境、ネットワークとい った頻繁には変わらないリソースは Terraform などの IaC ツールに任せる設計 です。
ecspresso (ECS) batcha (AWS Batch) タスク定義を JSON テンプレートで管理 Job Definition
を JSON テンプレートで管理 ecspresso register でタスク定義登録 batcha register で Job Definition 登録 ecspresso diff で差分検出 batcha diff で差分検出 ecspresso verify でローカル検証 batcha verify でローカル検証 ecspresso init で既存リソースから生成 batcha init で既存定義から生成 ecspresso run でタスク実行 batcha run でジョブ実行 tfstate プラグインで Terraform 連携 同様に tfstate プラグインで連携 https://kyosu.dev/#/blog/introducing-batcha より引用
batchaはClaude Codeが(ほぼ)実装した batcha のコードはほぼ Claude Code が書いたもので、自分は設計の方向付けと調 整に徹しました。ecspresso という優れた手本があったのも大きいですが、こう いうツールがサクッと作れてしまう、いい時代になりましたね。
https://kyosu.dev/#/blog/introducing-batcha より引用 fujiwara自身もこのパターンでいくつもOSSを作っている AWS Lambda用の fujiwara/lambroll さくらのAppRun用の fujiwara/apprun-cli この設計パターンが有用な事は実証されている(と思う) 「良い設計パターンを踏襲すれば同様のツールはAIに作らせることができる」時代
まとめ 「やらないこと」を決めることが設計では重要 できることが多ければいいわけではない なんでも抽象化すればいいわけではない 技術選定は初手で正解を当てなくてもよい、が致命傷は避ける 最初の選択で間違うこともある、結果的にそれが良かったこともある 向き合い、改善し続けることが重要 AI時代に「作るべきもの」をどう見極めるか 「設計を言語化できれば」実装はAIに任せることができるようになってきた 「作るべきもの」を見極める力がより重要になる