What do beginners struggle with?

eureka!!!

today i read the following and i feel like all of a sudden a few ( obvious? ) things are finally starting to click / falling into place for me! :slight_smile: here it is:

Arthur Rubinstein: ā€žIf I were to begin my career anew it would be on this keyboardā€œ

WOW!!! i mean, isnā€™t this very similar to what we have with emacs / lisp / clojure?

what do i mean:

  • clj is for experts
  • average work experience of clj programmers is very high

but what is the eureka you ask? well, take a look at this:

basically i was thinking, people really should learn to program in lisp, and if they later get a job using some other programming language, nop. whatā€™s more, i always felt like people should WANT to learn how to program in lisp, becauseā€¦ that is what i would have wanted! :slight_smile:

but let us look at some of the things that have happened in this respect:

  • MIT: long moved away from lisp
  • HTDP: in the process of moving away from lisp?
  • university in tĆ¼bingen: moved away from lisp?
  • ā€¦

hmmā€¦ soā€¦ i supposeā€¦ here is the deal: if someone wants to become a ( professional ) piano-player, they are very likely to wanna start out using the mainstream keyboard layout, and piano-schools and teachers are very likely to wanna teach using the mainstream keyboard layout, and only after you have mastered the commonplace instrument are you gonna start looking for possible improvements / more exotic alternatives.

alright, but coming back then to the thing i have said about motivation, mentioning Feynmanā€™s somewhat unorthodox lectures on physics; what i have just realized today, is that things just do not work like that! :slight_smile: in other words, when thinking about an emacs / lisp beginner, to think of a university student is probably very much misleading. the person taking an interest in learning clj is very likely to be a seasoned programming veteran who is not worried about learning to program or finding a job at all!

bottom line, what i argued before may make perfect sense in theory ( why not start on the janko keyboard?! ) but in practice the argument does not seam to be sustainable under the weight of the contradictory evidence. :frowning:

1 Like

I find that the single biggest flaw in Clojure is the ridiculously opaque compiler messages. I donā€™t know how people who have no Java experience can deal with it. And the problem is rarely described on the command line. Instead, we must examine an output file from the compiler that (usually) lists a Java stacktrace in which we may or may not be able to discern the syntactical error.

1 Like

These are the things that I struggled with as a beginner, and to an extent still have some problems with today.

a) Error messages. The error messages are much improved since I started with Clojure, but they are still not very informative. So the classic beginner error of (1 2 3) is rewarded with ā€œExecution error (ClassCastException) at user/eval2005 (REPL:1).
class java.lang.Long cannot be cast to class clojure.lang.IFn (java.lang.Long is in module java.base of loader ā€˜bootstrapā€™; clojure.lang.IFn is in unnamed module of loader ā€˜appā€™)ā€ rather than ā€œError: the first item in list (1 2 3) isnā€™t a function.ā€ I also had problems with the usual beginner mistakes, such as using def rather than let.
b) Program structure. Most texts concentrate on the syntax (such as it is), often at a very low level, such things as cons, conj, etc., but saying very little on how to write Clojure code. Iā€™ve worked though multiple books on Clojure, yet I am still struggling somewhat in managing dependencies in Clojure. I made some progress when I set Clojure aside for a while, and learnt how to code in Haskell, which has a more opinionated style of coding. Then, returning to Clojure, I made a lot more progress. My coding continues to improve.
c) Poor documentation. I had problems with using JACOB (Java COM Bridge). As I wasnā€™t coming from a Java background, I didnā€™t really understand the CLASSPATH and LOADPATH. I think Iā€™ve got JACOB straight in my mind, but havenā€™t made much progress with connecting to databases. The documentation isnā€™t very good - can I volunteer to help out?

5 Likes

I started my first (and only, still working on it) Clojure project based on a Luminus template. At the beginning, I did not understand most of the code that tied the whole project together. Reading a lot of Clojure books did not help me with that either. Instead, I just deleted/changed code and saw what happened. So now i feel more comfortable, but even though my code has been in production for a few years now, I still have a sense that I donā€™t know what I am doing.

2 Likes

A word about me. A seizure has forced me to use a phone as my left hand is useless. Serious frustration with files using Android 10, no root authority. Want to write simple prog to find strings in local files. Two problems, donā€™t have r/w access to a file I created. And for the life of me I canā€™t find doc to open, read and write files.

Regarding the first, I plugged ā€œfile:///storage/emulated/0/a.htmlā€ into Chrome and got:
ERR_ACCESS_DENIED. Also tried ā€œhttp://127.0.0.1:27524/storage/emulated/0/a.htmlā€ and got:
This site canā€™t be reached127.0.0.1

refused to connect.
Try:

Checking the connection
ERR_CONNECTION_REFUSED

I donā€™t know how I found ā€œhttp://127.0.0.1:27524ā€ and since I failed to copy it, I got to waste hours looking for it. Am seriously disappointed with my 2 apps, especially the pro version of one. All they give is (slurp ā€œa.txtā€) and (spit str ā€œa.txtā€). Seriously.

clojure/clojurescript.org donā€™t give simple examples either. What additional software do I need? Not looking forward to installing JDK and a ton of additional software given my limitations. Just really like what I see of Clojure and would like to learn as much as I can.

TIA

The good news is that we now have auto complete thanks to clojure-lsp
Here is a short talk about it from @borkdude :

Hey, thatā€™s true, we do have a few options for static auto-complete, Cursive has also been doing it for a few years now, and more recently with clj-kondo you have clojure-lsp and anakondo doing it as well. We also had auto-complete with a connected REPL for a while thanks to complement.

That said, we do not have auto-complete that shows only operations available to the type. And thatā€™s the bit I was referring too. People used to Java for example with IntelliJ, they often donā€™t learn to know what types things are and what operations the types have, they simply rely on their IDE for it. Itā€™s a little how you forget even simple multiplication like 9*4 once you start using a calculator.

1 Like

People used to Java for example with IntelliJ, they often donā€™t learn to know what types things are and what operations the types have, they simply rely on their IDE for it.

I find it the opposite. Auto-complete accompanied by documentation and navigation features helps me get a better overview of the libraries Iā€™m using.

1 Like

Me. All the time! :smiley:

2 Likes

I donā€™t think Iā€™m a beginner, Iā€™ve been playing with Clojure on and off for about 8 years, but Iā€™ve started a new project recently with clojure cli / deps.edn. The biggest problems Iā€™ve had are:

  • Identifying Clojure application architecture best practices
  • Tooling ergonomics
  • Library discovery and selection

For application architecture, Eric Normandā€™s question ā€œOrganizing Clojure code - A real problem?ā€ has been a great help. Turns out I was bringing some C# habits to Clojure.

For deps.edn, examples have been really useful, if a little overwhelming:

I find deps.edn to be a pretty nice way to encode build related stuff as data, and I find it easier to understand than Leiningen, but the ergonomics are just ghastly. I know we should favour simple over easy, but I donā€™t think itā€™s unreasonable to want to have both. Tools like Git or Homebrew have a relatively friendly and discoverable interface that helps you learn more about how to use the tooling. I understand that clojure cli is supposed to be simple, and that these kinds of ergonomics arenā€™t part of what it does. Unfortunately, as a byproduct, I spend far too long trawling through examples and guides to try and curate my own set of aliases.

I found the post ā€œ[Idea] A tool for helping developers get started using Clojure CLI tools and deps.edn - Community Center / Community Building - ClojureVerseā€ which led to the creation of ā€œlilactown/plumā€, but at a glance that doesnā€™t seem to have gone anywhere.

I found an example of a makefile wrapping deps.edn in antq and ended up learning how to debug make so that I could have one too. A couple of days later borkdude announced Babashka task runner, which is rather nice, and I converted my project to using that.

My project is a small thing, and itā€™s an attempt to port an overly complicated project that I built with Leiningen over to deps.edn. Part of that complexity was too much state in too many places so I decided to find some libraries to handle sql queries, connections, and migrations. There are quite a lot of libraries out there, many of them abandoned (though that doesnā€™t always matter). Finding them and choosing between them is a time consuming nightmare. Not to mention library gotchas like logging and handling of date and times.

Iā€™m now at the point where Iā€™ve got a bug relating to how migrations are running, which is fine, and I thought Iā€™ve quickly whip up test project so I can try an isolate the problem. I couldnā€™t remember the semantics for calling seancorfield/clj-new, so had to open up my .clojure/deps.edn to check. I thought about wrapping my global deps.edn in Babashka tasks to try and provide some executable documentation, but it feels like Iā€™m just pushing deps up hill at this point.

So, here I am, frustrated, having poured time into a hobby project where the only real headway Iā€™ve made is setting up tooling, and Iā€™m still haunted by the thought that the next time I set up a project itā€™s not going to be much easier.

I donā€™t think the clojure community is deliberately making things hard for beginners, but it is hard. Simple is wonderful, I love simple, but I donā€™t think itā€™s unreasonable to want to have at least some of that simple within reach, for it to be easy.

If Iā€™d done this project at work, in C#, Iā€™d already be done. Thatā€™s because itā€™s my day job, but thatā€™s also because all the pieces I need to make it work are within easy reach.

Donā€™t get me wrong, when Iā€™m dealing with the internals of the application, when all the libraries are in place and I donā€™t have to think about how to get a repl running, Clojure is wonderful, and I often solve C# problems first in Clojure and try and convert the solution. But getting to that point seems a lot more painful than it has to be.

4 Likes

tools.deps is NOT a build tool. It is not meant to encode build related stuff as data, but only launching apps with appropriate dependencies pulled in and made available. It is a dependency manager and application launcher for Clojure.

With this in mind, it makes sense that it doesnā€™t offer the ergonomics youā€™d want of a build tool. The fact itā€™s so simple has enabled others to very easily and quickly (I kid not, like in one day you can build one), create full build tools and build pipelines around it.

So whatā€™s happening now is there is no ā€œwinningā€ build tool in the community yet. Leiningen used to be it, but since tools.deps has made it so easy for everyone to write their own build tool, it created a state where each project has their own build machinery leveraging tools.deps.

So if you followed, youā€™d now understand this is totally fine, you do need to add some build tooling to your project, because tools.deps does not provide any build facilities of its own. So wrapping/extending it with something else to allow for defining build tasks and build task pipelines is necessary.

Alright, now, the core team is currently working on a tools.build to complement tools.deps as the official build tool, but not much is known of it yet. In the meantime I think babashka task is a great start putting together your own build tooling.

1 Like

I hadnā€™t heard about tools.build, thatā€™s something to look forward to. Thanks.

Hey there, Iā€™m a beginner, and hereā€™s what Iā€™ve found difficult so far:

  1. Refactoring. When I need to change things Iā€™m a lot slower. I love emacs, but the ramp up time to get anywhere near as quick as an Intellij product is still large ahead of me. When I want to move things and extract things it just takes a bit of time (in emacs-for me-as a beginner). Also, I wish there was auto-importing/requiring when I specify a fully qualified variable (is there?).

  2. Working with async data (network resposnes). When I fetch some data asynchronously, how can I use that data throughout my application without a network call each time I need that piece of data? ie. auth token.

  3. Sometimes I wish the documentation was better. For instance when I first started splitting out my functions from a single file, I was trying to learn how use namespaces so I read Clojure - Namespaces and thereā€™s no examplesā€¦ just a programmatic explanation of what it is. I learned how to use namespaces and how/when to use :require and :use by googling clojure projects github and looking through other peoplesā€™ source code.

So far, other than that, I love everything about Clojure though and itā€™s what I want to make my main language (I use Kotlin and JS at work).

Iā€™m currently using it to build a Postman-like helper tool for myself to generate and move data for me in the services Iā€™m working on across their many different environments and for this I absolutely love the repl. I can build functions in clojure around servicesā€™ apis and create complex automation tasks that a typical rest-client canā€™t do and I can run those functions while simultaneously building them, itā€™s absolutely insane I love it. I want to do something, I write the function, I evoke it. Love.

Please upvote this issue: Namespace introduction/guide is needed Ā· Issue #419 Ā· clojure/clojure-site (github.com)!

2 Likes

Is there any reason you donā€™t just stick with Intellij and Cursive?

Iā€™ve been using Clojure professionally for 3 years and I still donā€™t quite get the hype for emacs when it comes to Clojure development. I mean, I get the whole philosophy behind emacs and the synergy of the Lisp heritage, but from what Iā€™ve seen of various Clojure emacs setups they rarely beat the functionality of (a barely configured) Cursive. Iā€™m sure some 10xers with finetuned setups will disagree with me, but most people donā€™t operate at that level.

This is just going to be an echo of what @simongray wrote above. :slight_smile:

Over the years I have been coding Clojure in vim, emacs (spacemacs and doom), atom, and for the last couple of years Cursive. My day-job these days being Java/Typescript/SQL, I wanted an environment that could handle it all as well as Clojure for fun-time, and to be honest, I think Cursive beats the others for ease of setup and comfort.

I enjoy using it for how lightweight it is compared to intellij. When Iā€™m working I have typically 2-5 intellij applications running and a couple servers, I really donā€™t want to add another one for clojure (clojure is not part of my tech stack at work-just using it to build personal tooling). That and I also like having the same setup on my personal computer since I donā€™t have my own license of intellij.

That being said, as my application grows I most like will give cursive a shot!

Not sure what you mean by ā€œasyncā€ and why would you need to call it again every time. You can use (future) and (promise) and other mechanisms. I like the Imperative Shell, Functional Core architecture - first I fetch all the data I need then pass it as data to the pure functions doing the actual work, finally perform any effects they return.

The https://clojure.org/reference/* resources are not meant for learning. Many people like Clojure for the Brave and True. Have a look at its Organizing Your Project: A Librarianā€™s Tale | Clojure for the Brave and True

Not familiar with that architecture! I will look into promise and future.

For async I mean this: I have a server (A) that logs into other servers (B) and retrieves an access token. Then I call (A) to perform a series of api calls on (B), but those calls need that access token I retrieved earlier from login. Iā€™m using an atom to store the access token, but itā€™s not clear to me how to use pure functional programming to ā€˜storeā€™ the access token I retrieved from a network request (async) and then how to use that access token for other async calls triggered by a client.

Hope that makes more sense