SlideShare a Scribd company logo
JavaFX GUI architecture
with Clojure core.async
@friemens
JavaFX GUI architecture with Clojure core.async
GUIs are challenging
GUI implementation causes significant LOC numbers
GUIs require frequent changes
Automatic GUI testing is expensive
GUI code needs a suitable architecture
Model Controller
View
Model Controller
View
MVC makes you think of mutable things
MVC Variations
MVP
a.k.a
Passive View
View
Model
Presenter View
Model
View
Model
MVVM
a.k.a
PresentationModel
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!
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
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
Think again... what is a user interface?
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]}
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)
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
( )
Asynchronity in GUIs
GUI can become unresponsive
Java FX application thread
Event loop
Your code
Service call
What happens
if a service call
takes seconds?
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
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
The magic of go
sequential code
in go block
read
write
macro
expansion
state
machine
code snippets
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
Expensive service call: it's your choice
(def events (chan))
(go-loop []
(let [evt (<! events)]
(case ((juxt :type :value) evt)
[:action :invoke-blocking]
(case (-> (<! (let [ch (chan)]
(future (put! ch (expensive-service-call)))
ch))
:state)
:ok (println "(sync) OK")
:nok (println "(sync) Error"))
[:action :invoke-non-blocking]
(future (put! events
{:type :call
:value (-> (expensive-service-call)
:state)}))
[:call :ok] (println "(async) OK")
[:call :nok] (println "(async) Error")))
(recur))
blocking
non-
blocking
ad-hoc new channel
use views events channel
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
A glimpse of
https://github.com/friemen/async-ui
prototype
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
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
(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
(handler) - Event handler of a view
(defn item-editor-handler
[view event]
(go (case ((juxt :source :type) event)
["OK" :action]
(assoc view :terminated true)
["Cancel" :action]
(assoc view
:terminated true
:cancelled true)
view)))
Using a view
(let [editor-view (<! (v/run-view
#'item-editor-spec
#'item-editor-handler
{:text (nth items index)}))]
. . .)
(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)))
(defn item-editor-handler
[view event]
(go (case ((juxt :source :type) event)
["OK" :action]
(assoc view :terminated true)
["Cancel" :action]
(assoc view
:terminated true
:cancelled true)
view)))
a map with initial user data
spec handler
calling view process waits for callee
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
Wrap up
MVC leads to thinking in terms of mutation
UIs introduce asynchronity
UI is a reactive representation of system state
Thank you for listening!
Questions?
@friemens
www.itemis.de@itemis
https://github.com/friemen/async-ui

More Related Content

PDF
«От экспериментов с инфраструктурой до внедрения в продакшен»​
PDF
Redux. From twitter hype to production
PDF
Angular performance slides
PDF
Intro to ColdBox MVC at Japan CFUG
PDF
An Introduction To Testing In AngularJS Applications
PDF
Scheduling tasks the human way - Brad Wood - ITB2021
PDF
Service Oriented Architecture in Magento 2
PDF
MBLTDev15: Cesar Valiente, Wunderlist
«От экспериментов с инфраструктурой до внедрения в продакшен»​
Redux. From twitter hype to production
Angular performance slides
Intro to ColdBox MVC at Japan CFUG
An Introduction To Testing In AngularJS Applications
Scheduling tasks the human way - Brad Wood - ITB2021
Service Oriented Architecture in Magento 2
MBLTDev15: Cesar Valiente, Wunderlist

What's hot (20)

PDF
React Native: JS MVC Meetup #15
PDF
MBLTDev15: Egor Tolstoy, Rambler&Co
KEY
Groovy Ecosystem - JFokus 2011 - Guillaume Laforge
PDF
Reactive, component 그리고 angular2
PPTX
C#on linux
PDF
Unity and WebSockets
PDF
Load testing with gatling
PDF
"Service Worker: Let Your Web App Feel Like a Native "
PDF
Svelte JS introduction
PDF
Metrics by coda hale : to know your app’ health
PDF
Mobile Day - React Native
PDF
Workshop 23: ReactJS, React & Redux testing
PPTX
Academy PRO: React JS. Redux & Tooling
PDF
Workshop 12: AngularJS Parte I
ODP
Javascript frameworks: Backbone.js
PDF
React JS and Redux
PPTX
React + Redux Introduction
PPTX
Protractor framework architecture with example
PDF
Redux vs Alt
PDF
Protocol Oriented MVVM - Auckland iOS Meetup
React Native: JS MVC Meetup #15
MBLTDev15: Egor Tolstoy, Rambler&Co
Groovy Ecosystem - JFokus 2011 - Guillaume Laforge
Reactive, component 그리고 angular2
C#on linux
Unity and WebSockets
Load testing with gatling
"Service Worker: Let Your Web App Feel Like a Native "
Svelte JS introduction
Metrics by coda hale : to know your app’ health
Mobile Day - React Native
Workshop 23: ReactJS, React & Redux testing
Academy PRO: React JS. Redux & Tooling
Workshop 12: AngularJS Parte I
Javascript frameworks: Backbone.js
React JS and Redux
React + Redux Introduction
Protractor framework architecture with example
Redux vs Alt
Protocol Oriented MVVM - Auckland iOS Meetup
Ad

Viewers also liked (20)

PPTX
FlatGUI: Reactive GUI Toolkit Implemented in Clojure
PDF
Аренда класса
PDF
Трансдюсеры, CSP каналы, неизменяемые структуры данных в JavaScript
PDF
Функциональное программирование в браузере / Никита Прокопов
PDF
CodeFest 2013. Прокопов Н. — Зачем вам нужна Clojure?
PDF
Построение мультисервисного стартапа в реалиях full-stack javascript
PDF
2014.12.06 05 Антон Плешивцев — Разбираем естественные языки на Lisp'е
PPTX
Назад в будущее! …и другие мысли о подготовке программистов в ВУЗах
PDF
JavaScript завтра / Сергей Рубанов (Exante Limited)
PPTX
Hacking JavaFX with Groovy, Clojure, Scala, and Visage
PDF
Алексей Романчук «Реактивное программирование»
PDF
Clojure - Why does it matter?
PDF
Some basic FP concepts
PDF
ClojureScript Introduction
PDF
Clojure+ClojureScript Webapps
PDF
Making design decisions in React-based ClojureScript web applications
PDF
ClojureScript - A functional Lisp for the browser
PDF
"Content Security Policy" — Алексей Андросов, MoscowJS 18
PPTX
Monte carlo simulation
PDF
FlatGUI: Reactive GUI Toolkit Implemented in Clojure
Аренда класса
Трансдюсеры, CSP каналы, неизменяемые структуры данных в JavaScript
Функциональное программирование в браузере / Никита Прокопов
CodeFest 2013. Прокопов Н. — Зачем вам нужна Clojure?
Построение мультисервисного стартапа в реалиях full-stack javascript
2014.12.06 05 Антон Плешивцев — Разбираем естественные языки на Lisp'е
Назад в будущее! …и другие мысли о подготовке программистов в ВУЗах
JavaScript завтра / Сергей Рубанов (Exante Limited)
Hacking JavaFX with Groovy, Clojure, Scala, and Visage
Алексей Романчук «Реактивное программирование»
Clojure - Why does it matter?
Some basic FP concepts
ClojureScript Introduction
Clojure+ClojureScript Webapps
Making design decisions in React-based ClojureScript web applications
ClojureScript - A functional Lisp for the browser
"Content Security Policy" — Алексей Андросов, MoscowJS 18
Monte carlo simulation
Ad

Similar to JavaFX GUI architecture with Clojure core.async (20)

PPTX
Highload JavaScript Framework without Inheritance
PPT
Web services, WCF services and Multi Threading with Windows Forms
PDF
Jsf2 html5-jazoon
PDF
Java Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
PPT
PDF
Google Web Toolkit
PDF
The fundamental problems of GUI applications and why people choose React
PPT
Architectural Patterns and Software Architectures: Client-Server, Multi-Tier,...
PPTX
Jsf presentation
PPTX
Windows 8 for Web Developers
PDF
Java Web Programming [8/9] : JSF and AJAX
PPTX
PDF
Airflow presentation
PDF
Developing maintainable Cordova applications
PPT
When Web Services Go Bad
PDF
using Mithril.js + postgREST to build and consume API's
PDF
Web Performance Part 4 "Client-side performance"
PPTX
Developing your first application using FIWARE
PDF
MOPCON 2014 - Best software architecture in app development
PPTX
Democratizing Serverless
Highload JavaScript Framework without Inheritance
Web services, WCF services and Multi Threading with Windows Forms
Jsf2 html5-jazoon
Java Web Programming on Google Cloud Platform [3/3] : Google Web Toolkit
Google Web Toolkit
The fundamental problems of GUI applications and why people choose React
Architectural Patterns and Software Architectures: Client-Server, Multi-Tier,...
Jsf presentation
Windows 8 for Web Developers
Java Web Programming [8/9] : JSF and AJAX
Airflow presentation
Developing maintainable Cordova applications
When Web Services Go Bad
using Mithril.js + postgREST to build and consume API's
Web Performance Part 4 "Client-side performance"
Developing your first application using FIWARE
MOPCON 2014 - Best software architecture in app development
Democratizing Serverless

Recently uploaded (20)

PDF
Encapsulation theory and applications.pdf
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PPTX
Big Data Technologies - Introduction.pptx
PDF
Review of recent advances in non-invasive hemoglobin estimation
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
Dropbox Q2 2025 Financial Results & Investor Presentation
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPT
Teaching material agriculture food technology
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Approach and Philosophy of On baking technology
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Unlocking AI with Model Context Protocol (MCP)
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Encapsulation theory and applications.pdf
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Advanced methodologies resolving dimensionality complications for autism neur...
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Big Data Technologies - Introduction.pptx
Review of recent advances in non-invasive hemoglobin estimation
Programs and apps: productivity, graphics, security and other tools
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Encapsulation_ Review paper, used for researhc scholars
Dropbox Q2 2025 Financial Results & Investor Presentation
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Teaching material agriculture food technology
The AUB Centre for AI in Media Proposal.docx
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
20250228 LYD VKU AI Blended-Learning.pptx
Approach and Philosophy of On baking technology
The Rise and Fall of 3GPP – Time for a Sabbatical?
Unlocking AI with Model Context Protocol (MCP)
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx

JavaFX GUI architecture with Clojure core.async

  • 1. JavaFX GUI architecture with Clojure core.async @friemens
  • 4. GUI implementation causes significant LOC numbers
  • 6. Automatic GUI testing is expensive
  • 7. GUI code needs a suitable architecture
  • 9. Model Controller View MVC makes you think of mutable things
  • 10. MVC Variations MVP a.k.a Passive View View Model Presenter View Model View Model MVVM a.k.a PresentationModel
  • 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
  • 14. Think again... what is a user interface?
  • 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
  • 24. Expensive service call: it's your choice (def events (chan)) (go-loop [] (let [evt (<! events)] (case ((juxt :type :value) evt) [:action :invoke-blocking] (case (-> (<! (let [ch (chan)] (future (put! ch (expensive-service-call))) ch)) :state) :ok (println "(sync) OK") :nok (println "(sync) Error")) [:action :invoke-non-blocking] (future (put! events {:type :call :value (-> (expensive-service-call) :state)})) [:call :ok] (println "(async) OK") [:call :nok] (println "(async) Error"))) (recur)) blocking non- blocking ad-hoc new channel use views events channel
  • 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
  • 30. (handler) - Event handler of a view (defn item-editor-handler [view event] (go (case ((juxt :source :type) event) ["OK" :action] (assoc view :terminated true) ["Cancel" :action] (assoc view :terminated true :cancelled true) view)))
  • 31. Using a view (let [editor-view (<! (v/run-view #'item-editor-spec #'item-editor-handler {:text (nth items index)}))] . . .) (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))) (defn item-editor-handler [view event] (go (case ((juxt :source :type) event) ["OK" :action] (assoc view :terminated true) ["Cancel" :action] (assoc view :terminated true :cancelled true) view))) a map with initial user data spec handler calling view process waits for callee
  • 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
  • 34. MVC leads to thinking in terms of mutation UIs introduce asynchronity UI is a reactive representation of system state
  • 35. Thank you for listening! Questions? @friemens www.itemis.de@itemis https://github.com/friemen/async-ui