Live data from Hacker News

Notes on debugging Clojure code

eli.thegreenplace.net

1–10 of 50 posts

Re: Notes on debugging Clojure code

#2
Another trick is to define temporary inline vars. If I have some Ring handler, it can be quite annoying to construct a request by hand. Instead, I can do something like:

    (defn foo-handler [{{:strs [authorization]} :headers :as req}]
      (def *req req)
      (def *auth authorization)
      ...)
Then fire off a request in my browser and simply proceed to play around with `req` and `auth` in my editor/REPL, which is where I am running my local server from.

Re: Notes on debugging Clojure code

#4
A few more tricks:

- CIDER, the de-facto Clojure environment for Emacs, has a debugger[1]. This is also true for some of the larger IDEs, like Cursive.

- Timbre[2] has a number of cool debugging macros, especially spy, which you can tack onto any expression and it'll log it for you. Very useful, similar to the macro in the post, except you don't have to write it :)

I really can't overestimate how valuable a real REPL-driven development environment is.

[1]: https://github.com/clojure-emacs/cider/blob/master/doc/debug... [2]: https://github.com/ptaoussanis/timbre

Re: Notes on debugging Clojure code

#5
post #2

Another trick is to define temporary inline vars. If I have some Ring handler, it can be quite annoying to construct a request by hand. Instead, I can do something like: (defn foo-handler [{{:strs [authorization]} :headers :as req}] (def *req req) (def *auth authorization) ...) Then fire off a request in my browser and simply proceed to play around with `req` and `auth` in my editor/REPL, which is where I am running…

For people used to Scheme (or most other programming languages, I guess): note that def will create a var in the current namespace, not a locally-scoped variable. In Scheme, or e.g. in Python, a define or = in the same spot as that def would get you a local var. In Clojure, the idiomatic way to do the same thing is normally a let or something -- but using def here makes it easy to access from a REPL running in that namespace.

(A var is a Clojure thing that holds a value. If you've ever had like a "fully qualified path" to a class or object and had to describe it as a string or whatever, that concept is a first-class thing in Clojure, and called a var.)

Re: Notes on debugging Clojure code

#6
post #5
post #2

Another trick is to define temporary inline vars. If I have some Ring handler, it can be quite annoying to construct a request by hand. Instead, I can do something like: (defn foo-handler [{{:strs [authorization]} :headers :as req}] (def *req req) (def *auth authorization) ...) Then fire off a request in my browser and simply proceed to play around with `req` and `auth` in my editor/REPL, which is where I am running…

For people used to Scheme (or most other programming languages, I guess): note that def will create a var in the current namespace, not a locally-scoped variable. In Scheme, or e.g. in Python, a define or = in the same spot as that def would get you a local var. In Clojure, the idiomatic way to do the same thing is normally a let or something -- but using def here makes it easy to access from a REPL running in that n…

> For people used to Scheme (or most other programming languages, I guess)

That's what LISP did since shortly after the last dinosaurs got killed by humans.

Re: Notes on debugging Clojure code

#9
post #2

Another trick is to define temporary inline vars. If I have some Ring handler, it can be quite annoying to construct a request by hand. Instead, I can do something like: (defn foo-handler [{{:strs [authorization]} :headers :as req}] (def *req req) (def *auth authorization) ...) Then fire off a request in my browser and simply proceed to play around with `req` and `auth` in my editor/REPL, which is where I am running…

This is a terrible advice, and is not even necessary. Even println debugging is better than this. Not only defs are abused contrary to their intended use, they are difficult to distinguish from legitimate defs, and thus some may (and will!) slip away into the wild.

Re: Notes on debugging Clojure code

#10
post #4

A few more tricks: - CIDER, the de-facto Clojure environment for Emacs, has a debugger[1]. This is also true for some of the larger IDEs, like Cursive. - Timbre[2] has a number of cool debugging macros, especially spy, which you can tack onto any expression and it'll log it for you. Very useful, similar to the macro in the post, except you don't have to write it :) I really can't overestimate how valuable a real REPL…

This!

Many times when people complain about Clojure, the solution is "just use already available tool X", but they say "no, I am not used to tool X" and then go to invent some half-baked solution in vanilla REPL. That is great for learning, but spreads lousy (mis)information about Clojure's development process. Folks, learn Emacs + CIDER, or at least Idea + Cursive...

Post reply on HN