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
Duct for beginners.
Search
Nakamura, Ryotaro
February 16, 2018
Technology
0
4.1k
Duct for beginners.
How to use Integrant and Duct.
Nakamura, Ryotaro
February 16, 2018
Tweet
Share
More Decks by Nakamura, Ryotaro
See All by Nakamura, Ryotaro
Learn Go in 15 minutes
nryotaro
0
37
An introduction of statistical learning
nryotaro
0
43
Seven architectural patterns
nryotaro
1
110
Improving Performance with Parallel Programming
nryotaro
0
55
Other Decks in Technology
See All in Technology
JAZUG 15周年記念 × JAT「AI Agent開発者必見:"今"のOracle技術で拡張するAzure × OCIの共存アーキテクチャ」
shisyu_gaku
0
140
Goに育てられ開発者向けセキュリティ事業を立ち上げた僕が今向き合う、AI × セキュリティの最前線 / Go Conference 2025
flatt_security
0
370
ACA でMAGI システムを社内で展開しようとした話
mappie_kochi
1
310
生成AIで「お客様の声」を ストーリーに変える 新潮流「Generative ETL」
ishikawa_satoru
1
370
Shirankedo NOCで見えてきたeduroam/OpenRoaming運用ノウハウと課題 - BAKUCHIKU BANBAN #2
marokiki
0
170
OpenAI gpt-oss ファインチューニング入門
kmotohas
2
1.1k
「使い方教えて」「事例教えて」じゃもう遅い! Microsoft 365 Copilot を触り倒そう!
taichinakamura
0
200
業務効率化をさらに加速させる、ノーコードツールとStep Functionsのハイブリッド化
smt7174
2
110
防災デジタル分野での官民共創の取り組み (2)DIT/CCとD-CERTについて
ditccsugii
0
120
AIAgentの限界を超え、 現場を動かすWorkflowAgentの設計と実践
miyatakoji
1
160
AI時代こそ求められる設計力- AWSクラウドデザインパターン3選で信頼性と拡張性を高める-
kenichirokimura
3
200
ユーザーの声とAI検証で進める、プロダクトディスカバリー
sansantech
PRO
1
100
Featured
See All Featured
Statistics for Hackers
jakevdp
799
220k
4 Signs Your Business is Dying
shpigford
185
22k
Building Flexible Design Systems
yeseniaperezcruz
329
39k
Embracing the Ebb and Flow
colly
88
4.8k
Balancing Empowerment & Direction
lara
4
680
Navigating Team Friction
lara
189
15k
How to train your dragon (web standard)
notwaldorf
96
6.3k
A Tale of Four Properties
chriscoyier
160
23k
Testing 201, or: Great Expectations
jmmastey
45
7.7k
Mobile First: as difficult as doing things right
swwweet
224
10k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
33
2.5k
Bash Introduction
62gerente
615
210k
Transcript
はじめてのDuct 中村 遼太郎
話すこと 2 IntegrantでこまってDuctを使うようになった話 • Integrant ◦ 概要 ◦ 困ったこと •
Duct ◦ 概要 ◦ Boundaries ◦ Moduleの作り方
Integrant 3
Ringの初期化例 4 (def endpoint “http://localhost/health”) (defn handler [request] (get-health endpoint))
(defn -main [] (jetty/run-jetty handler {:port 3000})) 他のサービスの状態を調べるハンドラ endpointに対するヘルスチェックの結果を返す
よくないところ 5 (def endpoint “http://localhost/health”) (defn handler [request] (get-health endpoint))
(defn -main [] (jetty/run-jetty handler {:port 3000})) グローバル変数による依存解決 変数のスコープが必要以上に大きい mainからendpointが見える
パラメタでスコープを小さくする 6 パラメタによる依存解決 設定とリクエストまじり,パラメタが複雑になる (defn wrap-handler [handler ep] (fn [request]
(handler (assoc request :endpoint ep)))) (defn handler [request] (get-health (:endpoint request))) (wrap-handler handler “http://localhost/health”)
Integrant 7 クロージャによる依存解決 クロージャでローカル変数を個別に渡す (defmethod ig/init-key :ebis/handler [_ endpoint] (fn
[request] (get-health endpoint))) (defmethod ig/init-key :ebis/jetty [_ {:keys [handler] :as options}] (jetty/run-jetty handler options))
関心ごと分離 8 コンフィグマップ(構造) Integrantはシステムの実装と構造を分ける {:ebis/handler “http://localhost/health” :ebis/jetty {:handler #ig/ref :ebis/handler
:port 3000}}
Integrantがやること 9 キーワードをオブジェクトに置き換える Integrantはシステムの実装と構造を分ける {:ebis/handler “http://localhost/health” :ebis/jetty {:handler #ig/ref :ebis/handler
:port 3000}} init-key
Integrantからみたシステム 10 コードの木 Integrantはコードの幹にある integrantは コードを呼び出す コードが ライブラリを呼ぶ https://skillsmatter.com/skillscasts/8717-arachne-building-a-framework-in-clojure
Integrantからみたシステム 11 システムの実装と構造の分離 Integrantは幹の部分から実装とコードを分けていく James Reeves, Enter Integrant: a micro-framework
for data-driven-architecture 実装
Integrantで困ったこと 12 途中までIntegrantを使う ライブラリの呼び出し部分への適用が最後になる ライブラリと コードが密結合 コンフィグマップ にする順序
ほしいもの 13 途中までIntegrantを使う ➔ ライブラリの呼び出しを楽を疎にするもの ➔ コンフィグマップの適用を楽にするもの 楽に適用できる システムの境界 を疎にできる
ほしいもの 14 途中までIntegrantを使う ➔ ライブラリの呼び出しを楽を疎にするもの ➔ コンフィグマップの適用を楽にするもの 楽に適用できる システムの境界 を疎にできる
Duct Boundaries Duct modules
Duct 15 weavejester If Integrant is the “grammar”, Duct is
attempting to build a “vocabulary”
Integrantの初期化手順 16 コンフィグをもとにシステムを初期化する read init コンフィグを読む コンフィグをオブジェクトに変換する
Ductの初期化手順 17 コンフィグを拡張する中間ステップがある read init コンフィグを読む prep コンフィグを書き換える コンフィグをオブジェクトに変換する
モジュール 18 prepステップでコンフィグを展開する純粋関数 read init prep module.web module.cljs module.sql module.logging
module.ataraxy Ductが提供するもの
コンフィグの展開 19 config.ednで使うモジュールを宣言する コンフィグのロード $ cat resources/ebis/config.edn { :duct.module/logging {}
... } ... $ lein repl user => (dev) :loaded Read Prep init
コンフィグの展開 20 prepでコンフィグを展開する モジュールによるloggerの展開 Read Prep init (dev) => (prep)
:prepped dev => (pprint config) { :duct.logger/timbre {:level :debug, {:appenders {: ...} :duct.logger.timbre/spit {:fname “logs/..”} :duct.module/logging {} ... }
コンフィグの展開 21 展開されたコンフィグでシステムが初期化される サーバの起動 Read Prep init dev => (go)
:duct.server.http.jetty/starting-server {:port 3000} :initiated
プロジェクトの構造 22 lein newでテンプレートからプロジェクトを作れる プロジェクトの構造 lein new duct ebis +api
+ataraxy {{project}} ├── src │ └── {{project}} │ ├── boundary │ │ └── {{boundary}}.clj │ ├── handler │ │ └── {{handler}}.clj │ └── main.clj
Boundaries 23 protocolを介してシステムの外と通信する プロトコルの利用例 (defprotocol Health (get-health [this])) (defrecord HttpHealth
[method url handler] Health (get-health [{:keys [method url handler]}] (handler (method url)))) (defmethod ig/init-key ::http [_ {:keys [url]}] (->HttpHealth http/get “http://..” #(..)))
Ductで困ること 24 必要なモジュールがない https://github.com/duct-framework module.web module.cljs module.sql module.logging module.ataraxy Duct
frameworkが提供するモジュール
事例 25 Google pubsubのモジュールを作る 購読開始処理 (def s-name (SubscriptionName/create “p-id” “s-id”))
(def receiver (reify MessageReceiver (receiveMessage [this message consume] (println (. message getData))))) (def subscriber (Subscriber/newBuilder s-name receiver)) (. (. subscriber build) startAsync)
モジュール化の方針 26 SubscriptionName/createをモジュールに移す 処理の分割 (def s-name → モジュール (SubscriptionName/create “p-id”
“s-id”)) (def receiver → ig/init (reify MessageReceiver (receiveMessage [this message consume] (println (. message getData))))) (def subscriber (Subscriber/newBuilder s-name receiver)) (. (. subscriber build) startAsync)→ protocol
モジュール側 1/3 27 src/duct_hierachy.ednにprepで呼び出すキーを登録 :duct/moduleを継承する {:duct.module/message [:duct/module]}
モジュール側 2/3 28 :duct/moduleを継承したキーがprepで呼び出される :duct/message/pubsubをコンフィグマップに追加 (defmethod ig/init-key :duct.module/message [_ options]
{:fn (fn [config] (core/merge-configs config ; ユーザが定義したコンフィグ {:duct.message/pubsub ;追加するキー {:logger (ig/ref :duct/logger)}}))}) :duct/module
モジュール側 3/3 29 prepで追加されたキーはinitするときに呼び出される SubscriptionNameのインスタンス化 (defmethod ig/init-key :duct.message/pubsub [_ {:keys
[p-id s-id] :as opt}] (assoc opt :s-name (SubscriptionName/create p-id s-id)))
アプリケーション側 1/3 30 config.ednに作ったモジュールを宣言する config.ednにモジュールを宣言 {:duct.message/pubsub {:p-id "clj-p" :s-id "clj-s"}
:duct.module/message {} :ebis.boundary/message #ig/ref :duct.message/pubsub } モジュールが初期化する
アプリケーション側 2/3 31 boundaryでprotocolを宣言する Receiverの宣言 (defprotocol Receiver (start [this]) (stop
[this])) (defrecord PubSubReceiver [subscriber logger] (start [this] (l/log logger :info “start”) (. subscriber startAsync)) ..)
アプリケーション側 3/3 32 Receiverをinit-keyの中で作る Receiverの生成 (defmethod :ig/init-key :ebis.boundary/message [_ {:keys
s-name logger}] (let [subscriber (... (reify MessageReceiver ...)) receiver (->PubSubReceiver subscriber logger)] (start receiver) (receiver)))
おさらい 33 ➔ Integrantだけだとコンフィグマップの適用がたいへん ➔ Ductのモジュールはコンフィグ化を助けてくれる ➔ しかしモジュールの数は少なく,作り方の説明は不十分 ➔ そこでモジュールの作り方を紹介した
参考資料 34 ➔ Arachne: building a framework in Clojure https://skillsmatter.com/skillscasts/8717-arachne-building-a-framework-in-clojure
➔ Productive Duct https://skillsmatter.com/skillscasts/10836-productive-duct ➔ Integrant: a micro-framework for data-driven architecture with James Reeves https://skillsmatter.com/skillscasts/9820-enter-integrant-a-micro-framework-for-data-driven-architecture-with-james-r eeves ➔ Duct, Covered https://skillsmatter.com/skillscasts/7229-duct-covered ➔ Duct Framework and supporting libraries https://github.com/duct-framework