I have debugged a lot of code in my life and got pretty proficient in it at least in a specific language and ide. Do you guys think, that debugging in clojure by examining functions in the repl is faster than debugging? Is my question clear?
It depends on the situation. Some things are faster, some are not. I guess the heuristic here can be something like "if you start thinking about how you'd debug it in a REPL, just stop thinking and debug it with a debugger". After all, a proper debugger lets you evaluate arbitrary Clojure forms, and as such it's not all that far from a REPL.
If you debug your own code it is maybe faster. If you debug code that is not by you, I think, it will be slower. In other languages debugging is often an intuitive tool to learn how the code works. Maybe this is an abuse of the debugger. But people like to experiment. And debugging brings you directly to a realistic situation so that you can start experimenting. Debugging in Clojure is more an intimate affair with your code. For example if you want to set a breakpoint or a condition in Calva you have to write it into the code. It is not just clicking somewhere. If you don't already know how something is called and what data structures are used, you cannot start with the REPL.
I'm one of those folks who has almost never used an actual debugger (in 45+ years of software development).
I used to use one sometimes back when I wrote C and C++. I very occasionally used one in Java. I've never used a debugger with a dynamic language in general or Clojure specifically.
For Clojure, I always work with the REPL connected to my editor. I have hot keys to define a value for a selected symbol and to turn a symbol/expr pair in a let into a def, so that I can eval any expr inside a fn. I use tap> heavily, with Portal (in VS Code), to view/navigate any runtime data I want to inspect (and often leave the tap> calls in the code since they're harmless in production).
I suspect this may be because I started my career with assembly and COBOL so you tended to debug things by printing out the core dump and going through the hex code... The few debugging tools available back then were fairly primitive and it was often very time-consuming to get a complex program into the state you needed for a debugging session. What "youngsters" are used to as debuggers nowadays didn't really appear until the mid/late-'90s 😄
Assuming a large new to you codebase - how do you figure out what's going on when it's a multimethod and protocol galore? Especially when there are overrides, even dynamic ones.
Use the REPL. Use Spec. Navigate via the IDE (search, go to definition). These days, I also ask Copilot to analyze the code and describe the architecture to me.
Microsoft's AgentForge can be a very helpful tool too (notionally, it analyzes a codebase to create skills and instructions for agents/AI, but those Markdown docs it produces are great for humans too).
Search and go to definition don't help much with utterly dynamic stuff. :( I also don't use debugger all that often because such stuff usually doesn't come up often, fortunately. But as soon as I start thinking "what the...", I find it to be much faster to just throw a bunch of conditional breakpoints and "step into" 15 times.
With Clojure I completely changed the way how I learn or investigate things. Instead of playing around with something and naively navigate through the code I read. I read the API, I read the documentation. I read comments. And often the code is also like a book. It is about reading and absorbing information. For me that is so much more satisfying and more professional than just starting the debugger. Before Clojure I completely forgot how to systematically learn something.
@p-himik You are expressing my fear.
I spend less time debugging clojure code because our clojure code has fewer bugs 😉 For seven straight years I worked on a 1M line c++ codebase, and got very, very good at visual studio's debugger. The debugger in CIDER is better; it's less polished, but more effective. > examining functions in the repl This undersells it, with the CIDER debugger, I can pause execution at any form in any function, and then still have the complete power of the repl (while execution is paused). Namely I can write programs that interrogate and modify any part of the complete state of the running program. It's a qualitatively different experience from setting a breakpoint in visual studio, running the program to that point, and then looking at a mostly static table of local values. And really, it's only the most pernicious problems that make me reach for CIDER's debugger at all; logging, tracing, and tapping in the repl are all typically faster, and suffice for most problems. It's a game-changer to be able to recompile a single function with a bit of tracing in it, temporarily, while the program continues to run. The idea of waiting to recompile and link an entire program (even incrementally, in parallel, with a build farm) to investigate a small component just seems weird now.
@lifeainteasy What is that fear? Troubles of debugging code with a high degree of dynamism? That might very well be attributed to the nature of my work as an independent contractor. :) Not everyone will see things I've seen.
over time I have transitioned most of my interactive debugging into unit testing. in most cases I can make a program structure that turns any logic complex enough to require debugging into a clause in a pass / fail test
though I will also capture data in an atom in a running system, to verify things that aren't obvious in the code at rest
but even in that case I move the data if possible into an input to a test case
@didibus thank you, will need to dive deeper in flow storm and the cider debugger
I have found the CIDER debugger useful to step through recursive code to see where I am getting different values than expected. I use the REPL to evaluate all the code I write and use, as I am working with it. This gives feedback straight away and leads to fewer bugs to hunt down 😇 For an unfamiliar codebase I use LSP references to help navigate whats useful. Eventually I may try an 'AI' tool to help with this kind of software archeology 😆
@p-himik My fear, I will need a debugger. Also I like to get to know the data flow by debugging.
Debugger is nice. Flowstorm is great and also cider debugger and such are great. But also sometimes just repl/printing is faster. It depends how much step by step you need.