re-frame-trace
let's you inspect the inner workings of a running re-frame
application. It presents as a programmer's dashboard, delivering curated insight and illumination. A 10x programmer is the one with 10x more knowledge and insight.
re-frame
applications are computationally regular. First an event happens,
and then boom, boom, boom go a series of known computational steps (aka dominoes),
in a known order. When this chain reaction completes,
a re-frame
app enters a quiescent state waiting for another
event to kick off the next iteration of the same process.
Each re-frame
event and its consequent computation forms a bounded "epoch"
which can be inspected, analysed and understood independently of other epochs. This
tool is epoch-oriented - it shows you one at a time.
And, yes, it has "time travel debugger" capabilities - you can go
backwards and forwards through epochs - but that's really not the most interesting or powerful aspect of what re-frame-trace
delivers.
As it runs, re-frame
logs "trace" as data, and this provides an x-ray (MRI?) of your app's inner
functioning. At its most basic level, re-frame-trace
is a consumer, processor and presenter
of trace data.
While re-frame is a functional framework, it is
strongly defined by its "data oriented" design. re-frame
"flows" data, in a loop, through the functions you provide.
To understand what is happening in a re-frame
app, you must understand
what data is "happening".
So, clearly, data is at the core of re-frame-trace
for both of the reasons
just outlined, but its importance is even more base and fundamental than that.
Each time you put a println
into your program, you are printing out what?
And why? Invariably, it is data which fuels your debugging investigation,
confirming your current hypothesis, or not.
And when you write your unittests, you represent your expections as what? Correct data is the very definition of success.
So, for debugging and understanding activities, more data, more easily is winning. Going back
and adding a println
shouldn't be necessary. All the data you need should already
be captured, and it should be readily available in your REPL for further experimentation.
Perhaps you have seen LightTable in action?
In the small, it is a delightfully productive debugging environment because it co-renders code and the data generated by running the code. The data provides a "paper trail" which brings the code to life, revealing its dynamics and enriching a programmer's understanding.
re-frame-trace
has a similar goal, although the method is different.
Observing raw data trace is both interesting and valuable, but it isn't enough. First, we want to leverage this data for insights. And, second, there's often too much data - you can drown in the detail.
So, re-frame-trace
tries to be a "dashboard" which curates this
"raw data" into "information" through various kinds of analysis
and "roll ups". It should deliver insight "at a glance", while still allowing
you to drill down into the detail.
Four ways:
It helps you to learn re-frame
. Simply looking at
the "raw traces" provides insight into how it operates. Even experienced
re-framians, er, like me, have learned a lot.
It helps you to explore and learn an unfamiliar re-frame
codebase.
When I click, over here, on this "X" button, it shows me what event is dispatch
-ed
and in what namespace the associated event handler is registered. And,
"oh look, that's interesting - four subscriptions recalculated". Etc.
It helps you with debugging. You see an x-ray of your app's functioning.
In particular, it will assist you to write and debug
event handlers, which is useful because they hold most of the logic
in your re-frame
apps.
It helps you to find performance problems and/or detect where there is unnecessary computation occurring.
Point 3, is primary, of course. But Point 2 is almost as important because we all spend a lot of our time groking unfamiliar codebases. Being able to observe the inner workings of a running app is a great way to bring code to life, reveal key features, and build a cognative map of how the code is structured.
Some of the claims above are aspirational.
re-frame-trace
remains a WIP.
We debated internally about the name re-frame-trace
. While -trace
is accurate, it is 100% sausage because it talks about low level function, and not higher level benefit (sizzle, sizzle). I wanted to call it vox-datum
(voice of the data) but that was cruelly rejected, for reasons I don't care to remember. The pain. I mean, who the hell doesn't like a Latin name?? Philistines. Anyway, -insight
and -illumination
are the benefits, but they made the name waaaay too long. Naming things - it's just a nightmare! As is inertia. So, -trace
it remains.
Update: a name change to re-frame-10x
is on the cards. Disapointingly, my latest suggestion, TenMinutesByTractor
, was also rejected. I shake my head. Why can noone see that we're all "code farmers" by profession?
Slightly out of date, but indicative ...
If you are using leiningen, modify project.clj
in the following ways. When puzzling over the various possible leiningen configurations, it's often helpful to look at a sample project.clj.
Update your re-frame dependency to at least 0.10.5
- [re-frame "0.10.5"]
.
Add re-frame-trace as a dev dependency by placing [day8.re-frame/trace "VERSION"]
within :profiles :dev :dependencies
. For example:
:profiles
{:dev
{:dependencies [[some-other-package "0.0.0"]
[day8.re-frame/trace "0.0.0 (see version above)"]] }}
If your project uses React 16 and Reagent 0.8.0-alpha2 (or higher) then you will need to add the qualifier -react16
to the version, e.g. [day8.re-frame/trace "0.0.0-react16"]
.
Locate the :compiler
map under :dev
and add:
:closure-defines {"re_frame.trace.trace_enabled_QMARK_" true}
:preloads [day8.re-frame.trace.preload]
For example:
{:builds
[{:id "dev"
:source-paths ["src" "dev"]
:compiler {...
:closure-defines {"re_frame.trace.trace_enabled_QMARK_" true}
:preloads [day8.re-frame.trace.preload]
}}]}
cljs-devtools is not required to use re-frame-trace, but it is highly recommended.
Make sure you have followed all of the installation instructions above.
Start up your application.
Once it is loaded, focus the document window and press ctrl-h
to slide open the trace panel and enable tracing.
When the panel is closed, tracing is disabled.
lein clean
day8.re_frame.trace.factory_reset_BANG_()
in the JavaScript console.day8.re-frame.trace
from your browser's Local Storage.re-frame is instrumented - all important activity generates trace data.
re-frame-trace
consumes this trace data and renders useful visualisations of the re-frame
process. Currently, re-frame's tracing capabilities are in alpha and are subject to change at any time. We're testing the utility of the the trace by building an app on top.
By default, re-frame tracing is "compiled out", so it won't impose a performance cost in production. The trade-off here is that you need to explicitly enable it in development.
The preloads option (:preloads [day8.re-frame.trace.preload]
) has to be set in order to automatically monkeypatch Reagent to add appropriate lifecycle hooks. Yes this is gross, and yes we will make a PR to reagent to add proper hooks, once we know exactly what we need. The preload namespace also injects a div containing the devtools panel into the DOM.
If you want to work on re-frame-trace, see DEVELOPERS.md.
Can you improve this documentation? These fine people already did:
Mike Thompson, Daniel Compton, chris (daiyi), Dexter Gramfors, Matthew Jaoudi, Saskia Lindner, chris & chris⚡Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close