torsdag 6 augusti 2015

Boot - not yet

Leiningen gets messy when trying to define complicated build paths combining Clojure, ClojureScript and possibly multiple artefacts, CSS compilations etc in one build process/configuration file.

Since Clojure 1.7.0 there can be support for multiple platforms in one codebase through cljc-files. This is awesome but must be leveraged.

Boot solves a lot of these problems by composing builds just like ordinary functions. To overcome problems with mutable file systems, boot uses an immutable file system called Filesets. Very clever.

I'm investigating wheter a semi-complex build process would benefit from moving from two repos containing a backend server and an administration client respectively.

I found out that there's no selective auto-reloading of code like in the amazing Figwheel. This limits the usability of boot for doing rich web app development at the moment. I'm sure this will change very soon.

I'll stick with Leiningen for some more, but keeps my eyes wide open for improvements in the Boot project.

söndag 5 april 2015

Terse explanation of re-frame

Re-frame is an single page web app event-loop machinery built on Reagent/React.js.

Application state app-db is stored in one (1) reagent atom.

By using reagent's reactions, one can build up a graph, chained reactions, where more costly operations can be "shielded" behind reactions which wont report a change if the reactions view from a new app-db is the same immutable data structure as it was in the previous app-db.

The redrawing of the DOM/screen is triggered by requestAnimationFrame. Given a standard refresh rate of 60 Hz, this trigger will occur every 16.67 ms, if the program is done with it's previous recalculation by then.

Re-frame uses hiccup-style syntax feed to the Reacts Virtual DOM.

There can be several related reagent atom-constructs called reactions, containing derived state ("views") of the app-state.

To make state changes in the application, initialization code or callback functions from event-emitters like the DOM, timers, network connections should send dispatch messages. These are put in a core.async channel and handled by registered handlers.

There's two special types of dispatch, dispatch-sync which handles the event directly, and does not put it in the core.async channel. The other special dispatch is putting ^:flush-dom metadata on the dispatched event, which doesn't wait for a requestAnimationFrame event before re-rendering the reactive data structures.

Events are sent as a very simple vector format. Like a lisp sexpression the first item of the vector should be a symbol (keyword) for which function (handler) that should be handling this sexpression (event). The rest of the vector is a free-form argument vector.

Handlers are registered with (register-sub :name-of-event handler-fn)

The handler-fn has the same purpose as a clojure reduce-function, its arguments are the app-state (derefed!) and the incoming event.

The handler-fn returns the new application-state, which re-frame will reset! into app-db.

Re-frame offers a simple middleware-abstraction, where debug/logging-statements can be put. Another powerful middleware is path, that works as a lens, making the handler-fn simpler by making it work on a specific path in the app-db.

I guess one could create some middleware for simplifying the use of datascript as application state atom.

The handler should implement the logic on what should happend to an incoming event, potentially based on the app-db state.  The re-frame readme mentions finite state machines as a fruitful abstraction.

söndag 29 mars 2015

bigdec, decimal?, integer?

The function bigdec returns a java.math.BigDecimal.

If you want to test it you can use decimal? instead of defining your own function bigdec?

integer? does not test the value for not having decimals, but for being some natively decimal number type.

(defn no-decimal-part?
  "converts the number to bigdec,
  make sure a division by
  zero has remainder exactly zero"
  [number]
  (zero? (.remainder (bigdec number) java.math.BigDecimal/ONE)))


is better to use to make sure the bigdec does not have any decimals.