PurelyFunctional.tv Newsletter 424: Leverage in a thriving ecosystem
Issue 424 - April 27, 2021 · Archives · Subscribe
Design Thoughts 💡
Leverage in a thriving ecosystem
In Clojure, we often look for leverage. Leverage is ideal in a walled garden where we lack the free labor to solve problems the hard way. However, in an open ecosystem, demands are numerous and lack a coherent design. We often just need to apply brute force. But how can we, when the Clojure community is so tiny? We use Clojure's most powerful ethic: to inject a high-leverage tool into a thriving ecosystem.
Lisp is a high-leverage language. With a few basic constructs, you can write a high-level solution. That works really well in a walled garden. If your Lisp system only interacts with other Lisp systems, you can build very quickly. You are making a wall against the churn on the outside.
The walling off of Lisp and its high power led to the success of artificial intelligence projects until the late 1980s. Researchers could build their own solutions to their needs because they had sharp tools. I felt this power when I was writing Common Lisp. Although I didn't have access to all of Java's libraries, I could satisfy my particular needs. This was a common sentiment among lispers.
However, in 2008, I attended a small conference called "Lisp 50", which celebrated the 50th anniversary of Lisp. People were expressing that sentiment a lot: "we can do anything with Lisp." But one man spoke up: "I've been trying to build a consultancy using Common Lisp. I believe it is a better language with more leverage. But every time I talk to an enterprise client, they need me to use WSDL and Web Services. I lose the client because I can't find a Lisp solution for those." The lispers had rejected a prevalent practice, Web Services, from their garden. Despite the leverage, this man could not reach the abundance just over the wall.
Then Rich Hickey presented his new language, Clojure. It spoke directly to this issue. Outside the wall, there are legions of people using primitive tools. Although you can build elegant structures inside the garden, there is enough labor to build pyramids outside.
Here's the thing about the world outside of the wall: Yes, the solutions are less than ideal, yes, the rabble churns through those naive solutions, and yes, they are built out of millions of if statements instead of leveraged techniques. However, those ecosystems are so massive---measured in dollars and measured in people---that they solve the problems you've solved---and more---eventually.
Rich Hickey's solution was to design Clojure as a high-leverage language within a thriving ecosystem. Clojure provides a functional and data-oriented garden. But also gives you enough seamless interoperation to use the gazillions of libraries available on the JVM. It's not perfect, but it works for a large class of problems. And the time had come for it. Lisp's once-lucrative garden was in decline. We should reach for this tactic whenever we feel the legendary smugness of the lisper because it means we resent the thriving ecosystem outside our garden.
Over the years, this same tactic was applied powerfully in
sub-ecosystems. Ring leverages Java's webserver ecosystem. clj-http
leverages the Apache HTTP libraries. And many more.
Let's look at two other related examples that illustrate what happens when your solution arrives early before the ecosystem is established. When ClojureScript was released in 2011, jQuery dominated the JavaScript scene. ClojureScript broke with that trend and used Google Closure as a module standard and to leverage its compiler. Since then, the ecosystem has evolved into a giant collection of JavaScript libraries for every purpose, written in various dialects of JavaScript, hosted on npm, and built with different transpilation pipelines.
Meanwhile, ClojureScript still compiles to the same old JavaScript subset that Google Closure worked with back in 2011. And it uses the same old module system. ClojureScript has been walled off from all of that churn. As the npm ecosystem grew, however, that wall prevented ClojureScript from taking advantage of it. Though many attempts have been made, Shadow CLJS has found a way to open the wall. Shadow is the best solution to interoperability with npm and JavaScript libraries.
React is another example. When it came out, there was no React ecosystem to tap into. The ClojureScript community quickly chose Reagent as the de facto solution. It's a high-leverage approach, pinpointing the problem of reactivity to state. While React churned, we were productive. However, React has found something very cool with React Hooks. And there's now a thriving ecosystem of tools and libraries that are mostly incompatible with Reagent. It's time that we re-looked at wrapping React with an eye toward interoperability with the ecosystem.
Clojure innovated the symbiotic language---a language designed to run within a runtime. We can generalize that to a strategy: Build a high-leverage tool within a thriving ecosystem. However, it may be that there is no ecosystem to thrive within. That can happen if you're very early, as Lisp was in computing, as Clojure was with ClojureScript, and as ClojureScript was with React. In those cases, the wall is quite protective. However, we must open the wall eventually to take advantage of the emergent solutions thriving outside.
Awesome book 📖
A World Without Email by Cal Newport.
I've been a fan of Cal Newport for about 12 years now. His other books resonated with me. I always appreciated his analytical approach. So I was eagerly awaiting this new book which attempts to understand why email is drowning us at work and what we can do about it. His explanation is clear: instead of planning our coordination ahead of time, we just "shoot a quick email" whenever we have a question. A vicious cycle leads us to answer emails more quickly and expect answers quickly as well.
The solutions are nuanced. I want to try some of them myself. He analyzes different sources of email and the different systemic pressures pushing them toward an unhealthy use of the medium. I don't think it's going to completely "solve email" for me because even if you improve it for yourself, others are still under the sway of those pressures. But the ideas are well-reasoned. I think they could help.
Podcast episode🎙
This week on the podcast, I talk about the two phases of domain modeling.
Podcast appearance 📢
I was honored to talk about functional programming and legacy code on the Legacy Code Rocks podcast.
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. Take care of loved ones.
Clojure Challenge 🤔
Last issue's challenge
- No challenge
This week's challenge
Sock pairs
After doing laundry, your socks are unmatched to their pairs. You need to match them!
Write a function that takes a collection of values and makes pairs if they are equal. If there is not a match for a particular value, return it as well.
(pair-match []) ;=> {:pairs [] :unmatched []}
(pair-match [1 2 1]) ;=> {:pairs [[1 1]] :unmatched [2]}
(pair-match [1 2 3 1 2 3 1 1 2]) ;=> {:pairs [[1 1] [2 2] [3 3] [1 1]]
;=> :unmatc
hed [2]}
Note: It's like socks. If you have 3 blue socks, that's one pair and one unmatched. If you have 4 blue socks, that's two pairs.
Thanks to this site for the problem idea, where it is rated Hard in Ruby. The problem has been modified.
Please submit your solutions as comments on this gist.
Rock on!
Eric Normand