Fork me on GitHub
#clojure
<
2023-06-03
>
markx17:06:08

What's a modern good way to debug code nowadays? (something that works with Conjure or editor independent)

igrishaev17:06:41

https://github.com/igrishaev/bogus GUI, editor-independent debugger. Just put the #bogus tag before a form and run it

👍 2
seancorfield18:06:02

There's also the "simple" approach of adding tap> calls into your code and using a tap-listener like Portal, Morse, Reveal, etc. I've always found that plenty good enough.

markx18:06:07

Great! Also, is there a good way to inject these debugging helpers into a namespace automatically, using deps? This is to avoid having to require the libs to debug and then remove them. I think leiningen can do it but currently I don't use it.

seancorfield18:06:07

Not sure what you mean by that -- tap> is built-in -- and all the other tools mentioned here have their own instructions on how to use them. The thing I like about tap> is that you don't need to add anything to your code -- you just need to add the tool's deps to your project (under, say, a :dev alias so they're only present when developing and not when you're running "normally", such as in production), and then start the tool up from your REPL either before or after your program is started (from the REPL).

seancorfield18:06:41

My setup for development and debugging uses Portal as a dependency, and the extension in VS Code. Once I've started a REPL ("jacked-in"), I have a hot key that opens Portal as window inside VS Code, and any values I tap> -- either explicitly via Calva's ctrl+alt+t space or via tap> directly in my code -- appear in the Portal window and can be expanded/navigated/viewed in various ways, including graphically. My dev setup can be found in https://github.com/seancorfield/dot-clojure and https://github.com/seancorfield/vscode-calva-setup -- the former has my REPL startup code and user-level dev aliases, the latter has my VS Code / Calva / Portal customizations and Joyride scripts.

seancorfield18:06:33

I have logging wired up to tap> in development, so whatever my program logs also appears in a Portal window while it is running. Another useful tip is that if you have a -> expression, you can add (doto tap>) in between expressions to see each value as it passes through the threading pipeline.

igrishaev18:06:13

> is there a good way to inject these debugging helpers into a namespace automatically, using deps? If you mean bogus, I don't know. As I remember, deps doesn't support Lein's injections. But you can put (require 'bogus.core) into your user or dev namesace.

practicalli-johnny18:06:41

I would say that a step debugger is something I'd use only if tools like tap> and Portal data inspector were not sufficient (they almost always are for me) I send all evaluations to Portal by wrapping the nrepl protocol, so it works with Emacs, Conjure and any editor that used nrepl I usually launch and connect Portal on REPL startup, including the code in dev/user.clj so it's only loaded at dev time (when including`dev` on the path. Example of use with Clojure CLI (deps.edn). The dev/user.clj code also works with Leiningen https://practical.li/clojure/data-inspector/portal/

seancorfield19:06:26

I will mention that a couple of our production processes have nREPL and Portal as dependencies and start both on startup (based on JVM properties and some custom code), so that we can do remote process debugging -- against QA or production -- using the same "dev" setup with a connected editor and Portal displayed locally inside VS Code. Makes for a great debugging experience -- but of course having your editor connected to a running production process is very much "caveat developer" and not every company would even allow such a setup.

🕷️ 2
👨 2
markx19:06:22

> But you can put (require 'bogus.core) into your user or dev namesace. I think this would only make it avaible in the dev namespace though, right? I still need to require it in order to add the #bogus in my code, which is outside the dev namespace.

seancorfield20:06:08

#bogus is a reader macro, so once it is registered (by loading the namespace that defines it), it is available everywhere.

👍 2
👏 2
seancorfield20:06:29

(and the data_readers.clj file that maps #bogus to the function that processes the data -- but that's handled automatically by Clojure with the bogus library on the classpath)

markx20:06:57

Thanks a lot for sharing! @U04V70XH6

markx20:06:52

Maybe I'm missing something but... tap> returns a bool, so you would have to add (tap> some-form-interesting) in the code, instead of just inserting tab> anywhere in the code, like #bogus ? like #p or #spy/p ? If so, sounds like tap> is just like prn to me?

seancorfield20:06:38

Hence my comment about (doto .. tap>) above.

seancorfield20:06:17

prn prints a string. tap> sends data to a listening process. Take a look at Portal, Morse, or Reveal for the sort of things that enables.

seancorfield20:06:30

(doto <expr> tap>) returns the value of <expr>

markx20:06:44

I see. So you normally just use a keyboard shortcut to tap the value you want, instead of adding the (tap> xxx) in the code?

seancorfield20:06:26

It depends on what I need. I have both options. I haven't (yet) added a hot key to wrap an expression in doto tap but that would be easy enough.

markx20:06:54

No not for doto tap, I mean your shortcut ctrl+alt+t space in Calva.

seancorfield20:06:21

As I said, it depends on what I want.

seancorfield20:06:15

When I'm evaluating code from my editor, in general I tap those values. When I'm debugging running code, I generally add tap calls

👍 2
seancorfield21:06:08

(I'm answering in my phone right now while I'm having lunch... I can write more later, or do a screen share to show you)

markx21:06:09

Thanks again for sharing! Now I have a few options to try.

markx21:06:44

Btw @U04V70XH6 This reminds me of your old video of how you fixed a bug, using Atom and REBL at the time. Very helpful

jpmonettas21:06:49

> Also, is there a good way to inject these debugging helpers into a namespace automatically, using deps? @U2DUDHWQY with the latest version of #C03KZ3XT0CF you just setup you deps.edn and you are done, you don't even need to instrument code, and you have time-travel debugging If you want to try it, just run this command :

clj -Sforce -Sdeps '{:deps {} :aliases {:dev {:classpath-overrides {org.clojure/clojure nil} :extra-deps {com.github.jpmonettas/clojure {:mvn/version "1.11.1-3"} com.github.jpmonettas/flow-storm-dbg {:mvn/version "3.6.2"}} :jvm-opts ["-Dclojure.storm.instrumentEnable=true" "-Dclojure.storm.instrumentOnlyPrefixes=user"]}}}' -A:dev
which will bring a repl with Clojure 1.11.1 and the debugger enable. On the repl just eval :tut/basics for a in-repl tutorial. Show up in #C03KZ3XT0CF if you have any questions, it also works for ClojureScript

👍 1
seancorfield21:06:12

@U2DUDHWQY yeah, I need to do some new videos showing the dual Portal window / VS Code setup I use now, including my QA/Production debugging stuff:grin:

igrishaev03:06:38

In emacs, there is a great wrap-region plugin that allows you to wrap a selected region with whatever you want by a certain key. For example

(wrap-region-add-wrapper "(doto " " (tap>))" "t" 'clojure-mode)
Mark any form, press t and it will be wrapped with (todo form (tap>)) . I have similar p and i keys for pretty-print and clojure.inspector.

👍 1
igrishaev03:06:08

for reader tags (bogus, hashp, etc), there is another approach that's free from any plugins:

(defun bogus ()
  (interactive)
  (insert "#bogus"))

(global-set-key (kbd "C-c b") 'bogus)
It works in two ways: either by pressing C-c b or running an interactive command M-x bogus

seancorfield17:06:27

I decided to add "wrap with doto tap>" for VS Code, using Joyride: https://github.com/seancorfield/vscode-calva-setup/blob/develop/joyride/scripts/tap.cljs -- if your cursor is in the middle of a -> pipeline, it inserts (doto tap>) otherwise it wraps the current form at the cursor with (doto ... tap>) which addresses my two use cases.

Olical17:06:32

Conjure does technically have CIDER debugging support which is listed on the wiki I think. However, I'll be working full time for a few weeks soon on the Clojure DAP system, which will integrate Clojure with various GUI debuggers across the ecosystem. Including neovim!

🎉 2
markx17:06:19

Yeah I saw that in the wiki, so I was thinking while waiting for your new DAP plugin I'll ask what people use these days. (I haven't written Clojure for a while now)

practicalli-johnny18:06:46

Conjure works nicely with Portal, inspecting the results of a function call can quickly help find issues

markx18:06:07

Great! Also, is there a good way to inject these debugging helpers into a namespace automatically, using deps? This is to avoid having to require the libs to debug and then remove them. I think leiningen can do it but currently I don't use it.