Based on the core.async library Clojure allows a CSP programming style, so your system is made up of asynchronous, lightweight processes which communicate through channels.
The talk shows common pitfalls in classic OO GUI
approaches and shows how to tackle some of these problems in a fundamentally simpler way.
11. A real-world OO GUI architecture
ControllerViewModel
ViewImpl
UI Toolkit Impl
UIView
Other parts of the system
two-way
databinding
updates
action
events
only data!
12. Benefits so far
ControllerViewModel
ViewImpl
UI Toolkit Impl
UIView
Other parts of the system
two-way
databinding
updates
action
events
only data!
Dumb Views => generated code
Dumb ViewModels => generated code
Controllers are unit-testable
13. Remaining annoyances
ControllerViewModel
ViewImpl
UI Toolkit Impl
UIView
Other parts of the system
two-way
databinding
updates
action
events
only data!
Unpredicatble execution paths
Coordination with long runnning code
Merging of responses into ViewModels
Window modality is based on a hack
15. events
state
1) is a representation of system state
A user interface ...
{:name {:value "Foo"
:message nil}
:addresses [{:name "Bar"
:street "Barstr"
:city "Berlin"}
{:name "Baz"
:street "Downstr"
:city "Bonn"}]
:selected [1]}
16. events
state
1) is a representation of system state
2) allows us to transform system state
A user interface ...
{:name {:value "Foo"
:message nil}
:addresses [{:name "Bar"
:street "Barstr"
:city "Berlin"}
{:name "Baz"
:street "Downstr"
:city "Bonn"}]
:selected [1]}
2)
1)
17. A user interface ...
… consists of two functions ...
which – for technical reasons –
need to be executed asynchronously.
[state] → ⊥ ;; update UI (side effects!)
[state event] → state ;; presentation logic
( )
19. GUI can become unresponsive
Java FX application thread
Event loop
Your code
Service call
What happens
if a service call
takes seconds?
20. Keep GUI responsive (callback based solution)
Service call
Your code 1
Your code 2
Use other thread
Java FX application thread
Event loop Some worker thread
Delegate execution
Schedule to
event loop
21. Meet core.async: channels go blocks+
Based on Tony Hoare's CSP* approach (1978).
Communicating Sequential Processes
*
(require '[clojure.core.async :refer
[put! >! <! go chan go-loop]])
(def c1 (chan))
(go-loop [xs []]
(let [x (<! c1)]
(println "Got" x ", xs so far:" xs)
(recur (conj xs x))))
(put! c1 "foo")
;; outputs: Got bar , xs so far: [foo]
a blocking read
make a new channelcreates a
lightweight
process
async write
readwrite
22. The magic of go
sequential code
in go block
read
write
macro
expansion
state
machine
code snippets
23. Keep GUI responsive (CSP based solution)
core.async process
core.async process
Java FX application thread
Your code
Update UI
<! >!
<!
put!
go-loop
one per viewexactly one
events
state
25. Properties of CSP based solution
„Blocking read“ expresses modality
A views events channel takes ALL async results
✔ long-running calculations
✔ service calls
✔ results of other views
Each view is an async process
Strong separation of concerns
27. JavaFX + Tk-process + many view-processes
JavaFX
Many view processes
One toolkit oriented
process
(run-view)
(run-tk)
Event handler
(spec) (handler)
Each view has one
events channel
28. Data representing view state
:id ;; identifier
:spec ;; data describing visual components
:vc ;; instantiated JavaFX objects
:data ;; user data
:mapping ;; mapping user data <-> VCs
:events ;; core.async channel
:setter-fns ;; map of update functions
:validation-rule-set ;; validation rules
:validation-results ;; current validation messages
:terminated ;; window can be closed
:cancelled ;; abandon user data
29. (spec) - View specification with data
(defn item-editor-spec
[data]
(-> (v/make-view "item-editor"
(window "Item Editor"
:modality :window
:content
(panel "Content" :lygeneral "wrap 2, fill"
:lycolumns "[|100,grow]"
:components
[(label "Text")
(textfield "text" :lyhint "growx")
(panel "Actions" :lygeneral "ins 0"
:lyhint "span, right"
:components [(button "OK")
(button "Cancel")])])))
(assoc :mapping (v/make-mapping :text ["text" :text])
:validation-rule-set (e/rule-set :text (c/min-length 1))
:data data)))
attach more
configuration data
a map with initial user data
specify contents
32. You can easily build it yourself!
JavaFX API
update
build
Toolkit
Impl
View process fns
Toolkit process fns
core.clj
tk.clj
builder.clj
binding.clj
bind
< 400 LOC