component library
TRANSCRIPT
![Page 1: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/1.jpg)
component libraryhttps://github.com/stuartsierra/component
https://github.com/jordillonch/component-example
@jordillonch July 2015
![Page 2: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/2.jpg)
Agenda
• component library introduction
• example
![Page 3: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/3.jpg)
Introduction
![Page 4: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/4.jpg)
Tiny Clojure framework for managing the lifecycle of
software components which have runtime state
![Page 5: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/5.jpg)
Real-world applications need to manage state
![Page 6: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/6.jpg)
It can be seen as a style of dependency injection using
immutable data structures
![Page 7: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/7.jpg)
Components and
Systems
![Page 8: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/8.jpg)
Components
![Page 9: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/9.jpg)
A component is a collection of functions which share
some runtime state
![Page 10: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/10.jpg)
A component is similar in spirit to the definition of an object in Object-Oriented Programming
![Page 11: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/11.jpg)
A component knows how to start and stop the application pieces
that have to manage state
![Page 12: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/12.jpg)
Some examples
• Database access: database connection
• External API service: HTTP connection pool
• Web server: a session store
• In-memory cache: a Clojure Atom or Ref
![Page 13: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/13.jpg)
Systems
![Page 14: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/14.jpg)
Components are composed into systems
![Page 15: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/15.jpg)
A system is a component which knows how to start
and stop other components
![Page 16: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/16.jpg)
It is also responsible for injecting dependencies into the components which need them
![Page 17: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/17.jpg)
Advantages of the Component Model
![Page 18: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/18.jpg)
Large applications often consist of many stateful processes which must be started and stopped in a
particular order.
The component model makes those relationships explicit and declarative
![Page 19: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/19.jpg)
Each component receives references only to the things it needs, avoiding unnecessary
shared state
![Page 20: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/20.jpg)
Easy to swap in "stub" or "mock" implementations of a component for testing purposes, without relying on time-dependent constructs, such as with-redefs
or binding, which are often subject to race conditions in multi-threaded code
![Page 21: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/21.jpg)
Having all state reachable via a single "system" object makes it easy to reach in and inspect any part of the application from
the REPL
![Page 22: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/22.jpg)
Having a coherent way to set up and tear down all the state associated with an
application enables rapid development cycles without restarting the JVM
![Page 23: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/23.jpg)
It can also make unit tests faster and more independent, since the cost of creating and starting a system is low
enough that every test can create a new instance of the system
![Page 24: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/24.jpg)
Disadvantages of the Component Model
![Page 25: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/25.jpg)
It is not easy to retrofit the component model to an existing
application without major refactoring
![Page 26: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/26.jpg)
For small applications, declaring the dependency relationships among
components may actually be more work than manually starting all the components
in the correct order
![Page 27: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/27.jpg)
The system map is too large to inspect visually
![Page 28: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/28.jpg)
The code cannot discover relationships
automatically
![Page 29: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/29.jpg)
Cyclic dependencies are forbidden among
components
![Page 30: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/30.jpg)
Some code
![Page 31: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/31.jpg)
(defrecord Database [host port connection] ;; Implement the Lifecycle protocol component/Lifecycle
(start [component] (println ";; Starting database") ;; In the 'start' method, initialize this component ;; and start it running. For example, connect to a ;; database, create thread pools, or initialize shared ;; state. (let [conn (connect-to-database host port)] ;; Return an updated version of the component with ;; the run-time state assoc'd in. (assoc component :connection conn)))
(stop [component] (println ";; Stopping database") ;; In the 'stop' method, shut down the running ;; component and release any external resources it has ;; acquired. (.close connection) ;; Return the component, optionally modified. Remember that if you ;; dissoc one of a record's base fields, you get a plain map. (assoc component :connection nil)))
(defn new-database [host port] (map->Database {:host host :port port}))
![Page 32: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/32.jpg)
(defrecord ExampleComponent [options cache database scheduler] component/Lifecycle
(start [this] (println ";; Starting ExampleComponent") ;; In the 'start' method, a component may assume that its ;; dependencies are available and have already been started. (assoc this :admin (get-user database "admin")))
(stop [this] (println ";; Stopping ExampleComponent") ;; Likewise, in the 'stop' method, a component may assume that its ;; dependencies will not be stopped until AFTER it is stopped. this))
(defn example-component [config-options] (map->ExampleComponent {:options config-options :cache (atom {})}))
![Page 33: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/33.jpg)
(defn example-system [config-options] (let [{:keys [host port]} config-options] (component/system-map :database (new-database host port) :scheduler (new-scheduler) :app (component/using (example-component config-options) [:database :scheduler]))))
![Page 34: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/34.jpg)
example-system
app
ExampleComponent
database
Database
scheduler
Scheduler
(go)
![Page 35: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/35.jpg)
example-systemexample-system
app
ExampleComponent
database
Database
scheduler
Scheduler
app
ExampleComponent
database
Database
scheduler
Scheduler
(reset)
![Page 36: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/36.jpg)
Our examplehttps://github.com/jordillonch/component-example
![Page 37: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/37.jpg)
Shows how component library works and how use a workflow that let you change code and
avoid the JVM restarting
![Page 38: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/38.jpg)
The example is just an API that exposes one
endpoint to do additions
curl http://localhost:8080/math/sum -v --data "value1=1;value2=2"
![Page 39: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/39.jpg)
my-system
application-api
ApplicationApiComponent
context-math-engine
MathOracleSimple
![Page 40: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/40.jpg)
(defn my-system []
(component/system-map
:context-math-engine (new-context-math-engine-system)
:application-api (component/using (new-application-api) [:context-math-engine])))
![Page 41: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/41.jpg)
Demo time :)
![Page 42: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/42.jpg)
Resources
https://github.com/danielsz/system
https://github.com/stuartsierra/component
https://youtu.be/13cmHf_kt-Q
http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded
![Page 43: Component library](https://reader033.vdocuments.site/reader033/viewer/2022042819/55cccbeebb61ebba608b46eb/html5/thumbnails/43.jpg)
Thanks