What do beginners struggle with?

My team uses it in production :yum:

There are about 20% of the time where performance would be a blocker to not having them, so they made sense at the time. Transducers managed to solve that problem similarly elegantly now, but they were not imagined early enough in the design of the language. Now Iā€™d say lazy-seq are still nice for certain things, but itā€™s true that a lot of people feel it be nice if transducers was the default more convenient syntax, and lazy-seq the thing you reached for in special cases.

You eventually outgrow their ā€œunexpected behaviour of your codeā€ and stop really having to deal with that, if thatā€™s any consolation.

I also love them for the cool factor.:sunglasses:

Fair point, I think thatā€™s true of a lot of things in Clojure.

You mean people explain Protocols by reference.to Java interfaces?

Thatā€™s also a fair point, I think a lot of people doing Clojure have Java expertise as well, which must bias them in how they explain things.

That said, I would say that itā€™s important to learn the runtime memory and computation model of Clojure to become an expert in it. I think itā€™s important to learn that of any language. And in the case of Clojure that is the JVM. So learning about the JVM and some of its tools like VisualVM is pretty useful and it makes sense to be a part of learning Clojure. That doesnā€™t mean you need to learn about the Java language though.

Iā€™ve shared that sentiment but now Iā€™m starting to question it. After having gotten used to transducers and realizing how neatly they can be integrated into existing code, they donā€™t seem as esoteric and such a long reach anymore.

The question is: If you could have a language that could act as both a scripting language and a high performance language, would you prefer its default mode be scripting or high performance? If you prefer high performance, is that worth losing general laziness too?

When gluing together different systems, would you rather have a flexible language that can easily talk about endless things, or a high performance system that can only talk about finite things (with a lazy escape hatch)?

I think Iā€™d rather the default case be the more scriptable one, for easily gluing systems together, with the option use more performant capabilities when necessary in the core performance critical areas.

And is the alternative really possible? When dealing with unbounded sequences, would it really be as easy as ā€˜reaching for lazy-seq in special casesā€™ or would it be more complicated than that, involving an entire extra streams API bolted on to the side of the language?

It would be interesting to see what the default performance of a transducers-all-the-way-down Clojure/lisp/lang would look like. Maybe that would prove useful for some things. But I think laziness is actually a better on-ramp for beginners / new Clojure developers that are gluing streaming systems together - just a little longer of an on-ramp in the beginning, to learn about forcing consumption when necessary. And then you can move gradually away from lazy scripting semantics for hot code paths in a more Ć  la carte manner.

3 Likes

Good points, I think between lazy sequences and transducers there are things that transducers make more convoluted as well, and there isnā€™t a transducer for every lazy-seq function, and I think part of that is because they arenā€™t always all trivial to implement as a transducer, and sometimes they donā€™t all compose as easily together or you need to be aware of the transducing context.

I guess the question would be more what it would look like against a hybrid of eager sequence functions and transducers. For the cases of modeling infinity and such it is still a good point as too what that would look like, I donā€™t know if it would be better, but its an interesting thought.

Another thing, which Iā€™ve seen sometimes as a criticism in Clojure, is that sequence functions were in the core namespace to begin with. If they had been in say a sequence namespace, you could have had another namespace named transducer or something like that. So you could have both with similar interfaces. I canā€™t remember why Clojire didnā€™t do that and choose to overload arity for transducers, when it did do it for reducers.

Anyways, to beginners reading, remember all things have trade offs and pros/cons, and I think lazy sequences over iterator style streams like Java and C#, over eager functions over transducers donā€™t necessarily have a clear winner, just different qualities that sometimes make one better than another. Like John said, lazy sequences do end up being a really nice default with a good balance between performance, flexibility and convenience, and there is an easy path towards performant and eager variants.

1 Like

Thatā€™s interesting! If you had to do it again, would you use core.logic, one of the rule-based libraries, or one of the datomic clones (datascript, datalevin, datahike, ā€¦)?

Thanks @didibus and @John_Newman !

1 Like

Iā€™ll have a look at that!

I want to provide an update to myself here. My day-job is still Typescript and SQL, but about half a year ago I got so fed up with IntelliJ loading times and ergonomics that I jumped back to Vim. I havenā€™t missed IntelliJ even once since then, for any of the languages I develop in. I think I t is healthy to try whatā€™s on the other side of the fence sometimes, maybe get good at it, and then make an informed decision. That goes for languages, editors/IDEs, mostly anything really.

I started (again) on Clojure after I gave up on my last try about 2 years ago. After revisiting some of the books I read, I found understanding the language not that difficult as I learned LISP and Scheme during my studies in my earlier life. However, after I have no Java and no Java Script background, I found two things difficult:

  1. In most books or tutorial there a lots of references how this would be done in Java or Java Script to explain a certain issue or functionality. I mostly donā€™t find it helpful at all. Reagent is explained mostly for people who did work with React. Thatā€™s it. Itā€™s like I try to learn Japanese, and I am explained by what is the word is in Chinese.

  2. I still fight 90% of the time to get somehow the dots connected between cljs-start, Leiningen, deps.edn, cli, figwheel, Calva, REPL. As stated, I never did Java or JS, so I donā€™t have any experience with maven or npm, or what is a typical way of setting up dependencies in project (I choose Clojure exactly because I donā€™t want to learn these languages or tools). None of the Clojure books I have or online resource I found does cover these things in a good way for beginners.

Example: Today I tried to add a Clojure project I found on github to my project. This was apparently set up with Leiningen. How do I get integrated this with my deps.edn? What is anyway the best way? Clone the github repository locally? Add a dependency? If yes, how? No idea. Struggled whole day on this one. I need a broader picture about this.

1 Like

Most Clojure libraries are published to Clojars or Maven Central. Both are available by default to tools.deps.

So most likely you just define it as a Maven dependency in your deps.edn.

If the author did not publish the library, and only offers the source code, you can try adding it as a git dependency, it might work, unless the lib needs some prep.

Finally, if the lib needs some prep, and is not published to Clojars or Maven Central, youā€™ll have to pull it down locally and figure out how to get it prepared to be used as a dependency. This is most unlikely, Iā€™ve never had to do that for an open source Clojure library yet, but saying it could be possible.

1 Like

What I found works 99% of the time (I have not yet encountered the 1%, so it might be 100% of the time)

In Lein, you add this to the vector of dependencies: [org-name/lib-name "0.1.1"]
In deps, you add this to the map of dependencies: org-name/lib-name {:mvn-version "0.1.1"}

And in Lein, sometimes youā€™ll just have lib-name, no org-name, so you can try: lib-name/lib-name {:mvn-version "0.1.1"}

tl;dr: for beginners, learning the language is very easy, but learning to do something with it is very hard. Steep or not, it should be a single learning curve, not so many curves.

I am an eternal beginner, several times I have tried to get started with Clojure and ClojureScript, and several times I had to quit and move to more urgent matters. I know the language, I have even solved a good number of exercises in Codewars. But learning to use it is always too challenging. It would be better to:

  1. Have a tutorial from scratch, like start installing leiningen.
  2. Even better, have several similar tutorials, and an index/tree about the pros and cons of each path, e.g. leiningen will give you everything for Clojure, but if you want ClojureScript you may need shadow-cljs.
  3. Build simple applications (all starting from scratch):
    1. A script that processes files from a local folder.
    2. A backend that serves a few URLs.
    3. A frontend with a ToDo list.
    4. A container in the cloud.
    5. A lambda function in the cloud.
  4. Do not stop at having something that runs, consider: testing, CI/CD, linting, dependency management, etc. Learning Clojure is (IMHO) very easy. Clojure for the Brave covers the basics really well. But that is like the ā€œhow to draw an owlā€ meme. Eventually you want to commit to a repository, automatically run tests, and if all is green, push updates (both in backend and frontend) to the cloud, like using Terraform, lambda functions, Heroku, Docker,ā€¦ Now that video-tutorials are monetizable, I think there is a lot of money on the table.
    • Note: This kind of tutorial is really important (IMHO) and nearly impossible to find, for any language. Doesnā€™t anyone notice this? I feel like I am taking crazy pills!
  5. You may even want to share what you create in clojars, npm, or something else. The friction for that is so strong that thinking that people do it for free with FOSS is mindblowing.

Today I am here just because I had ClojureScript parked for many months and I wanted to make a quick and dirty script to process a .edn file, just change some timestamps according to a new timezone. In Python (which I use more often) I would have done the script in the time to write this post. In ClojureScript I am still trying to find out if I should install Leiningen, Lumo, Shadow-cljs, Yarn, a combination of the previous, or something else. All that I want is something that works, if possible something that works in the frontend and the backend.

I have even seen references to Webpack, regularly, I still have no idea where it goes in the pipeline. I understand it should be part of a github action for CI/CD, but I may be wrong. I cannot even begin to imagine why React and Reagent components may be incompatible, or different, and this incompatibility may be in one direction or both.

4 Likes

Humā€¦ Iā€™ve been looking to try something to walk people through actually building applications, and not just doing exercises like data-structures and algorithms stuff.

My first artifact from that is this: GitHub - didibus/clj-ddd-example: An example implementation of Domain Driven Design in Clojure.

My question is, what would you prefer to accompany that code base example and maybe to expand on?

Iā€™m thinking a video, but would you prefer a video where you see me implement that code base from scratch? I feel that can be tedious and less engaging to watch, as youā€™ll see me spending a lot of time just thinking and typing.

Or maybe a video walkthrough, where I walkthrough the code after the fact? And maybe where you see me setup my environment for cloning the repo, setting up my build, launching a REPL in it, testing it, and then maybe youā€™d see me configure CI/CD, database, and see me deploying it as well? And then using it in production?

And maybe I could do something similar for all the things you listed:

?

So instead of a video of me going through all that from scratch, Iā€™d make a repo, and then a video walkthrough of the code and how to go about running it and deploying it?

No promise here haha, just wondering if me or someone else wants to take a jab at it, would you prefer the walkthrough/run/deploy after the fact, or literally hours of video of me doing it all from scratch?

3 Likes

No videos, please. Instead, write a a blog post.

Explain the process of building the application, and insert code snippets after the explanation as an example of how to write it. The repository is something to check later, to see everything in context.

PD: then if you want make a YouTube video, walking people through the blog post. It is an inferior format, but it may be more monetizable. That is for you to decide.

2 Likes

Humā€¦ I worry a blog is too small a format to walkthrough writing a complete app, also when you get to setting up CI/CD, deployment, running the app, it becomes difficult to show in text form. Something like Web Development with Clojure 3rd edition the book kind of does what you want, but it takes a full book.

Still, maybe it is possible to somehow cut out a lot of details and still be useful. Iā€™ll think about it.

Do you have similar examples of that done but in another programming language for inspo?

Something like this:

  1. Introducing FastAPI. FastAPI is a modern, fastā€¦ | by SebastiĆ”n RamĆ­rez | Medium
  2. Host your Fastapi server on Heroku | by Devpenzil | Medium

When I mention:

I do not mean one repository with everything, but just the minimal codebase to cover that. The blog post should not explain everything, only the things that are new.

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.