3 ms·
> What surprised me the most in working with Clojure commercially is how many commercial developers did not get the ethos of the language or have watched the ri
by embedding-shape 7mo ago
> What surprised me the most in working with Clojure commercially is how many commercial developers did not get the ethos of the language or have watched the rich hickey talks or use the REPL
Yeah, this continues to stick out. The amount of people I've come across who do Clojure development and restart the application (really, the JVM process, kill it and launch it again, over and over!) is way too high, considering the first "real" reason I had for moving wholesale to Clojure was a shorter feedback loop. If that's not one of your goals when moving to Clojure, I'm not sure what you're up to really.
- jgalt212 7mo agoYes, but without a clean REPL you can't easily be sure that your var definitions are what you think they are.
- embedding-shape 7mo agoSure, so once a week or so you need to restart the process if you end up like that. What I've seen people do, is restart the process after each change like you typically do in other languages, rather than evaluating the current form...
- cfiggers 7mo agoThe thing that happens to me is that I'll get something working in the REPL, then try to deploy it and it breaks—because unbeknownst to me, I had gotten my REPL into some state where everything was working, but a cold start doesn't look the same. Is this a skill issue? Absolutely. Do I still restart the REPL frequently (not after every def, but often) just to make sure I'm working with the same environment my program will be experiencing at run time? Yes I absolutely do.
- Folcon 7mo agoCouldn't you have one test that requires your -main and runs it? Just fire that off every now and then? Basically the same thing, but you don't lose repl state
- embedding-shape 7mo agoAh yeah, been there, and probably the first time was when renaming a function but missing to update callers, so callers keep calling the old function, and you have no idea why the changes you made in the new function aren't working. I have a this little function for clearing the current namespace that I call every time I rename any var inside a namespace: (defn clear-ns [] (map #(ns-unmap *ns* %) (keys (ns-interns *ns*)))) Not a perfect solution, but personally I also don't know a better solution that doesn't involve loosing out on other (non-negotiable for me) benefits.
- mvc 7mo agoOnce a week?! Aren't you killing the repl at least to run a full test suite without any stale leftover developer state before deploying?
- embedding-shape 7mo agoFull test suites I run before committing essentially, in a separate tab altogether, then the full suite is typically also run in CI before any deploys.
- TacticalCoder 7mo ago> Yes, but without a clean REPL you can't easily be sure that your var definitions are what you think they are. vars and functions too. It's the biggest issue: the inevitable mismatch after a while. As soon as I've got any doubt there might be a stable cache or a mismatch, I'll just "nuke the current CIDER buffers and relaunch cider-jack-in-clj&cljs". And it takes 1.3 seconds. I'll also regularly spawn, from a terminal next to my Emacs, all the unit tests related to what I'm working on, in its own JVM / process(es). I'm not talking about running tests on commit (which I can do too). I'm not talking about running tests when I modify a function. I was there 3000 years ago when Java 1.1 was using green threads on Linux and using Java on Linux required a serious leap of faith (but I knew... I knew it'd take the world... And I knew great things like Clojure would then come). Now a JVM starts and exits in 40 ms. Emacs starts and exit, with 4 000 lines of elisp customization I created over the years, in 1.1s. I cider-jack-in-clj&cljs spawning both a CLJ and a CLJS REPL in 1.3s. Clojure devs definitely should modify vars and redefine functions at runtime and use the REPL etc. But there's no need to let a REPL live for one week like GP is suggesting. I can launch my entire app, including Emacs and two REPLs, in 2.5s. While at the same time having all my unit tests being launched in another process. At 2.5s to "restart the world", there's no reason not to do it more than once a week. P.S: also stale caches are a thing in this world. It's sad but it's simply how it is. How it's always been. Restarting the whole world, while in dev, helps also deal with a great many stale caches issues that may not be related to Clojure but to other things (e.g. I didn't invent the "disable cache" button in browsers' developer tools and there's a reason it's there).
- eduction 7mo agoI'm probably not the sort of person you're referring to, but I do regularly restart the REPL because 1. multimethods, if you change the dispatch fn you can't get it just with a recompile, there are tools to help with this but i'm not yet in the hang of using them after several years. (Many people don't hit this because they don't use multimethods. I love multimethods for the use cases I've hit so far with clojure.) 2. interceptors (pedestal) - I love this pattern and lib, and they've made moves toward improving repl friendliness, but I find I need to recompile two NSes typically to get a true reload even in dev mode (the one where my routes are defined and the one where a particular interceptor chain is defined). sometimes i lose track of what i've reloaded, and I dont know if a bug is "real" or just an artifact of forgetting to recompile - "f it, just restart the repl"
- spopejoy 7mo agoBeen over a decade since I used Clojure in anger, but at the time it really seemed like IDEs made it hard to use a REPL with a large codebase -- they seemed more to want it to be like a javac/maven stack. I assume that got better?