A Clojure learning journey
stuttaford.me
stuttaford.me
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.
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.
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?
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).
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.
Here's a good article I've found with information about them:
http://josf.info/blog/2014/03/21/getting-acquainted-with-clo...
http://www.smashcompany.com/technology/embarrassing-code-i-w...
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.
Coming from Django Rest Framework I felt at home with Compojure-API.
Hearing "you are overqualified" is awful.
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.
Maybe if you had used datomic as your database it would’ve been fine (/s)
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.
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...
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.
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.
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...
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.
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.)
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. :)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.
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.
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.
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.
Another option your comment suggests would be something in popular science or media.
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.
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.
How does one get into these kind of writing jobs, for someone with a programming background?
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.
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.
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.
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).