What do beginners struggle with?

For me and others I think one of the largest issue is seeing a lot of experienced clojure developers around yet there aren’t many visible projects to look over. Everyone seems to be using it for new startups or privately and there’s not enough examples to look over.

Hmm just a thought…as a new developer in general I’ve put the most time in clojure after playing with ruby, python and a little C++. The thing that made clojure and lisp cool to me was treating my code like lego pieces. You mentioned deeply nested forms. I’ve seen several examples where functions are 15-20 lines long, early on I liked breaking things down into very small pieces. Functions that are 5 lines long and plugging them in to build something larger. It feels very much 'plug ‘n play’ to me and makes solving problems easier than any other language for me.

Here’s some 33K repos to have a look at: Repository search results · GitHub

And here’s a somewhat more curated selection of those: clojure · GitHub Topics · GitHub

2 Likes

Sure, I was a convert to small functions before coming across Clojure. Actually the problem I referred to above was more a matter of editor mechanics - getting nested function calls messed up when refactoring etc. I’m still only somewhat casually learning Clojure and haven’t written much of any seriousness, but I’m over that now :wink:

I don’t think the number of projects on github is the issue. I think there is an issue, as I’ve seen the question asked many times (and have asked it myself). Tens of thousands of uncatalogued github projects are no more use to a relative beginner than access to a publisher’s slush pile would be to an aspiring novelist. What people want is a canon to learn from. There seems to be a shortage of well-attested public clojure projects that represent realistic production uses of the language in end-user applications (it’s a different matter for libraries). Perhaps they’re out there, but the small number of specific responses these questions usually garner suggests that if they are, they’re little known.

3 Likes

If you look at the 2nd link (the “curated” one) there’s plenty of big, well-crafted applications. Just off the top: Metabase, Riemann, a Lisp implemented in Clojure (from the MAL collection), Onyx…

Unless you’re looking for “canonical CRUD app”, in which case there are also many tutorials (including one by @seancorfield that starts from the very basics)

3 Likes

I’m talking about personal recommendations. It’s hard to know what’s ‘well-crafted’ when you’re getting started, and automated lists aren’t reliable guides. Believe me in the clojure world they’re hard to come by (as I wrote above, few responses to such questions are usually received). I guess you’ve just made some - so thanks!

Tutorials and associated code are a different matter. I agree @seancorfield’s amongst others are very useful to get started with. Any reasonably experienced programmer is soon though going to want to see production code. Even when it’s beyond a learner’s current level, there’s much to be learned about the pragmatics of a language & associated tools and libraries that can’t be canvassed in material specifically written for learning.

1 Like

While not considering myself any kind of authority on this, I’d highly recommend having a look at stuff by @borkdude, @plexus, @weavejester, as well as tutorials by @ericnormand.

This is a very reasonable concern. I’ve been doing production Clojure for a decade and I would find it very hard to answer this question. There are very few open-source production Clojure apps out there, and library code tends to be a lot more narrowly focused and often not a good example of “architecture”.

I think there’s also very little information out there on good architecture in Clojure. You can pick some of it up from various conference talks (Domain-Driven Development in Clojure, Clojure in the Large, some of Stu’s talks – the ClojureTV channel on YouTube is definitely worth spending time on).

Most of the books are focused on learning the language at various levels but don’t cover the more expansive subjects (Clojure Applied is probably the main exception there, and The Clojure Cookbook and The Joy of Clojure are worth reading for their practical and philosophical aspects that go beyond “just language”).

I suspect part of this is that Clojure has traditionally appealed to people building unusual apps that are, by nature, proprietary. The sorts of full-stack open-source apps you see in other languages are typically not things that people build in Clojure. Where I work, we’ve always used Clojure for very “standard” stuff, even for plain ol’ CRUD apps – but we’re in somewhat of a minority niche in the Clojure world (e.g., when I got started, pretty much no one was using JDBC and relational databases from Clojure and there was no one maintaining clojure.contrib.sql – and that’s how I came to maintain it, as clojure.java.jdbc, and then next.jdbc).

I think it also doesn’t help that Clojure has historically attracted more senior engineers, who are looking for “something better”, and so they’re often already so far past the learning point that @crispinb is asking about – how to bridge from beginner to intermediate and beyond – that they’re relying on a lot of deeply internalized intuition about overall architecture. If they’ve also internalized Clojure’s fundamental concepts (simplicity, immutability, composability, separating effects from pure code), then they probably don’t even think about a lot of this stuff.

Other than waving my hand vaguely in the direction of a few talks and a few books, I don’t really know what to suggest to address that (very real) gap in the Clojure world.

11 Likes

One of the things I still struggle with a year or so in, but especially when I was first learning Clojure, is navigating/grokking the reference documentation. It’s very compact and terse, like Clojure itself. And because Clojure is so different from other popular languages in some pretty fundamental ways, it also reads as quite insular and self-referential, making any given piece of the docs hard to understand if you don’t already understand adjacent pieces. To be clear, I think this is true of any sufficiently advanced tool, but I think it’s especially true for tools like Clojure.

Take the doc comment for loop for example:

Evaluates the exprs in a lexical context in which the symbols in
the binding-forms are bound to their respective init-exprs or parts
therein. Acts as a recur target.

Loops are pretty fundamental (although arguably less fundamental to Clojure/Functional Programming). Yet when I read that I couldn’t even tell if it was what I was looking for or not. I had a similar experience trying to figure out recur. I did eventually crack that and was able to come back to loop and later conclude that what I really needed was for. If I hadn’t had a bit of FP experience under my belt, I wonder if I would’ve been able to intuit what recur was all about, and how much longer it would’ve taken.

I do see a certain value in information-dense, extremely concise reference documentation. But I think I would find it a lot more useful and much less daunting if:

  1. different part of the reference docs were interlinked more intentionally
  2. particularly important or tricky sections of the docs contained a blurb about certain aspects you’re expected to be familiar with to understand the page you’re on

Anyway, despite all that, I’m super happy with my Clojure journey so far. Thanks!

7 Likes

@seancorfield why do you think that is? It seems like you’re implying (and if so I think you might be right) that Clojure engineers, who tend to skew senior, are just not as interested in building basic CRUD apps, and perhaps also have more leverage in choosing what they work on. And so that “middle ground” suffers as a result.

I read your comment after leaving my own above, and I actually think the two are closely related. I’ve also been thinking a lot about Eric Normand’s rant where he attributes Clojure’s niche status to its lack of a “boring” web framework and other things that e.g. Python devs may take for granted. I think Clojure offers some really interesting opportunities to reimagine how basic CRUD apps and their boring constituents could work, so I’m wondering if you think solving those boring problems would help address the gap you pointed out by attracting a wider range of skill?

1 Like

When you don’t know Clojure very well, the docs are like a foreign language. But once you do, they’re this nice short and sweet clear explanation.

For example, loop actually doesn’t loop. It does much more what the doc-string says than what the name implies. In fact, you can use it instead of let:

(loop [a 10
       b 20]
 (+ a b))
;;=> 30

In this case, loop evaluate the expression (+ a b) in a lexical context in which the symbols a and b as defined in the binding form are bound to their respective init-expressions 10 and 20 respectively. And that’s why we get 30.

The difference between loop and let is that loop can act as a target for recur and let can’t. Recur, will basically jump back to the beginning of loop, change the values the symbols are bound too, and re-evaluate the expression with those new bound values. Thus using recur inside loop lets you well… loop :stuck_out_tongue_closed_eyes:

Ya, even that probably sounds like giberrish. Good doc-string that everyone can understand and benefit from is really hard to put together though.

3 Likes

You mean loop there I think…

I think, with hindsight, the names loop and recur are perhaps misleading when you’re a beginner in Clojure since recur isn’t really about recursion (although it looks that when when used in a function, instead of a “loop”) and loop isn’t really a “loop” in any intuitive way, based on understanding other languages. But naming is hard and I can’t come up with names that are better.

2 Likes

Yes, I think that’s true. CRUD apps are very necessary but they are also not very “interesting” since they are a “solved problem”. If I needed a CMS, I wouldn’t build it, I’d just pick one that worked with my (JVM) stack – or even standalone depending on what level of integration I needed.

I don’t know. When I’m writing CRUD code at work, I do sort of wish for something a bit higher-level to avoid form handling boilerplate but I’m leery of “framework-style” automation because that nearly always needs extending for the cases not covered out-of-the-box and my experience is that things either get real ugly or real complex around those extension points. But it’s also not enough of a pain point for me that I’m motivated to actually build something generic (and, in fact, at work one of my “background tasks” is slowly rewriting a legacy CRUD app, that was based on a generic framework, into bespoke Clojure code, and I’m constantly finding cases that the legacy code/framework didn’t actually cover or made so difficult that we lived with a poorer UX rather than wrestle with said framework – so as I’m rewriting things, I’m fixing those old bugs, adding support for the missing cases, and improving the UI/UX).

I do think that automating form validation via Spec is a promising avenue and we already have some macros for generating CRUD functions from Specs for database tables (at work), but figuring out how best to map from validated input to persistent output is a messy problem to solve generically, and auto-generating the backend Specs from database metadata feels like it might be worthwhile (but hard, in general). Overall though, I’m also torn on whether this should be a generator-based approach or a generic framework-based approach.

Generic code that satisfies a broad enough range of end-user requirements to be released as an open source “framework” is a big piece of work. There’s also the whole i18n / l10n issue which needs to be integrated, along with date/time and timezone handling. And most folks want some sort of built-in (but still very flexible) authentication / user management functionality. All of these are “solved problems” on their own but creating the “right” integration of them all is hard (and still not really an “interesting” problem to solve).

4 Likes

I suppose you’re familiar with it, but just in case, clojuredocs.org has a bunch of user-contributed examples for each function documented, which I’ve found (and still find) super helpful.

For the loop case, it gives you 13 concrete examples.

3 Likes

@seancorfield’s User Manager example has been very informative for me - I spent some lovely time running it and inserting println’s to understand ring, next-jdbc, component and other libs. Just look at the comments: https://github.com/seancorfield/usermanager-example/blob/develop/src/usermanager/main.clj

RE the CRUD debate: there are some really nice low-code tools like Hasura and PostgREST that turn a database into an API that can be combined with things like React-Admin that generates an admin UI. I’m not experienced enough to understand their downsides, but if they are integrated into lein or tools.edn they can be used to quickly create a CRUD app that has its business logic and “glue” code in Clojure, where presumably the most business value is.

2 Likes

And Cider lets you access them with cider-clojuredocs (or C-c C-d C-c) :slight_smile:
(something I only recently discovered)

1 Like

Also…I have a bit of a thing with buying EVERY book but I think new clojure developers should get The Clojure Workshop. This book is over 800 pages and goes through the basics in depth, it goes into working with databases even to the point of going through database pooling, clojurescript, HTTP via Ring. There’s been a few newer books that never picked up traction that are quite good for newcomers.

3 Likes

because of the current global health crisis schooling has changed considerably in many places… also… seams to me, that the covid-situation is acting a bit as a catalyst for certain trends that had already been set into motion well before the outbreak of the disease… i am thinking of MIT open courseware etc. etc.

anyway… when reading this thread, the fundamental question is really about learning… about how people are able / can be enabled to acquire new and complex sets of skills…

okay… but what is it that students struggle with, when they are supposed to learn how to read and write in elementary school? when they need to digest complicated mathematical ideas at university? when they are tackling lisp / clj for the first time? … what can be done / provided to help them succeed? what are the main obstacles holding them back?

so… as i was pondering these matters… why beginners tend to struggle with clj etc. i was reminded of the following:

https://www.feynmanlectures.caltech.edu/I_91.html

enjoy! :smile:

p.s. my 2 cents… i really like the following quote:

"The power of instruction is seldom of much efficacy except in those happy dispositions where it is almost superfluous.” (Gibbon)

…and this reminds me a bit of the following anecdote:

It is said that a dispassionate young man approached the Greek philosopher and casually said, “O great Socrates, I come to you for knowledge.”

The philosopher took the young man down to the sea, waded in with him, and then dunked him under the water for thirty seconds.

When he let the young man up for air, Socrates asked him to repeat what he wanted. “Knowledge, O great one,” he sputtered.

Socrates put him under the water again, only this time a little longer.

After repeated dunkings and responses, the philosopher asked, “What do you want?” The young man finally gasped, “Air. I want air!”

“Good,” answered Socrates. "Now, when you want knowledge as much as you wanted air, you shall have it.

my main point being, that what seams to be of the utmost importance is for students to be / become motivated to learn! if they are motivated enough… they’ll figure it / something out! :smile:

now, truth be told, i imagine that home-schooling places an enormous burden on parents, because getting kids motivated to do their studying is ( often ) gonna require some real effort!

but… focusing on clj for a second, when one reads this thread, it is all about some of the language features, the books / learning materials that are available… project templates… stuff like that… but if one thinks about it a bit more from this motivation angle, i guess one could be tempted to argue, that what clj beginners struggle with the most are the relatively poor labor-market-opportunities.

now what makes me say that? well, what is it that motivates someone to study something like physics or computer-science or medicine? lots of reasons of course, but most likely the prospect of landing a decent job will play at least some part in motivating that person enough to buckle down like that.

okay, but now suppose someone starts out learning clj, most likely on their own, investing their precious free time,… now, when you start something new it is always fun and exiting, but after a few weeks going to the gym tends to become a chore and so you quit your membership or you simply stop going, because you don’t wanna be a quitter. :smile:

long story short, should clj keep becoming ever more popular, more and more jobs will be created as a consequence, perhaps so much so, that schools will decide to teach courses on clj, because they want to enhance the position of their graduates on the labor-market, all of which will help to provide motivation for beginners to stick with clj! :wink:

I think Fulcro RAD
has a really good story here for showing and editing data. Its guiding design principle is extensibility and it’s good at it. It can do a lot for you out of the box and makes it easy / possible to take over to any desirable extent.

But it is intended for solving complicated needs and thus has a steep learning curve. For me it is absolutely worth paying the learning price once and then benefit from it for years but it is not suitable for one off use. I would not recommend it as a beginner ClojureScript framework.

Its key concept is “attribute”. Ex: (defattribute :person/fname :string {}) where the final map can contain any plugin/user data such as :sql/schema, formatters, validators,… Those are then used when generating code to read/write/display/edit them. And you can always write your own code for any of that. Works great for me.

1 Like