Fork me on GitHub

Has anyone created a custom Clojure keyboard? Where integrated the main used “shortcuts”, keys? I use sometimes ducky-pad (not for all shortcuts, but few.. quicker to push one button cases).. just therefore I ask.


not strictly but my layout is quite clojure/emacs centric, quick access to various paired symbols, most of the important stuff on the home row + modifier etc etc

👍 3

Does anyone else have this workflow, where in the exploratory phase of figuring out how to do a project (which can last a really long time) just having one huge namespace with everything in it, and continually scrapping that and starting again (obviously copying over big chunks)?


Yes, I also do this. But to be honest, I do in all phases, not only exploratory. For example, if I'm working on an API, I will probably have everything on core.clj until it's too big. Then, I'll create a namespace handlers, move every handler there. Rinse and repeat 😄

👍 6

I rarely have separate namespaces unless it's important for the public API or some compilation reason


and then I'll do core.clj, core2.clj, core3.clj....


as I write and rewrite it

👍 3

Good to know I'm not alone. I'm approaching core100.clj for a thing


i think you are alone there

😅 12

nope ) I’m on core35.cljc atm )


are these work products or more serial things like project euler or other challenge type things?


The big one is an ongoing personal side project


interesting. how do you navigate those files? if you needed to change the behavior of some function f how do you know where it lives easily, and do you have an enormous require statement somewhere?


yeah the require statement is big. I generally navigate with just "ctrl-f" and emacs point/mark ring. I've wondered if I could optimize this a bit more, but I do think I personally find even that to be less mental overhead than remember which file something is in


And I guess a key thing is I'm making breaking changes frequently, which I also find easier to manage when all usages are in one file. (I know there are tools that also help with this I just never got used to them yet)


In many programming communities is common to start a project by creating a lot of files/dirs, with predefined names like models views etc.. I personally do not like this approach. I usually start in an empty dir with one file, and grow my namespaces "on demand" I would like to search more about this problem/difference/pattern/practice, but I don't even know which terms should I search for to learn about it.

Ian Fernandez17:03:18

Like, it's very interesting to begin with nothing and discovers how to name your domains understanding some type of problem...

Ian Fernandez17:03:49

MVC project design/context is something that is attached at a time developers needed some sanity by isolating "Frontend I/O" from "Backend I/O" and nowadays it drives many carreers decisions...

Ian Fernandez17:03:38

naming is a very difficult issue, to not try to pre-bake them is a nice way of beginning stuff


One overlooked nuance is that a monolithic .clj ns will be slower to reload under at least two workflows (`require :reload` and tools.namespace refresh; re-evaluating discrete forms is still fast oc) e.g. you just change a single defn, want to reload the file, now every single defn has to be reloaded again. And the clojure compiler is quite slow For me it's a big enough reason to favor small namespaces (which also tend to be conceptually simpler).


this effect can be pronounced even in small namespaces that mix unrelated concerns. For example a util ns that has json + spec + http stuff under 100 LOC can have many dependent namespaces on the json part, but just one in the http part. you want to change the http part -> whoops, you're reloading your whole app (because of the json dependents), and takes 60s instead of 1s


Why would you reload the whole file on changing just a single defn? Just eval that one form into the REPL and you’re good to go.


Your comment sounds more like an argument against reload-based workflows (which, hey, I agree with b/c I think those are the “wrong” approach).

👍 6

It boils down to styles of thinking, I think all are fine My style of thinking is 'careless' (abstract?). I don't want to reason about what needs to be re-evaluated, and what needs to be done for that corpus to successfully propagate. I want to hit the same keyboard shortcut always and get the code reloaded


FWIW my side projects rarely grow beyond 1k lines, which means it's not super slow to reload the whole ns

👍 3

e.g. on the 10th, 12th iteration? and I finally got it to a state where I was like, OK i'll split it into separate namespaces


most of the complexity is in core.cljc which is 400ish lines. small enough than I can eval the buffer and it's pretty much instant


one of the downsides of splitting up the namespaces is that I have some small bits of global state defined in the core ns that don't get reset by evaling dependencies


but in general, my workflow is bang on a namespace, save and eval the buffer, run tests. In fact I have one hotkey that does that 🙂


I also try to avoid taking dependencies in my side projects. that also is probably a function of the types of projects I like to work on 😄


yeah more than one way to skin a cat! mostly I intended to share an insight that isn't commonly known almost all clojure workflows are fairly luxurious when compared with most compiled languages :)


It's not about "split or not split" files It's about "start with pré-defined names" vs "create names on-demand"

sheepy 3

@souenzzo I think that Clojure as a Lisp with the facilities of a REPL that can evaluate forms, one at a time, liberates the programmer from much ahead of time thinking, so allowing more experimentation, and I think that is the reason why it's so difficult to push the framework mindset.


I think that MVC pattern has a widespread adoption because it's what full batteries-included web frameworks used to provide, so all applications developed using such frameworks ends up gravitating towards MVC, and it affects even applications that doesn't use a framework, and are building using libraries


Clojure being so plastic/flexible allows one to decide later and just move functions to proper namespaces when needed

👍 9
🙂 6

I think that you both are focus in technical reasons that i don't have. I work daily on a 100k line project, with some files larger then ~1k lines, many many namespaces, and I have no issues with reloading namespaces or their dependencies. My change file -> run end-to-end (pedestal request-for, with everything running) test still run around ~0.1s. I dislike model view gen projects for other reasons: the boilerplate/names etc...


what's your workflow? when you change a given defn, what do you do so that the next http request will see it?


i have a keybinding to "load file to repl" And a keybinding to "run last test on REPL". Using midje, it show up in stdout. I use splited screen with code // repl So I usually not seeing the "test" namespace. But the main thing is design your namespaces/applications to be reloadable. Some libraries like pedestal and datomic helps A LOT on that. Where the library do not help, I do things like a simple (def register [...]) turns into (defn register [] [...]) so it's way "more reloadble"


thanks for the answer. don't you face edge cases with that approach? for example, you "load file to repl" a changed defmacro how do you determine and reload all namespaces dependent on that defmacro that need to be recompiled? (else they'd be using the old macroexpansion) (Especially on a 100KLOC codebase)

Ian Fernandez23:03:08

the problem is to look into the idea of a model or a view these are names that are too generic

Ian Fernandez23:03:42

to think on effective programs is to go out from a view that we need generic boilerplates/names, isn't it?


Yes @d.ian.b and it's just a convention that happens to influence a lot how people design web apps


they usually mean nothing. They force you to translate names from here to there Any change in the project will be spread across many files etc

👍 3

They just follow the convention, even if it doesn't apply

Ian Fernandez23:03:04

they don't mean nothing, I don't think at Clojure we use something like "Convention before Configuration".


Yes, and it hurts other communities until today. There are several discussions across the internet about "How Rails is not your application"


The "Convention over Configuration" thing was a reaction against the pile of XML needed to configure J2EE style frameworks circa 2000-2004


But Clojure is a totally different thing that doesn't work on the same level.


This is why I think that the attempts to make a Rails like framework on Clojure, that sometimes pops-up are diverging a lot of the "Clojure philosophy"


The best we can do is to provide a good template, and Luminus is a good one, but we have others that fulfill the same space.


Consultancies sometimes open source their templates, like Juxt, Cognitect, etc


Because can be hard to re-wire the same things (auth, not-found-pages, etc) over and over again


And it can be so simple as a base project that you clone e fill with customizations, but with the wire already done


@marciol At work, as we’ve built more and more web apps, we’ve refactored older code into “libraries” (`:local/root` subproject dependencies), so that it’s easier to stand up a new app and just reuse code we’ve built before. A lot of the web “boilerplate” for at least bootstrapping a new web app comes down to the initial middleware stack the components you have to startup to get the app running. At this point, we’ve mostly refined and refactored that into standard namespaces/code so there’s very little actual code to write to standup a new app.

🔝 12

Yes @seancorfield, that is what @d.ian.b is suggesting to me in a private conversation


I think each company builds up (and prefers) their own curated set of 3rd party libraries though so if you switch companies, you’ll have to learn “web app 101” all over again. Or maybe “web app 201" at that point.

clojure-spin 6

Yes, I also do this. But to be honest, I do in all phases, not only exploratory. For example, if I'm working on an API, I will probably have everything on core.clj until it's too big. Then, I'll create a namespace handlers, move every handler there. Rinse and repeat 😄

👍 6