Slide 1

Slide 1 text

*OUFHSBOU ʹ͍ͭͯ !@BZBUP@Q$ZCP[V4UBSUVQT JOD

Slide 2

Slide 2 text

自己紹介 •あやぴー •朝ジムを倒しまくってる •普段はComponentベースでシステム開発

Slide 3

Slide 3 text

Integrant概要

Slide 4

Slide 4 text

Integrantとは •Jamesオジサンが作った新しいデータ駆動
 アーキテクチャなマイクロフレームワーク •つまり、ライフサイクルを管理するライブラリ •Componentで指摘された課題を解決しようとしたもの •システムがデータから組み立てられる •各コンポーネントは必ずしもマップやレコードである 必要はない

Slide 5

Slide 5 text

データによるシステム定義 •ednでシステムを定義できる {:adapter/jetty {:port 8080, :handler #ref :handler/greet} :handler/greet {:name "Alice"}}

Slide 6

Slide 6 text

Multimethodによるコンポーネント定義 •レコードやマップに限らず関数やただの数値などもコン ポーネントにすることが可能 (require '[ring.jetty.adapter :as jetty] '[ring.util.response :as resp]) (defmethod ig/init-key :adapter/jetty [_ {:keys [handler] :as opts}] (jetty/run-jetty handler (-> opts (dissoc :handler) (assoc :join? false)))) (defmethod ig/init-key :handler/greet [_ {:keys [name]}] (fn [_] (resp/response (str "Hello " name))))

Slide 7

Slide 7 text

一時停止と再開のサポート •再起動が遅くなるのを回避できる •suspend-key!とresume-keyがポイント •初期化処理にも多少影響がある

Slide 8

Slide 8 text

一時停止と再開のサポート (defmethod ig/init-key :adapter/jetty [_ opts] (let [handler (atom (delay (:handler opts))) options (-> opts (dissoc :handler) (assoc :join? false))] {:handler handler :server (jetty/run-jetty (fn [req] (@@handler req)) options)})) (defmethod ig/halt-key! :adapter/jetty [_ {:keys [server]}] (.stop server)) (defmethod ig/suspend-key! :adapter/jetty [_ {:keys [handler]}] (reset! handler (promise))) (defmethod ig/resume-key :adapter/jetty [key opts old-opts old-impl] (if (= (dissoc opts :handler) (dissoc old-opts :handler)) (do (deliver @(:handler old-impl) (:handler opts)) old-impl) (do (ig/halt-key! key old-impl) (ig/init-key key opts))))

Slide 9

Slide 9 text

Componentと比較して⚔

Slide 10

Slide 10 text

良いところ •データでシステムを記述できる •どんなモノでもコンポーネントにできる •心理的な負担が減る

Slide 11

Slide 11 text

悪いところ •明示的にコンポーネントの名前空間を読み込む必要性

Slide 12

Slide 12 text

変わらなかったこと •あるコンポーネントに依存したいならば
 それ自身をコンポーネントとして定義する必要がある

Slide 13

Slide 13 text

Integrantはこう使う
 (と良いかも)

Slide 14

Slide 14 text

独自のns loaderを作る •デフォルトでついてくるのは使い勝手が悪い •完全修飾されたキーワードは設定ファイルに書き難い •開発時にシステムからコンポーネントを取り出すのも苦 •例えばbultitudeを利用して任意のprefix付きnsを
 ロードするようなbootstrap機能を実装する

Slide 15

Slide 15 text

同じコンポーネントを複数作る •マルチメソッドを大量に用意する? •No •任意の親を持つ子のキーワードを複数deriveしておく •注意点 •複数の子で設定を書く場合は親のキーワードを
 設定ファイルに書けない •refに対して子のキーワードを明示

Slide 16

Slide 16 text

同じコンポーネントを複数作る (derive :demo/master-db :demo/db) (derive :demo/read-db-1 :demo/db) (derive :demo/read-db-2 :demo/db) (defmethod ig/init-key :demo/db [_ opts] ...) (ig/init {:demo/read-db-1 {...} :demo/read-db-2 {...} :demo/master-db {...} :demo/get-user-handler 
 {:db (ig/ref :demo/read-db-1)} :demo/get-company-handler {:db (ig/ref :demo/read-db-2)} :demo/update-user-handler {:db (ig/ref :demo/master-db)}}

Slide 17

Slide 17 text

テストでコンポーネントを差し替える •deriveでok

Slide 18

Slide 18 text

baumと組み合わせる •baumは設定ファイルを素敵にする拡張可能な
 DSLライブラリ •環境変数などを取得できる •baumのカスタムリーダーとして
 integrant.core/refをラップする

Slide 19

Slide 19 text

baumと組み合わせる {$override* "dev-resources/config-local.edn" :demo/server {:port 3000 :handler #igref :demo/endpoint} :demo/database {:dbtype "postgresql" :dbname "my_blog" :user #env :db-user :password #env :db-password} :demo/endpoint {:db #igref :demo/database}}

Slide 20

Slide 20 text

まとめ •Componentにあった心理的な負担が減った •これが1番いいかと言われると疑問 •Arachne的なアプローチにも期待したい