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
36
An introduction of statistical learning
nryotaro
0
42
Seven architectural patterns
nryotaro
1
100
Improving Performance with Parallel Programming
nryotaro
0
51
Other Decks in Technology
See All in Technology
Zero Data Loss Autonomous Recovery Service サービス概要
oracle4engineer
PRO
2
7.8k
united airlines ™®️ USA Contact Numbers: Complete 2025 Support Guide
flyunitedhelp
1
440
敢えて生成AIを使わないマネジメント業務
kzkmaeda
2
470
20250707-AI活用の個人差を埋めるチームづくり
shnjtk
6
4k
CDKコード品質UP!ナイスな自作コンストラクタを作るための便利インターフェース
harukasakihara
2
140
Delegating the chores of authenticating users to Keycloak
ahus1
0
160
AWS認定を取る中で感じたこと
siromi
1
210
PO初心者が考えた ”POらしさ”
nb_rady
0
220
VGGT: Visual Geometry Grounded Transformer
peisuke
1
240
CDK Vibe Coding Fes
tomoki10
0
270
Enhancing SaaS Product Reliability and Release Velocity through Optimized Testing Approach
ropqa
1
240
第4回Snowflake 金融ユーザー会 Snowflake summit recap
tamaoki
1
300
Featured
See All Featured
Building an army of robots
kneath
306
45k
The World Runs on Bad Software
bkeepers
PRO
69
11k
How to train your dragon (web standard)
notwaldorf
96
6.1k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
45
7.5k
Why Our Code Smells
bkeepers
PRO
336
57k
Music & Morning Musume
bryan
46
6.6k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
48
2.9k
How GitHub (no longer) Works
holman
314
140k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Testing 201, or: Great Expectations
jmmastey
43
7.6k
Into the Great Unknown - MozCon
thekraken
40
1.9k
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