基盤開発チームブログリレー2日目の記事です。
1日目は田尻さんがOCamlについて書いてくれました。そのOCaml熱にあおられ私も仕事で使い始めたので、私も便乗してOCamlについて書いてみます。

はじめに
OCaml、書いてますか。私も書いています。仕事の補助ツールとして。
こんにちは、基盤開発チームの林です。
以前まで、ちょっとしたCLIツールを作る言語としては、簡潔に書ける Ruby を使うことが多かったのですが、最近はAIエージェントをよく使うようになったこともあり、自分用のCLIツール開発には OCaml を使うようになりました。
もともと私はローカル環境や設定の作り込みをするタイプではなく、むしろクリーンな環境・ゼロ設定で仕事をするのが好みだったのですが、近頃はCLIツール開発も含めてローカル環境の作り込みをするようになってきたので、そのあたりで考えたことなどを記事にしてみます。
なお、最初にお断りをしておくと、関数型言語を仕事で使った経験はほとんどなく*1、OCaml 自体にも詳しくはないので、OCaml 初心者による初心者向けの記事です。
- はじめに
- 自分用のCLIツールを開発したくなってきた経緯
- CLIツール開発言語に求めたい性質を列挙したら OCaml が残った
- 実際に OCaml をCLIツール開発に使ってみて
- おわりに
- We're hiring!
自分用のCLIツールを開発したくなってきた経緯
昨年から Claude Code を使い始めてからは、あらゆる手元の作業を Claude Code にお願いするようになりました。 また、Claude Code に作業を円滑にしてもらえるように、目的ごとに Skill ファイルもせっせと作るようになりました。
たとえばコードレビューの時は GitLab の公式CLIの glab コマンドを使って、コメントを取得する時はこのコマンドで、、と自然言語とコマンド例で書いていたりしたのですが、Skill を読ませても思った通りコマンド実行してくれず、何度もやり直しになることが多々ありました。 そもそも自然言語で書くとどうしても曖昧さが残りますし、Skill のメンテをするのにも疲れてきました。
そこで、定型の処理については、分かりやすいコマンド体系で決定的な動作をするCLIツールを自分用に作るのがよいと気付きました。
また、現在エムスリーでは Claude Team プランが導入されているので一定の上限枠までは定額利用でき、私はフルタイムで Claude Code を使っても枠が余っているので、CLIツール開発をAIにやってもらうのは実質費用なしでできてしまう状況です。
この状況を踏まえて、2026年に自分のローカル環境のCLIツール開発に使うならどの言語がいいかを検討しました。
CLIツール開発言語に求めたい性質を列挙したら OCaml が残った
- 代数的データ型とパターンマッチ
プログラミングを安全に分かりやすく記述するための奥義は、代数的データ型とパターンマッチだと常々思っているので、これは必須で欲しい機能でした。 パターン記述が見やすいとわかりやすさに直結するので、簡潔に書けることも重要。
- 静的型付け、型推論
型を丁寧に書くのは昔は面倒だったこともありますが、AI以前でもIDEで楽になっていましたし、今はAIに書いてもらうので型はあるだけ良いと思っています。 型が合わなければコンパイルで落ちてくれるので、テストがなくてもある程度安全です。 また、読む時に不要な情報が少ない方がよいので、型推論によって簡潔に書けることも重要です。
- ビルドや起動が遅くない
せっかちなので、遅くないものがよいです。
- メモリ管理はしたくはない
Rust が上で挙げた要素の多くを満たす選択肢であるとは思いますが、メモリ管理を記述したいほどのCLIツールは作らないので、今回は Rust という気分ではありませんでした。
以上のような性質を満たす言語を検討した結果、Haxe と OCaml が候補に残り、最終的には基盤開発チームメンバーの田尻さんが OCaml を激推ししていることもあって、OCaml に決めたのでした。*2
実際に OCaml をCLIツール開発に使ってみて
具体的にどのようなツールを作っているかですが、たとえば次のようなサービス用のCLIツールを作ったりしています。
- Confluence
- Jira
- Redmine
- Sentry
特にConfluenceやJiraは、同じAtlassian製でそれぞれ専用のクエリランゲージ(Confluenceの場合はCQL)があり、使いこなすと性能よく色々なことができるので便利です。*3
OCaml コードの大部分はAIに生成してもらっていますが、書き味というか読み味がよいです。 やはり代数的データ型をプログラムの上の方に宣言して、それのパターンマッチにより分岐を網羅して記述すると、AIも書き間違えないし、読むときも分かりやすくて気に入っています。
ただ、AIへの指示なしで書いてもらった時は、生成されたコードが期待とちょっと違ったので、指示を少しだけ CLAUDE.md に書いています。
AIへの指示
型駆動設計
代数的データ型とパターンマッチを重視して言語選定をしているので、それが最大限生かされるように次の指示を書いています。
## 型駆動設計 - 代数的データ型とパターンマッチを最重視 - 型で表現できることは型で表現 - 型シグネチャを先に決めてから実装
関数を書き始める前にまず型を考えて定義してくれるようになりました。
let* によるネスト改善
OCaml ではエラー処理にいわゆる Result 型を使えますが、 最初AIに書いてもらった時に、次のようにネストが深くなる書き方をされました。
let fetch_user config_path = (* 設定ファイルを読み込む(ファイルが無ければ失敗) *) match File.read config_path with | Error e -> Error e | Ok config -> (* 読み込んだ設定からAPIのURLを組み立ててHTTP GET *) match Http.get (config.endpoint ^ "/user") with | Error e -> Error e | Ok body -> Ok body
そこで次の指示を書いて、ネストしない見やすい書き方にしてもらっています。
## ネストを浅く保つ - Result型の連鎖にはResult.Syntaxのlet*演算子を使う
この指示があると、先ほどのコードは次のようにネストが深くならず見通しが良くなります。
let fetch_user config_path = let open Result.Syntax in let* config = File.read config_path in (* 設定ファイル読み込み *) let* body = Http.get (config.endpoint ^ "/user") in (* 読み込んだ設定でHTTP GET *) Ok body
使っているライブラリ
業務上必要なCLIツールの多くは、標準入出力、HTTPアクセス、JSON処理ができれば足りることが多いので、外部ライブラリはほとんど使っておらず、少数のライブラリのみ使っています。
おわりに
今回とりとめもなく、AI作業の効率化のためにCLIツール開発が必要だと思ったことや、CLIツール開発に OCaml を使っている話を書いてみました。 個人的には OCaml は認知負荷が低くて読みやすいし、AIもあまり書き間違えない気もしていて、型がしっかりあるとAIも書きやすいのかなと感じています。
もともとローカル環境整備に凝らない私が凝り始めているのだから、もともと凝るタイプの人が今どんなやり方をしているかもぜひ知りたいところですね。
We're hiring!
好きな開発言語・スタイルで仕事がしやすいエムスリーでは、ソフトウェアエンジニアを募集しています。 新卒・中途採用、カジュアル面談やインターンも募集しています!
エンジニア採用ページはこちら
カジュアル面談もお気軽にどうぞ
インターンも常時募集しています
*1:後述のHaxeは関数型言語のパラダイムも持っていて、仕事でFlash / HTML5 アプリケーション開発に使ったことはあります。あとは趣味で Lean を触ったことがある程度。
*2:なお Haxe は JavaScript とほぼ同じ文法で代数的データ型、パターンマッチ、型推論を簡単に扱えて体験が良かった好きな言語なので、機会があればまた使いたいと思っています。かつて AltJS 戦争というものがあり(以下略)
*3:有名なツールは、公式・非公式でCLIツールが提供されていることがほとんどなので「公式CLIやMCPを使えば良いのでは」と思われそうですが、自身の仕事に合うように、AIが誤解なく一発で作業を完遂できるためにCLIツールを自作する意味があります。