PurelyFunctional.tv Newsletter 433: The "Clojure Effect"
Sign up for weekly Clojure tips, software design, and a Clojure coding challenge.
Clojure Tip 💡
The "Clojure Effect"
Back in April, I posted a question on Clojureverse which started a discussion about organizing code. At some point in the discussion, I coined the term Clojure Effect. I explained it a little bit, but it needs its own essay.
When I'm programming in Rails, I spend a lot of time learning Rails. When I'm programming in Spring, I spend a lot of time learning Spring. But when I programming in Ring, I spend a lot of time learning HTTP. Why the difference? That's what I was calling the Clojure Effect. Clojure and its ecosystem, when at its best, "exposes the underlying system to you and you are forced to work directly in it. That helps you build a better understanding of the system than you would if there were complicated layers of indirection between you and the system."
HTTP is a stateless, request/response protocol. A request is just data. A response is just data. So what better representation of an HTTP server than a function from request to response? Using this logic, Ring gives you the thinnest of indirections (mostly just translating HTTP---which is a text-based format---into hash maps). Because of that, you are forced to confront the decisions and complexities of the protocol. What data goes in headers? And what are those headers called? Which status code should I respond with? How do I correctly handle the HTTP Method, especially the ones we don't think about often, like HEAD and OPTIONS?
The routing libraries have the same effect. Forcing me to write out the
routes and provide a handler for each, I must ask: If these routes
correspond to URLs, and URLs are universal resource locators, what
exactly is a resource? What does it mean for one to be
Now, I don't want to say that frameworks don't have benefits. One of the great things about Rails is that it does have a different model. You can build complex things without first understanding the ins and outs of HTTP. But in exchange for that ability, you give up learning HTTP.
I think this effect applies generally in the Clojure ecosystem. For example, Clojure forces you to confront the notion of modularity more directly than some languages. In Java, the idea of modularity is tied up in the idea of classes, which is itself tied up in the idea of files. In Clojure, a function can exist in any namespace. So which one do you put it in?
This week on the podcast, I read from Alan Kay's and Rich Hickey's discussion on Hacker News 5 years ago.
Book update 📘
Folks, the Kindle and iBooks versions of Grokking Simplicity are unreadable. I apologize if you bought those versions. I've been in discussion with the publisher and they are pulling them temporarily while they improve them. They are getting third-party help to do a better job at those eBook versions. Thanks for your patience.
Quarantine update 😷
I know a lot of people are going through tougher times than I am. If you, for any reason, can't afford my courses, and you think the courses will help you, please hit reply and I will set you up. It's a small gesture I can make, but it might help.
I don't want to shame you or anybody that we should be using this time to work on our skills. The number one priority is your health and safety. I know I haven't been able to work very much, let alone learn some new skill. But if learning Clojure is important to you, and you can't afford it, just hit reply and I'll set you up. Keeping busy can keep us sane.
Stay healthy. Wash your hands. Wear a mask. Get vaccinated if you can. Take care of loved ones.
Clojure Challenge 🤔
Last issue's challenge
- Atbash Cipher - Submissions
This week's challenge
Given two words, we can determine if they have the same vowels, ignoring
order and repetition. For instance, "Hello" and "Vowel" both have
\o, so they have the same vowels. Write a function that
groups words into "families" that all have the same vowels. "Tree"
and "tent" also belong to the same family because we ignore the
(vowel-families ["hello" "vowel" "fox" "cot" "hat" "cat"]) ;=> [["hello" "vowel"] ; ["fox" "cot"] ; ["hat" "cat"]] (vowel-families ) ;=>  (vowel-families ["tree" "tent" "blanket"] ;=> [["tree" "tent"] ; ["blanket"]]
For this exercise, the vowels are
you wish, you may include vowels from other languages and scripts. Your
algorithm should not be case-sensitive.
Please maintain capitalization and non-alphabetic characters.
Thanks to this site for the problem idea, where it is rated Very Hard in Python. The problem has been modified.
Please submit your solutions as comments on this gist.