[HN Gopher] Abstract Clojure ___________________________________________________________________ Abstract Clojure Author : joelittlejohn Score : 151 points Date : 2021-11-25 13:59 UTC (9 hours ago) (HTM) web link (www.juxt.pro) (TXT) w3m dump (www.juxt.pro) | slifin wrote: | Reddit conversation here: | https://www.reddit.com/r/Clojure/comments/r1x1ji/juxt_blog_a... | charesjrdan wrote: | Great pointers, I started learning Clojure for a hobby project | and was initially put off by the lack of 'frameworks' like nextjs | or rails, but after effectively piecing my own stack together | from components like Reitit and Integrant I'm really glad I | didn't use a framework. | | I actually feel like I understand everything that happens in the | system now, and when problems arise I can REPL in and hunt them | down with confidence. | | Though I don't use Clojure professionally, I've definitely become | a better developer just from playing with it, a contrast to | JavaScript where I feel like learning it actually lowered my | iq... | solmag wrote: | Rough to read Clojure code without never using it. | [deleted] | Zababa wrote: | > One of the trade-offs with this approach is that it results in | additional wiring; functions must be passed their dependencies | and wired together to form a system. The indirection means we can | no longer jump to the definition of get-article-by-id in the | server namespace. | | That seems like a huge loss. I feel like that approach could be | great for business logic maybe? There's the "business logic as a | library" technique that works well for this, and allows for easy | testing. | 147 wrote: | Doesn't it also make the stack traces more difficult to read as | well? | amackera wrote: | I also recommend the book "Grokking Simplicity" by Eric Normand | for a longer exploration of functional software design (not | Clojure-specific). The linked blog post uses Clojure examples, | but this approach to software design is universally applicable | (especially in functional programming!). | whalesalad wrote: | Thank you for this rec, been thirsty for knowledge in this | domain. | capableweb wrote: | Another good one is "Elements of Clojure" | (https://elementsofclojure.com/) which I think is a slightly | misleading title. It's a generally good programming book, it | just happens to use Clojure for it's examples, but I don't | think it's required to know Clojure to understand the | concepts explained in it. Also been discussed here before: | https://news.ycombinator.com/item?id=21090288 and | https://news.ycombinator.com/item?id=11306519 | slotrans wrote: | "Software design is a well researched and understood problem..." | | I got a good laugh out of that one. Honestly that final paragraph | should just be deleted. It's just a giant, indefensible claim. | WJW wrote: | That really sprung out at me too. I don't think the problem is | well understood at all, let alone the answers to it. | asdfasgasdgasdg wrote: | I'm not sure I agree here. There's not too much value in testing | these two or three lines of code in the get-article handler. And | the passing around of compositions of higher order functions can | get confusing. There are cases where an approach like this is | warranted but I would say that there needs to be a significant | level of complexity before this makes sense. | | Having a protocol for your data layer and an in memory | implementation of that for testing can make sense, especially | when your real data store is expensive to bring up, but I would | try to minimize the number of seams like this in my system. Each | one introduces cognitive overhead due to indirection, so you | should use them judiciously. | dwohnitmok wrote: | Yes Clojure is all about first-order functions working on | simple, concrete data structures. | | Pervasive use of protocols and custom, user-defined higher- | order functions I would argue is unidiomatic Clojure and | creates long-term pain as you end up with opaque functions | being passed around that can't be inspected at the REPL and a | lot of tricky "fitting functions together" that is made | difficult without a static type system. You sometimes need | them, but you should reach for them very judiciously. | | There's a reason Clojure emphasizes data over functions (and | both over macros). | d3nj4l wrote: | Yes - sometimes you can go too far in the quest for | abstraction. I've seen a ton of over-enterprisey people build | gorgeous abstractions with perfect testability and dependency | management, only for it to be used only ever in one context in | one way. I lean towards WET first before extracting an | abstraction, if that. | [deleted] | deobald wrote: | The argument for pure functions holds in a real system; these | particular signatures will be familiar to anyone who's built a | few Clojure web services. In reality, some of the functions | listed (say, `get-article`) would disappear entirely into a | system-specific convention. There's a balance to be had between | the number of seams the team is managing directly and those | which, by their creation, mean _less_ cognitive overhead. The | seams then exist only if they are required, as certain handlers | might choose to diverge from the conventional functions used in | a generic way. | | It's of course not easy to see that next step from the article, | since it doesn't eliminate any code by creating pure functions. | But even in a toy example, there is value of creating pure | functional abstractions. In some codebases, you might even see | the team lead segregate pure functions by namespace: "Pure | stuff over here, tainted stuff over there." In those | situations, teams try to reduce impure surface area -- in this | case, anything that touches the `db` namespace. | potency wrote: | What is Clojure's main selling point? | ByteJockey wrote: | It's lisp on the jvm. | vnorilo wrote: | Sibling provided a good overview of philosophy. Practically it | offers Lisp goodness, jvm/js interop and a well-designed set of | persistent collections everyone and their dog uses, part of the | reason why clj libraries tend to compose very well. You get | some stunning mileage out of the thing. | joelittlejohn wrote: | If you have an hour spare, probably the best way to understand | Clojure's main selling points is to watch this talk: | https://www.infoq.com/presentations/Simple-Made-Easy/ | | InfoQ list the Key Takeaways as: | | - We should aim for simplicity because simplicity is a | prerequisite for reliability. | | - Simple is often erroneously mistaken for easy. "Easy" means | "to be at hand", "to be approachable". "Simple" is the opposite | of "complex" which means "being intertwined", "being tied | together". Simple != easy. | | - What matters in software is: does the software do what is | supposed to do? Is it of high quality? Can we rely on it? Can | problems be fixed along the way? Can requirements change over | time? The answers to these questions is what matters in writing | software not the look and feel of the experience writing the | code or the cultural implications of it. | | - The benefits of simplicity are: ease of understanding, ease | of change, ease of debugging, flexibility. | | - Complex constructs: State, Object, Methods, Syntax, | Inheritance, Switch/matching, Vars, Imperative loops, Actors, | ORM, Conditionals. | | - Simple constructs: Values, Functions, Namespaces, Data, | Polymorphism, Managed refs, Set functions, Queues, Declarative | data manipulation, Rules, Consistency. | | - Build simple systems by: Abstracting (design by answering | questions related to what, who, when, where, why, and how); | Choosing constructs that generate simple artifacts; Simplifying | by encapsulation. | | So Clojure is a language that embodies these principles in its | design. It's a Lisp, which means that all code is constructed | from a very regular expression syntax that has an inherent | simplicity and can be quickly understood. It's a functional | programming language that provides exceptional tools for | minimising mutating state, and it favours working with a small | set of data structures and provides a core api with many useful | functions that operate on them. | | I'd say the result is getting a lot done with a small amount of | code, minimal ceremony, true reuse, and the ability to maintain | simplicity even as your system's capabilities grow. | knubie wrote: | https://clojure.org/about/rationale | beders wrote: | A really well thought out Lisp-1 that runs on the JVM, in the | browser, in node as well as the CLR and BEAM. | | It is hard to go back to other languages once you appreciate | its simplicity. | Scarbutt wrote: | Not writing Java (although you do have to do lots of interop | with Java). | capableweb wrote: | It's true it's "not writing Java", that's true for every | language besides Java! But the second part is definitely not | true. First, you can very much use JVM Clojure without | touching Java, I've done so many times. Secondly, you can use | ClojureScript which cannot even do interop with Java since it | "compiles" to JavaScript and doesn't run on the JVM. Thirdly, | you can use Babashka to run Clojure code with GraalVM and SCI | instead. | | Many options exists to not having to touch Java when you use | Clojure, but I guess it's hard to kill old memes? | mark_l_watson wrote: | Nice article. I have to admit living in the dark ages, Clojure | wise. I don't even use Protocols, just simple functions and I | love the simple built in data structures. I was comparing my | Clojure and Common Lisp libraries for using OpenAI's GPT3 APIs | last night. I usually use CL, but I notice how much cleaner the | Clojure version looked (I should refactor the CL version). | | Clojure is such a practical language. | Blackthorn wrote: | If you use Integrant like they suggest, you don't need to do any | of that for testability. You can just use the code you had | originally and have a test function that just creates an | Integrant system with all fake dependencies. Then you can just | reuse that test function in every test, occasionally overriding | one of the fake dependencies. ___________________________________________________________________ (page generated 2021-11-25 23:00 UTC)