[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)