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
マイクロサービス内で動くAPIをF#で書いている
Search
ayato
June 14, 2025
0
460
マイクロサービス内で動くAPIをF#で書いている
関数型まつり2025の発表資料
ayato
June 14, 2025
Tweet
Share
More Decks by ayato
See All by ayato
Clojureという言語が私逹にもたらしたもの
ayato0211
6
3k
3年間考え続けてきたWebアプリケーションにおけるテストの話
ayato0211
3
250
Re:REPL-Driven Development
ayato0211
3
1.3k
Meta Template Engine
ayato0211
2
1.1k
超変換! Hiccup data structure!!
ayato0211
2
600
About Integrant
ayato0211
0
550
Muscle Assert
ayato0211
0
260
Clojureを用いたWebアプリケーション開発
ayato0211
2
3.1k
翻訳にまつわるエトセトラ
ayato0211
6
1.2k
Featured
See All Featured
Six Lessons from altMBA
skipperchong
28
3.8k
Practical Orchestrator
shlominoach
188
11k
BBQ
matthewcrist
89
9.7k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Build The Right Thing And Hit Your Dates
maggiecrowley
36
2.8k
The Power of CSS Pseudo Elements
geoffreycrofte
77
5.8k
A Tale of Four Properties
chriscoyier
160
23k
Mobile First: as difficult as doing things right
swwweet
223
9.7k
Balancing Empowerment & Direction
lara
1
360
Optimising Largest Contentful Paint
csswizardry
37
3.3k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.8k
Transcript
マイクロサービス内で 動くAPIを F#で書いている 2025/06/15 関数型まつり
あやぴー - 株式会社ユーザベース - 9LISPという勉強会で道を外したヒト - 約10年関数型言語を業務で使っている - 最近はよくClojure, F#を書いてます
- @ayato-p - #fp_matsuri_c
どんな開発組織でF#を採用したのか
プロダクトチーム紹介 - XPに基づいたアジャイル開発組織 - 100人超の開発者(SWE, SRE, MLE, TE)が在籍 - ペアプログラミングを中心とした開発
- チームの最大人数は5人 - 規模が大きくなってもチームで独立して動けるようにする - 自律したチームなので明示的なリーダーは不在 - マイクロサービスとしてサービスを開発している - モノリス -> マイクロサービスをやってきている - 新規機能はマイクロサービスで開発している - モノリス部分は随時リプレース - マイクロサービスの各APIは多種多様な言語で書かれている - ↑大事
プロダクトチーム紹介 ※ イメージです
https://agilejourney.uzabase.com/archive/category/UZABASE 興味があれば…
F#導入以前のプロダクトチーム - Scala, Kotlin, ClojureなどJVM系言語を筆頭に様々な言語が採用されていた - Elixir, Go, Rustなどの時勢に乗った言語の採用もされていた -
OCaml, Haskellのようなちょっとレアな言語も採用されていた - フロントエンドではDart, TypeScriptなども採用されていた - 何故か.NET系の言語だけは採用されていなかった
どのように導入したのか - 当時私がいたチームをそそのかした - 全員ノリがよかった - Core APIにデータを投入するAPI ※ イメージです
なぜF#だったのか - 組織内で誰も使ったことがなかった - 静的型付けな関数型言語で現実世界で使いやすそう - シンタックスが簡素に感じた - エコシステムは.NETのものが流用できそう
開発環境 - .NET (Core) - クロスプラットフォームで動く、モダン.NET - dotnetコマンド - ビルドなど
- Paket - 依存関係の管理 - Ionide - VS Code / Cursorで動作するプラグイン - Fantomas - フォーマッター
F#らしさを活かした設計
F#らしさ - 第一級関数 - コンピュテーション式 - 判別共用体 - 例外 現実世界の問題を解くのにちょうどいい。
ASP.NET Core Minimal APIのスタイルを採用した - 関数プログラミングと親和性が高い - フレームワークよりライブラリの組み合わせが好ましいと考えていた - Library
patterns: Why frameworks are evil - Tomas Petricek - プロダクトチームとしてはフレームワークに求めている機能が多くはない - 外界を適切に分離して、ドメインを中心に据えたアーキテクチャを好むため ※ ルーティングに対して関数を登録するだけでよく、従来のフレームワークのようにクラスを作ったりアトリビュートを大量に付与する必要がない
アーキテクチャ概観 ※ こういうアーキテクチャで開発することが多い
境界にインターフェイスではなく関数型を使う - 関数型を境界に用いると他の関数と組み合わせるのが容易になる - 依存先をテストするさいにモックしやすい
ドメインを素朴に保つ - ドメインにある関数やレコードはできるだけモナドや副作用と無縁にする - 特に Option はEffective Javaでも言及があるようにフィールドに保持しない - F#の場合は判別共用体で宣言できる可能性が高い
ドメインを素朴に保つ - モデリング次第ではあるが判別共用体を頼る方が意味がハッキリする - Option を使うより良い可能性が高い
ユースケースで抽象度をあげてエラーを扱う - 判別共用体を多用すると具体的でハンドリングしにくい - 鉄道指向プログラミングを目指したい ※ このくらいなら許容できるレベルではあるが…
ユースケースで抽象度をあげてエラーを扱う
Resultに頼りすぎず例外を適切に使う - 関数プログラミングの書籍では例外より Result 型の良さが強調されがち - 現実世界では例外で済む事情をわざわざ Result 型に変換する必要はない -
特に外界の事情や業務上のエラーではない状態を Result 型に押し込めてはいけない ※ タイムアウトをResult型や判別共用体に変換してまでドメインレイヤーまで持ち上げたくないよね
非同期の取り扱い
ドメインは素朴にしたいが…Asyncだけは特別扱い - 以下のように Async を返す関数を引数に取る関数を定義したいことがある - これを無理に消すと Async.RunSynchronously などを使うことになる -
DDDで集約を跨いだ情報でロジックを構築するための「getter高階関数パターン」の紹介 - F#で Async を無理に外そうとすると大変な目に…(後述)
Asyncを不用意に止めない - Async.RunSynchronously を使って非同期計算を止めてしまうのは禁忌 - .NETは賢いのでスレッドプールを拡大し続けるが、そのために気付きにくい問題になる - レスポンスの値は基本的に Task やそれに準ずるものにしておく
- F#の Async は返り値に指定できないので注意 ※ 上記のようなコードを書いてはいけない
Asyncを不用意に止めない - 返り値は必ず Task にする
TaskよりAsyncを使う - Task は即時実行される、 Async は遅延実行される - 計算の遅延と仲良く付き合う
並行処理で想像以上にリクエストが飛ぶ - Async.Parallel で気軽に並行処理が実装できる - 問答無用で通信先を◯しにいく
並行処理で想像以上にリクエストが飛ぶ - その先がHTTP通信ならHTTP Clientの同時接続数設定をいれておく - NET 8 Networking Improvements -
Async.Parallel の maxDegreeOfParallelism を設定するのも良い - FSharp.Core - Async
その他、実装上の悩みごと
Minimal APIはF#からの利用に最適化されていない① - C#ではラムダ式を素直に受け取れるようになっている - F#の匿名関数はラムダ式と直接の互換性がないので Func に変換する - Func<>
and Delegate implicit conversion · Issue #1131 · fsharp/fslang-suggestions · GitHub
Minimal APIはF#からの利用に最適化されていない② - パラメーターバインドで苦労する - 匿名関数にアトリビュートを使えないなど問題が多々ある - Support attributes on
lambda expressions · Issue #984 · fsharp/fslang-suggestions · GitHub
Minimal APIはF#からの利用に最適化されていない② - パラメーターバインドで取れないときは BindAsync を自前で実装する
コンピュテーション式の取り扱いが増えると煩雑 - FSharpPlusを使えるとコンピュテーション式の利用を減らせる - FSharpPlus自体は便利だが… - ドキュメントはあまり親切ではない - monadコンピュテーション式など使えるのは良い
DIにReaderを使うか…?
関数の呼び出しを検証するのが面倒 - 自分で関数を用意する必要がある
運用は大変か?
大変ではない - F#特有の難しさはあまりない - .NETに慣れていないことで発生している難しさはある - 逆に.NETの運用に慣れていれば簡単に運用できるはず - dotnet-countersのようなツールを知っていれば◎ -
KubernetesにデプロイしているのでDockerイメージをビルドできれば◎ - 諸々のサービス利用も容易◎ - Datadogでメトリクス収集をしている - yamoryでのスキャンも簡単
強いて言うなら… - 日本語の情報は例によって少ない - とはいえ、私達の組織にとっては誤差でしかない - そういう言語をよく使っている - .NETやC#に慣れていないことが原因の大変さはある -
ドキュメントの読み替えや理解がどうしても難しい - 拡張関数とかどのパッケージ開いたらいいの?とかありがち - 生成AIも万能ではない
まとめ
まとめ - F#らしさを活かした設計をする - ドメインは素朴な関数やレコードを活用 - 一部で抽象度をあげてエラーハンドリングをする - 例外もちゃんと使う -
非同期はAsyncを適切に利用する - FSharpPlusはすごいが扱うのが難しい - .NETの運用は実務上困ることはない…はず