Fork me on GitHub
#clojuredesign-podcast
<
2023-10-10
>
JR22:10:03

Potential fodder for a future podcast: One thing that has been difficult for me in Clojure is /reading/ code. I miss the signposts that types (Types?! Heresy!) give me. In Java I can parachute in and get a lay of the land by looking at a function definition's argument types + name. With Clojure I find myself mentally reconstructing what sort of data a function operates on. You'd think this would be simple, but if a function passes data down several more levels of function calls, it gets hard to hold the entities' contents in my brain if someone hadn't spec-ing out the method. I find myself sprinkling printlns (or using a debugger) to find the contents of an entity. Some of this is that I'm unfamiliar with Clojure idioms (dare I say patterns?), I'm sure. Are there variable naming conventions, or some other conventions, or even reading conventions, that would help?

practicalli-johnny12:10:19

I include details of the kind of data passed to a function in its doc-string, along with the kind of value that is returned If there is a spec then I refer to that too. I also provide example function calls and return values for important functions, either at the end of a namespace or in a separate design journal This is all created as I evolve the design of each function, so it's already there when the code is ready to deploy. Unfortunately this doesn't help when others don't do this, but it can readily be added as the unfamiliar code base is learned.

JR23:10:54

Totally agree. (Well, I've never coded Clojure professionally, but it seems logical.)

JR23:10:32

There are some conventions I noticed, like "pred" for predicate, "s" is a string, "coll" is a collection, "f" is a function, "& <plural>" is rest for multiple args, "n" is a count, and so on. But that might only be used in clojure itself.

neumann22:10:17

@U02PB3ZMAHH In case you haven't seen it, there is a community-maintained https://guide.clojure.style/. There are a bunch of https://guide.clojure.style/#idiomatic-names that started with core. I also agree with @U0ETXRFEW that when it's your own code, good doc strings help a bunch. I love this topic idea. I do think that Clojure's lack of types has an effect on program structure. I'm noting this in my topic list. At the very least, it creates more pressure on good naming. @U0510902N noticed that effect pretty quickly when we started trying to scale up a proof-of-concept I wrote into a full-fledged system. Also, I tend to gather code in tightly focused, cohesive namespaces, and then name parameters and bindings (at the place of use) after what that "thing" represents. Dare I called it a "data type"?! If that data type is used more broadly, I'll define a schema in that same namespace, and reference it on parameters in functions that use it. In https://pragprog.com/titles/vmclojeco/clojure-applied/, it talks about this sort of thing as a "domain model". You can https://media.pragprog.com/titles/vmclojeco/validating.pdf. Also, keeping a shallow call stack helps a lot. You don't end up with far flung references to who-knows-what. Finally, @U0510902N and I end up with a little bit of tooling for inspection. If you can run the code, nothing removes all doubt like seeing the value itself. I understand that's not always practical, but for my own code, being able to live inspect just about anything has been hugely helpful. Thanks REPL integration!

👀 1
neumann22:10:33

Ack! I meant to mention @U05254DQM and not Pez! Sorry!

😂 2
JR15:10:49

I haven't seen that Style Guide, thanks! And adding Clojure Applied to my reading list.

JR15:10:07

Just thought of one more thing that could help me - if there are comprehensive unit tests, one can usually get the lay of the land quick enough from reading those. (I sometimes forget to rely on unit tests, since many organizations only use them sparingly. 😞 )

neumann00:10:57

@U02PB3ZMAHH Ah yes. I do like it when a code base has a lot of examples in unit tests! Personally, I find myself writing those upfront if I'm doing a lot of case-specific logic for a clear data model, but I write them later on when I'm trying to figure out how to model something.

✔️ 1