Hacker News new | past | comments | ask | show | jobs | submit login
A Clojure learning journey (stuttaford.me)
215 points by robstu on Feb 19, 2018 | hide | past | favorite | 66 comments



Not sure why the excitement around ditching Lein when it looks like there is little or nothing to be gained at this time? The author describes a handful of other tools that are necessary to do things Lein does out of the box (uberjar)

The Clojure ecosystem (specifically through the lens of this post) reminds me of the Linux desktop ecosystem. Lots and lots of tweaks and knobs and dials for the sake of having tweaks and knobs and dials.

That’s my biggest gripe with Clj... there is hardly ever a “right way” to do things and usually a dozen esoteric approaches to organizing your application. It’s a blessing and a curse. All the rope to hang yourself with.

That being said I really like writing Clojure in the pure sense but have yet to see a really pleasant 1. App architecture and 2. Web application and routing layer. Ring/compojure don’t do it for me.


It wasn't so much about ditching Lein as it was taking a clean-slate opportunity to learn and understand the new CLI tooling.

Nothing wrong with Lein at all!

Knobs and dials: this is true of every eco-system, wouldn't you say? Is 2018 the year of the linux desktop, finally? :-)

I agree that Clojure has a lot.

Right assumes a known context. Do what is right for you. Sometimes, that's Knob A, and sometimes that's Dial B. The fun is in figuring it out.


As a newcomer, I want sensible defaults. I want a Rails. Let me wait to learn the knobs and dials when I’ve got enough base knowledge to evaluate them fairly.


LuminusWeb is a great option for that. The generated code is simple to grasp and change as your knowledge grows.

http://www.luminusweb.net/


https://github.com/plexus/chestnut is Clojurescript, but it's fantastic. It's quite easy to roll out a UI and you can build your backend to your specifications. A bit less opinionated than Luminus, but both great for just getting started.


That being said I really like writing Clojure in the pure sense but have yet to see a really pleasant 1. App architecture and 2. Web application and routing layer. Ring/compojure don’t do it for me.

Aren't pretty much all languages the same in this area? expressjs/sinatra/flask, or are you implying you prefer opinionated frameworks like rails?

So I'm curious, what's a pleasant app architecture, web app/routing layer for you?


> Lots and lots of tweaks and knobs and dials

This is the case with all big-tent, "community-driven" PLs that have a high expressiveness, and attract contributors that have a multitude of preferences: Ruby, Javascript, Scala, Clojure, Haskell, Racket

Alternatively, are the 'prescriptive' cultures, that tend to select for predictability and high cohesion: C#, Elm, Go, Python (circa-2007).


It's interesting to see Ruby in there. The language definitely tries to cater to everyone's taste and offers a ton of ways to do the same thing. The community though seems a little more opinionated though. Everyone is set on bundler for example. There are really only two big testing frameworks that compete and the have very different goals etc.


It would be interesting to study the MBTI psyche types in each of the major language communities.


Would it be fair to say phrenological study of the same groups might be similarly interesting?


No.


@whalesalad, would you be willing to give me direct feedback on this project, as I go? I'd love to understand your pain points more fully!


Sure, my email is in my profile.


This probably doesn't really help you, but for "Web application and routing layer. Ring/compojure don’t do it for me.", I really love bidi and yada (both by juxt) as a very pleasant routing/web app layer. I also really love the re-frame app architecture, but its for clojurescript frontend only. So far, my backend needs have been very simple, but I would love for a re-frame-like system for backend too, that would be pretty nice IMHO.


I just got rejected in a hiring process at Nubank (a sexy fintec from Brazil that uses clojure a lot) because I used a database for the take-home code challenge they sent me (writing a REST API). Since I'm a Python developer who knows little about concurrency in clojure and I would not like to use locks, I thought it would be better to delegate these things to the database.

Apparently I was supposed to use a global shared collection instead of a proper database because they want to see if I'm able to map/filter/reduce.

Recruiting is such a gamble - I have this former colleague that I've introduced to functional programming and he passed with flying colors at Nubank's recruiting hoops. I would not say I'm smarter than him but he would agree that I know more about our trade.


I had a similar assignment when I applied for a remote Clojure job at a startup in California. Create a REST API in Clojure (which I can do in my sleep at this point). I decided to use a database (in my case, H2) along with HugSQL because it handled some of the requirements for me (unique constraints, etc.), and I'm comfortable with databases. I could have done it in code using a collection (and used filter/map/reduce/etc.), but just using a database and defining a schema seemed the simplest and most fool-proof solution (and I think the proper place for these sorts of checks is in the database, anyway).

During the code review, the interviewer seemed surprised that I used a database, but didn't seem to have much of a problem with it ("you're the only one I've seen do it that way"). In any event, the 'code review' consisted of him saying "Well, um.... I can't really find anything wrong with this, you're definitely a good Clojure developer"

And then they passed on me anyway. I wonder if they ever filled the position?

P.S., not the first time something like this has happened to me, I've had nearly the exact same experience when I applied for a Golang job.

P.P.S., Also I've got the "Pass. We think you'd be bored here." Which is aggravating. It seems I can only find employment at places with nearly non-existent tech screening that under-utilize me and don't care if I'm bored out of my skull.


HugSQL is very handy - used it for my solution also.

Coming from Django Rest Framework I felt at home with Compojure-API.

Hearing "you are overqualified" is awful.


Not being a Clojure dev I'm curious: Wouldn't a database be the more scalable solution? How would multiple servers share access to the data of it's in memory? What about persistence?


It was an 'exercise' for evaluation purpose. In the instructions I was told that a database was not necessary (I'm assuming the interviewer didn't want to have to setup a DBMS just to evaluate my solution).

The obvious solution to me in this case was not to eschew the use of a database. Since Clojure runs on the JVM, there are many 'embeddable' databases one can use (H2, Derby, et al) that do not place a burden on the person running your program. Hacking together a poor implementation of an in-memory database myself seemed silly.

Indeed, a major use of embedded databases like H2 and Derby is in prototyping - with the intent of moving to a 'real' database in production.


Having 5 years professional experience with Clojure, I applied a few months ago to a remote Clojure job, and the coding test was none other than recursion via zippers, literally my weakest point. I could have done the job just fine since they said they didn’t use zippers on the job, but failed the test and they passed on me. Coding tests are the real problem. I’ve had some great ones where you can tell someone put effort into it and will review it fairly, and I’ve had some that were hacked together like this one where it’s clear they weren’t given enough time to put it together by their superiors.


Coding tests aren't always the problem, but coding tests that evaluate skills the company doesn't even use? That's just disrespectful.


Zippers! This is definitely a knowledge gap for me; thank you for putting a name to a thing that I've encountered in the wild.

Here's a good article I've found with information about them:

http://josf.info/blog/2014/03/21/getting-acquainted-with-clo...


Yea, a proper technical interview needs have more breadth to mean anything. This question is pretty dang close to esoteric language features trivia. Which would have flustered me when I was young, but now just makes me angry and I'd probably (want to) launch a dry-erase marker at your head.


There is also the issue of nervousness that comes up at coding interviews. See "Embarrassing code I wrote under stress at a job interview":

http://www.smashcompany.com/technology/embarrassing-code-i-w...


During one of my first coding interviews I used a goto. I simply forgot about the existence of loops I was so nervous, but for some reason the archivist in the back of my brain responsible for preserving my childhood Apple ][ BASIC knowledge stepped up and said "I got this."


That’s pretty funny. Did they really not mention anything about using an atom when they sent you the assignment?

Maybe if you had used datomic as your database it would’ve been fine (/s)


The first assignment was writing an algorithm for managing a job queue according to some precedence rules involving job and worker properties. Input and output were JSON formatted data over stdin/stdout and my solution used native collections and car/cdr style recursion.

They said it was OK and asked me to turn it into a REST web service as the second part of the assignment. Now I had to keep score between calls but sharing data using a global structure goes against every fiber of my developer muscles so I picked a database. I'm no clojure expert but I guess in the real world most REST APIs are using databases under the hood instead of atoms.


Everytime I use clojure for some new project because I think it will help, I end up spending too much time on tooling and setup, and in the end change it to something easier to setup, which strangely that's javascript sometimes. I want to go work in a team where they have it ready for me and I can learn the tooling on the way, without needing to do that up front..


I think everyone goes through this when they're newish to clojure - it's a recognized deficiency in the ecosystem, and one that needs to be solved sooner than later.

However, I will say that once you "pick your poison" and get used to a specific workflow, it becomes vastly easier. The same set of tools work for pretty much any kind of project.

Stuart Halloway gives a great talk[0] where he drunkenly expounds on the importance of REPL driven development and explains his workflow. Honestly, this changed the way I work day-to-day for the better and helped me realize the power that tools like Emacs and Cursive give you; specifically, in-editor evaluation of forms.

For me, I use leiningen for building/dependencies and Emacs/CIDER for my editor. Another good choice is Cursive. Then split it up by what runtime I'm targetting:

Clojure/JVM: - mount for state - ring for HTTP services - clj-http for HTTP requests

ClojureScript/JS: - shadow-cljs for building (with lein integration) - mount for state - macchiato for HTTP services - cljs-http for HTTP requests - reagent for UI

These tools & libraries cover about 80-90% of what I need in a new project, and everything after that is specific to the use case.

Wading through one or two self-contained projects goes a long way into helping you figure out your workflow, and afterwards it's just applying it.

My hope is that in the near future, a lot of the initial friction will be wicked away from the tooling and people will be able to get spun up much faster. Advanced Clojure workflow is a very different way of developing software than most people are used to, though.

[0]: https://vimeo.com/223309989


I don't know how long it's been since you tried but I'd suggest giving it another go. The tooling today is what makes it one of the best experiences out there. The front-end tooling especially!


Can you speak to the front end tooling a bit more? I know Cursive makes for a nice coding experience in general, but I haven't really done any Clojurescript work to speak of.


[posting on an alt because noprocrast just kicked in on my main account]

The second half of this blog post talks a lot about what cljs dev is like: http://blog.jrheard.com/quinto-resurrecting-an-abandoned-boa...


Figwheel gives you a fantastic live coding type environment experience on the frontend. I'd suggest checking out the 6 minute demo linked here to really get what it does:

https://github.com/bhauman/lein-figwheel


All you need for setting up a Clojure web project is a copy of the JDK and Leiningen. With that in place you just do:

lein new luminus myapp

and you're good to go. This will create a new instance of the Luminus (http://www.luminusweb.net/) tempalte that sets up all the boilerplate with reasonable defaults.


I always read about those nice functional languages, but when I try to learn them myself I struggle pretty hard.

Can anybody point me to some small (5k LOC maybe) project on github that solves some "real world" problem?

I'd like to get some overview. As opposed to the usual tutorials that start with the very basics and don't seem to get anywhere...


This is exactly the reason I'm doing this :-)

From my past efforts, I can offer you https://github.com/cognician/datomic-doc, which is a riff on the idea of marrying a Markdown editor to doc strings on entities in a Datomic database.

It exposes a handful of Ring handlers as a library, so you can plug it into any Ring web app that uses Datomic and get a turn-key tech doc system.

It's a complete Clojure/ClojureScript/Datomic application, and it's only 800 lines.

I hope it helps you, and feedback is totally welcome!

As for 'book learning'; Living Clojure by Carin Meier is currently in the USD 1 Humble Bundle at https://www.humblebundle.com/books/functional-programming-bo.... It has a 13 week FP course in it. Highly recommended.


I've created this repo [1] exactly for that purpose i.e. show a solution for some clean, moderately complicated problem in Clojure.

[1] https://github.com/achikin/game2048-clj


It’s not Clojure, but the practical chapters in the book Practical Common Lisp might be a good way to get a feel for the way a Lisp works in a practical application.


>book Practical Common Lisp

It is a wonderful book and Common Lisp is powerful to the max, but note that CL is a multi-paradigm language and examples won't necessarily be in the "functional" style. Quite the opposite, Common Lisp makes imperative programming very comfortable (and OOP as well.)


While Common Lisp definitely allows for imperative constructs, I’d argue that its flavor of OOP is part of the functional paradigm: i.e. generic functions aren’t part of the classes, they are protocols that can be implemented in different ways by different classes. They are closer to typeclasses than to java-style OOP


We all learn differently, but I found Brave Clojure was a quick read:

https://www.braveclojure.com

From there I just started small by building some command line applications to solve every day needs. Many enjoy solving problems at http://www.4clojure.com as a method of learning.

Perhaps one of the main differences for someone coming from an OO world is that in OO, to learn an SDK means learning about all the classes and the methods they expose to operate on encapsulated data. You're limited to what you can do on the data via those public methods.

In a functional language, you instead learn a large amount of functions that operate on raw data directly. Then you build your app by creating functions that take an input and transforming it into a new output using these common set of functions.

One of the exciting things for me is Clojure Spec. One of the recurring problems in web development in an OO app is that you have some domain class like User and you have some service function which does CRUD on that User.

    // Look how great our model layer is!
    createUser(User)
Then as the app grows you have another service function which takes a Order object and 80% of the properties of User.

So you may start with this:

    // uses 100% of order, 80% of user
    doSomething(Order order, User user)
Then you have another service function which takes 3 object but only uses a few properties of each:

    // this feels like a code smell
    doAnotherThing(Order order, User user, SomethineElse somethingElse)
If you have a large team without a strong common practice an application can quickly turn into a ball of spaghetti:

    // let's list out specifically what this function takes
    doAnotherThing2(long orderId, double orderTotal, long userId, String userName, A something1, B something2)
And then you reach some maximum amount of parameters and refactor it to this:

    doAnotherThing3(DoAnotherThingRequest request)
DoAnotherThingRequest feels right but it's redefining the types of all of the properties already defined in our domain model:

    class DoAnotherThingRequest {
        long orderId;
        double orderTotal; ... }
And then you have another function which needs DoAnotherThingRequest and a few properties of another class:

    class YetAnotherThingRequest extends DoAnotherThingRequest {
        A something; ... }
And eventually you realize this is stupid and instead you do this:

    // Let's just use the raw JSON!
    doAnotherThing4(JSON json)
Clojure Spec on the other hand makes much more sense to me. You can define specs on namespaced keywords:

    :order/total is an integer
    :user/userName is a string with a maximum length of 10
And then your function can specify the shape of the data they receive:

    ; this requires an order total and a userName (Note: it doesn't redefine their specifications)
    (s/def ::do-another-thing-request (s/keys :req [:order/total :user/userName ...])))
This makes much more sense to me as a way of building large systems. And then you find out that Clojure spec can generate tests on your functions automatically based on the specifications you created and your mind is blown. :)


This is amazing. More people should get to know clojure as it's a wonderful language that has almost all concurrency models on this planet. Also now with core.typed it retains most of the benefits of the statically typed ones while being as productive as other dynamic ones or more.


> More people should get to know clojure as it's a wonderful language that has almost all concurrency models on this planet.

Clojure is great. But Rust is a Must, so I hear, and you will need some Python for ML. And then of course JavaScript if your stuff touches the web, and it all does. And there is Go and Erlang or is that Elixir for systems and transactions. Ruby or PHP for RAD and Java for the large stuff can not be ignored.

And before you know it you'll be bad at 25 languages, instead of good in one or two that allow you to do what needs to be done.

All these languages are great in the sense that they exist and show what is possible but they make it super hard for a professional programmer with ~8 hours in a productive day to choose which eco system (which is far larger than just the language by itself) they want to invest their time in leading to some variation on the paralysis of choice theme.

I'm super happy I don't have to earn my bread by coding today, I sincerely would not know what to choose to maximize longer term value of my investment in time. It's like building a house on quicksand.


I use Clojure (or Clojurescript) for all of the things you listed. When I need something other than Clojure, that thing is typically C which is either a device driver or something I'm going to call into from Clojure. In the past I used mostly Python/Javascript/C instead of Clojure/C to get where I wanted to be.

Just to be clear, I use clj/cljs (day to day) for:

* Mobile Applications on Android/iOS

* Analytics and Data Wrangling off queues

* Data Analysis

* Admin Dashboard stuff (CRUD, Charts/Graphs, misc)

* Business Rules

* User Messaging (Push / Email / Webhooks)

* Database ETL

* Web Services

* Background jobs

* Build System and Deployments

The only thing I don't use that is Clojure-based, on a regular basis for my job, is SaltStack for configuration management (and this is largely because we have a working SaltStack system that I don't have a need to mess with).

I'm super happy when I can spend most of my day with a monitor dedicated to Spacemacs while jacked into a clojure repl.


But does Clojure/C really makes you more productive than Python/Javascript/C? which I guess is the point the GP was referring to, although, you mentioned it makes you happy (which is a good of enough reason as any).

Don't get me wrong, I think learning Clojure is helpful for lots of developers, even if they won't use it for work/side projects, and I think that's exactly what happens in the Clojure ecosystem and the reason for so many libs being half finished and abandoned, devs learn Clojure, grab all the ideas and concepts, scratch an itch but ultimate terminate going back to their mainstream langs.


It sounds like you're suggesting that Python/Node have better libraries, which couldn't be further from the truth. Most "abandoned" Clojure libraries either (a). aren't abandoned and "just work" due to their limited scope or (b). are wrappers to Java libraries that are trivial or unnecessary. Most people would rather to interop directly.


To offer one small piece of anecdote to the contrary: We use Clojure for most of our server-side code and picked Lacinia from Walmart Labs [0] to implement our new GraphQL API. It does most of the basics just fine, but its pace of development lags extremely, painfully far behind GraphQL server implementations in more popular languages such as the ones in Node and Python. To this day it still doesn't have support for custom directives [1], not to mention any of the other more bleeding edge developments in the GraphQL community such as schema stitching and live queries, all of which we would really have liked to experiment with along with the rest of the GraphQL community. We ran into similar issues initially when trying to use gRPC with Clojure.

We love writing Clojure and still use it everywhere where appropriate, but the size of its community and ecosystem is definitely holding back its ability to compete for adoption with other languages on the bleeding edge of new technological trends.

[0] http://lacinia.readthedocs.io/en/latest/

[1] http://lacinia.readthedocs.io/en/latest/directives.html


Fair -- GraphQL seems like something that is particularly well suited to having a Clojure API so that's disappointing to hear it lags behind other implementations.


To what extent does the Python GIL hold it back from performing multithreaded tasks as compared to Clojure? I'm mostly a Python programmer but I've experimented with Clojure a few times for some small projects, and I've noticed the multithreading options with Clojure to be more plentiful and capable.


The best value a language can provide is the community around it. That is, the amount of high quality libraries out there. And the choices, when coming from this stance, are a handful: .Net and JVM ecosystems, Python, C/C++, then Perl and Ruby to some extent. With these, you know most of the generic things you'll need to have in order to do the specific thing you want to do are available to you. Equally important the amount of documentation and literature out there. The actual language features, syntax, etc., all come after this. First of all, a language has to have some giants with nice stable shoulders.


"And before you know it you'll be bad at 25 languages, instead of good in one or two that allow you to do what needs to be done."

I'm not sure that follows. Even if you choose to specialise in one stack, it is healthy to see a diversity of solutions and opinions/trade-offs in solving similar problems across different stacks. Even if you don't end up mastering any of those, exposure to those can help inform how you approach problems in other languages.

A lot of great ideas in modern ecosystems were stolen/inspired from lateral solutions (e.g. using immutable datastructures with React from the ClojureScript world, Netflix's Falcor influencing om.next in the other direction).


Would you share info about how you transitioned out of coding? I'm looking to do the same.


It was mostly co-incidence and some luck.

After a few thousand sweaters the next one is probably similar to one that you already made so I got bored and ended up burning out. That left me without desire to work on anything computer related, I bought a farm in Canada, moved there and ended up working on a windmill.

The websites I was running still contributed some income so I wasn't particularly worried about running dry.

Making the windmill required some tools, one of which was a computer controlled plasma cutter that I could not afford ready made and so I ended up cobbling it together. There was a little bit of software involved in that but nothing that occupied me for more than a few days.

The windmill design process involved rather more software but still it was peripheral to the rest of the work.

Then, in 2007 after returning back to NL I invested in a bunch of start-ups and at one of those a co-investor asked me if I wanted to do technical due diligence for a colleague, which turned out to be Endeit Capital, a well respected Dutch VC. One thing leading to another we are now working together for a decade+ and they've sent me lots of other customers as well so I'm nearly full time busy with this.

In the intermediate I also ran ww.com/camarades.com until enough money came in through the DD's that I no longer needed that income, I sold of all the assets in 2015.


> so I got bored and ended up burning out. That left me without desire to work on anything computer related,

I've been finding myself like this lately :( Sadly, I can't afford to buy a farm but working on a windmill sounds awesome! I've lately spent a lot of my time learning sleight of hand and magic illusions, but I don't expect I'll ever make any real money out of it, I'm just not a natural showman. I'll stick to software since its the only real marketable skill I have, but it is rather frustrating. I do love Clojure, though, but there's not much Clojure work where I am.

Thanks for sharing your story, its inspiring.


Some things that might help you:

I've noticed that the real money is usually to be made on the intersection of disciplines rather than by going deep into a single discipline.

So maybe it would be an option for you to branch out into a different field that intersects regularly with software, possibilities such as hardware or legal are most obvious.

That will give you something new to sink your teeth in while at the same time allowing you to re-use your old skills and knowledge to good effect.


Thanks for that, I really appreciate it!


You're welcome, I really hope it works out for you. If I can help with introductions or in any other way feel free to mail me.


Any suggestions for someone who's a competent developer, and an excellent communicator with a knack for explaining things to a non-technical audience?


Technical writers worth their salt are few and far between.

Another option your comment suggests would be something in popular science or media.


Technical writers worth their salt are few and far between.

Could you please expand on this one? Do you mean people who write help guides for OS/APIs, or do people who write industry reports or is it something different? Also, do you have any examples of such people/jobs?

This is something that is very interesting to me but I have no idea where to start.


Just to give a few examples:

We produce about one report per week, < 20 pages for venture capital groups about to invest into some company. That's a pretty tricky combination of elements, you are writing for a non-technical audience about technical findings.

The companies we work for tend to have people on the business side that have certain ideas about requirements which then need to be translated into technical specifications, typically so that some outsourcing company can make soup of it.

In both cases mistakes can be quite costly. There is this thread right now about 'what HN has given you', and if there is one thing HN has given me it is that it has made me a better writer (that, and blogging), which turned out to be a super useful skill.


Thank You.

How does one get into these kind of writing jobs, for someone with a programming background?


Go talk to places that produce reports: M&A outfits, VCs, research companies and so on.


Damn, this is so close to my state of mind right now. Either a farm or a cafeteria morning service and the rest of the day leaning in grass or painting.


I really like Clojure and am using it for a web project now. Datomic is awesome too, but not appropriate for my current project unfortunately (gis stuff)


Fascinating how large it is.. it's more than a learning.. or at least it's deep learning (sic).




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: