This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-10-18
Channels
- # announcements (12)
- # babashka (6)
- # beginners (62)
- # calva (3)
- # cider (41)
- # clerk (5)
- # clojure (192)
- # clojure-bay-area (1)
- # clojure-europe (14)
- # clojure-norway (97)
- # clojure-uk (6)
- # clojuredesign-podcast (4)
- # clojurescript (30)
- # code-reviews (7)
- # cursive (32)
- # datahike (4)
- # datomic (35)
- # docker (8)
- # emacs (8)
- # events (1)
- # fulcro (13)
- # helix (19)
- # hoplon (4)
- # hyperfiddle (37)
- # jobs-discuss (10)
- # membrane (11)
- # missionary (19)
- # off-topic (28)
- # polylith (8)
- # portal (10)
- # practicalli (8)
- # re-frame (31)
- # reitit (6)
- # shadow-cljs (39)
- # timbre (3)
- # vim (1)
- # xtdb (6)
Hi guys. Love the podcast. One thing I have struggled with in "composition" is now to build/structure your code so that you can walk through it step by step with new data (especially when you find a problem and need to go dig to fix it). I have tried flowstorm & various debuggers, but have yet to find a way to structure the code to make it easy to go step through. Let's assume, I'm passing through a main data structure like a techml dataset or clojure map, or vector of maps. This is my "one data structure" and I have 100 functions that operate on it. I have fiddle code for each function right below it's definition, I also have an "integration" comment block but it's only for integrations, instead of testing functions individually. A couple common problems are as follows: 1. I am using let blocks in my functions, and I am not able to step through what the value of the variables in the let block are, and instead I am recreating each of the let bindings, in my fiddle code with new data in order to get visibility. 2. I struggle with getting that state of my datastructure at step #57 (out of 100) of my flow (if its new data) and inspecting it there. I'm curious what you guys do when you want to trace through the execution of a large data transformation. Do you lean on logging, debuggers, println's, fiddle code, unit tests, integration tests, something cool I don't know about? And how and when do you reach for each in different situations?
Awesome that you started his thread!
I think #flow-storm helps with this. You can look at code at a particular frame, and have access to the let bindings, and evaluate code with those values and things like that. But you say you have tried flow-storm, so maybe it’s not as convenient as you want it to be? I would ask in the channel about it. Super responsive support there.
The major Clojure editor environments all have debuggers. With Calva’s debugger you can step the code and have access to the bindings, and can evaluate code using them. I demo that shortly here: https://clojurians.slack.com/archives/CBE668G4R/p1695764358776319?thread_ts=1695762446.918239&cid=CBE668G4R
I don’t see you mention tap>
. I find it very useful and together with tools such a #portal you can get really great observability of things in your app with them. May I plug my little macro library taplet here? Doing it! 😃 https://github.com/PEZ/taplet It lets you tap let bindings, and also has a #t
reader tag for easily tapping out any value.
Also do not see you mention inline defs. Sometimes, instead of using a comment form, you can use the actual form and place some (def foo foo)
in them, where the first foo
is a namespace symbol and the second foo
is some local variable, (function argument or binding). Then you can evaluate foo
to inspect it, and evaluate forms inside your function using foo
. I use this A LOT. Tools like Snitch https://github.com/AbhinavOmprakash/snitch by @U02CVMEFEUF makes this a lot easier than having to type all those inline defs.
Sometime inline def of that one data structure flowing through your app may offer a lot of observability. I use dissoc
and select-keys
to get some focus on what about the data structure I want to observe in some given situation.
Thanks @U0ETXRFEW I'll dig into each of these. We are also Calva user's at my company and appreciate all the work you have put into it 🙂
Let blocks can have println, tap> or log library expressions added, to show any desirable values, typically binding them to the _
by convention (indicating that _ name is not of interest
If it's a fairly well known function that's behaving strangely, especially one that iterates over data, then a step debug tool can be very useful
Emacs cider-debug instruments a function and will step through automatically created breakpoints when calling that function, showing intermediate values at the current point.
Flowstorm debugger seems similar, although I haven't used it personally
For iterative functions, generate a data structure that shows all the iterations, then inspect that data as required. Either use an accumulator in a loop or an atom outside the function
With a less understood function it is very effective to simply deconstruct a function, this is software after all and adding extra code is easy.
Deconstructing code the way lisp was taught. (I.e the SCIP videos)
I copy parts or all of the function I want to test into a comment form, adding specific values if required and evaluate in the repl quick to create a (comment form underneath the function examine
Personally I would never recommend an inline def as it's incorrect use of the Clojure language. Unfortunately I've seen it used in very public training materials without highlighting that it's abnormal use of the syntax and scope. This confuses people trying to learn the language effectively