|
'Well then, alone!' – Elektra's cry when Chrysothemis refuses to help her. Not triumphant independence, but desperate necessity fused with unwavering resolve. The isolation isn't chosen; it's forced by the impossibility of finding anyone who shares her singular purpose. Orestes isn't likely to materialise. There was a functional programming conference in Stockholm recently. I'm sure it was excellent. I didn't attend. I should probably have been there – Ooloi is built in Clojure, after all, and finding collaborators would be useful – but I felt conflicted, and that conflict revealed something I'd been avoiding: the FP community cannot help me, and I don't need it anyway. Sect DynamicsI'm disappointed with the functional programming community. I was expecting higher-level thinking – freer thinking, commensurate with the intellectual freedom Clojure itself offers – but the atmosphere proved to be a shallow puddle of sectarianism. That probably has its reasons – being marginalised as a community is probably one of them – but the end result remains unchanged. The patterns are unmistakable. Knowledge as gatekeeping: the endless monad tutorial phenomenon, where every advocate believes they can explain monads better than everyone else, typically through increasingly baroque metaphors involving burritos, space suits, or elephants. This isn't pedagogy; it's ritual initiation. The complexity serves a social function – maintaining boundaries between insiders and outsiders. Purity as virtue signalling: debates about whether using `IO` makes you impure, whether exceptions violate functional principles, whether mutation in bounded contexts is acceptable. These discussions frame technical trade-offs as moral categories, as though architectural design were a moral discipline rather than an engineering one. The language reveals it – clean, pure, disciplined versus dirty, impure, undisciplined. This is religious vocabulary applied to software engineering. Terminology as tribal marker: deliberate retention of academic terminology when simpler terms exist. Endofunctor, catamorphism, anamorphism when 'map over containers', 'fold', 'unfold' would suffice. The obscurity is the point – it establishes hierarchy and demonstrates membership. The emphasis falls on mathematical elegance rather than problem-solving. The question isn't Does this help ship software but Is this theoretically sound. People who can recite monad laws but have never shipped a product receive more status than developers applying functional patterns to solve actual problems. Then there's the missionary behaviour: the conviction that imperative programmers need conversion. The framework isn't Here's another useful tool but You're doing it wrong until you see the light. This creates antagonism rather than adoption. Being marginalised as a community probably explains some of this – defensive posture manifesting as increased boundary enforcement, which creates insider/outsider distinctions, which enables status hierarchies based on doctrinal purity. But understanding the cause doesn't change the result, and it doesn't make the behaviour intellectually rigorous or practically useful. The Clojure Exception Clojure largely escaped this because Rich Hickey explicitly rejected purity culture. 'It's acceptable to use Java libraries'. 'Mutability in bounded contexts is fine'. 'Solve problems first'. The Clojure community focused on what you can build, not on arcane knowledge as status marker. This produced broader adoption without compromising functional principles. This is why I chose Clojure for Ooloi in the first place. But even within that pragmatic oasis, the broader FP community dynamics leak through. The conference I didn't attend would have featured both kinds of people – those interested in building things and those interested in doctrinal purity – and I couldn't predict which would predominate. The Intersection Problem Here's the substantive issue: finding Ooloi collaborators in FP communities is statistically improbable because very few people occupy my intersection point between various disciplines. Music notation requires an understanding of compositional structure, engraving conventions, and how musicians actually work. Functional architecture requires a sophisticated understanding of immutability, higher-order functions, transducers, STM transactions, and compositional patterns. Backend infrastructure requires a willingness to work on unglamorous problems like endpoint resolution and temporal traversal rather than visible features, and in Ooloi's case, an understanding of server technology and secure cloud operations. The population at that intersection is approximately one. FP communities might yield people who appreciate my transducer implementations or STM transaction handling. But they won't understand why endpoint resolution for slurs matters, how temporal traversal serves musical structure, or what makes intelligent engraving different from geometric placement. The domain expertise is orthogonal to FP community concentration. The inverse holds equally: musicians who understand notation deeply rarely have the architectural sophistication to work on Ooloi's core, and even fewer would find satisfaction in building infrastructure rather than using tools. I've worked outside the FP community all my life. Functional programming is a tool, not a (monadic) religion. (And why are monadic and nomadic so similar?) Why join the community now, when the benefits are unclear and the costs palpable? Consilium LatinumThe technical response is what I call the Latin strategy: making Ooloi's core a stable foundation for a plugin ecosystem. Build the architectural core once in Clojure, then let developers in other JVM languages contribute via plugins without needing to understand the underlying functional implementation. I've written about this approach in Penitenziagite!, so I won't rehearse it here. Elektra or Quixote? The psychological question is whether this makes me Elektra or Don Quixote. Elektra confronts a real murder, real injustice, a legitimate need for action that others refuse. The isolation comes from their cowardice or pragmatism, not from her misunderstanding of reality. The task is achievable and gets completed. The tragedy is the psychological cost, not the validity of the purpose. Quixote confronts imaginary problems with obsolete ideals, mistaking windmills for giants. The isolation comes from a fundamental disconnect with reality. The task is impossible because it's based on delusion. The comedy (later tragedy) is that the quest itself is meaningless. The distinction depends on whether the problem is real. Do musicians actually need what Ooloi provides? If existing notation software genuinely fails at problems Ooloi solves, then Elektra. If musicians are adequately served by current tools, if the architectural sophistication I'm building doesn't translate to problems they actually experience, then Quixote. But there's a third option beyond tragic obsession and delusional quest. I'm building something architecturally excellent because I can, because it interests me, because functional approaches to musical structure are intellectually satisfying. The architecture might be elegant, but it's not worth psychological dissolution. The Latin model suggests I've already chosen this third path. I'm building core infrastructure well, documenting it properly, then making it available via plugin architecture that assumes others might have different needs. That's craft separated from identity. Not Dancing to DeathElektra's tragedy is total consumption by purpose. She becomes nothing but the task, and when it completes, there's nothing left because she permitted no existence beyond vengeance. She dances herself to death.
I'm certainly not doing that. Ooloi is a project, not my entire existence. Sustainable completion means finishing the backend, documenting it clearly, releasing it, and then moving on. The work stands independently; I remain separate from it. I'll finish Ooloi's core architecture working alone, not because I prefer isolation, but because collaboration at this intersection point is impractical. The resolve comes from accepting reality rather than pretending community exists where it doesn't. The backend is complete. The transducer-based timewalker is fast, tight, and efficient. Endpoint resolution handles slurs and ties correctly. Nearly nineteen thousand tests pass. Vector Path Descriptors enable elegant client-server communication. Then comes plugin architecture, and seeing whether anyone finds Ooloi useful. If they do, excellent. If they don't, I built something architecturally sound and learned what I needed to learn. Either way, the work speaks for itself. And I continue existing beyond it. Nun denn, allein!
0 Comments
I'm one of the world's most committed anti-religious people. Despite decades at organ consoles in churches and cathedrals, I stand with Hitchens: religion is humanity's adolescent phase, something we need to outgrow. Its influence is fundamentally harmful. But when I read something like How Lisp Became God's Own Programming Language, I completely understand the reverence the author describes. There's something about Lisp – and Clojure – that creates what you can only call a transcendental response. Nothing actually transcendental happens, of course, but the feeling is real. What Lisp gives you is freedom. I've written about 'windsurfing through parentheses' before, and the metaphor sticks because it captures something essential. Most programmers are chained to the oars of enterprise slave galleys, with CTOs yelling 'RAMMING SPEED!' like that brilliant scene from Ben-Hur. Meanwhile, those of us who've found Lisp are windsurfing in circles around them, enjoying a freedom they can barely imagine. The discovery feels like Dave Bowman meeting the monolith: 'My God... it's full of stars!' That vertigo when you realise this thing's inner dimensions vastly exceed its outer ones. Lisp isn't transcendental, but it works like a star gate in both senses. The language doesn't get in your way, and it opens new ways of thinking. At the same time, it's so simple that complexity becomes manageable.
I remember that August 1979 BYTE magazine perfectly. The cover promised mysteries, the articles delivered. I couldn't wait to start implementing what they described – eventually doing it in 6502 assembler, using an assembler I'd written in BASIC. Everything clicked, even as a teenager. This was real freedom, expressed as code. Years later, I wrote HotLisp (or 'HotLips' – M.A.S.H. was huge then) for the Royal College of Music in Stockholm. It was incredibly ambitious: a full Common Lisp that treated MIDI events as first-class citizens. Looking back, I see this as the beginning of what became Igor Engraver – integrating music directly into the computational core. We used it to control our Synclavier and MIDI synths whilst teaching algorithmic composition to advanced students at the Royal Academy. The Two-Bit History article nails something important about Lisp's mystique. It traces the evolution from McCarthy's 'elegant mathematical system' through AI research, Lisp machines, and SICP's role in making it the language that 'teaches you programming's hidden secrets'. Each phase built the reputation. What the article doesn't cover is the educational betrayal that followed. Computer science departments got it right for a while – they taught Scheme as a first language because it let students focus on learning algorithms rather than wrestling with syntax. Pure freedom to think about problems. Then Java Enterprise was foisted upon the world, the departments caved in, and they started churning out galley slaves instead of computer scientists. I see this as nothing short of high treason. But here's what really matters: that freedom has evolved in Clojure. Rich Hickey didn't just bring Lisp to the JVM – he solved problems that even Common Lisp couldn't handle elegantly. Those immutable data structures aren't academic toys; they're game changers that eliminate whole categories of bugs whilst making concurrency and parallelism natural instead of terrifying. The effects ripple out: undo/redo becomes trivial, and the JVM gives genuine multi-platform reach. This isn't just improvement – it's architectural breakthrough disguised as evolution. Clojure keeps Lisp's essential quality (that feeling of discovering how programming should work) whilst solving modern problems McCarthy couldn't have anticipated. The poor souls in corporate Java shops keep rowing, occasionally granted small mercies as functional concepts trickle in – hints of the freedom they're missing. I wish they could experience what we know: programming doesn't have to feel like industrial labour. There's a way of working where ideas flow directly into code, where the language becomes transparent, where you stop fighting tools and start windsurfing through solutions. Maybe that's the point. As McCarthy noted in 1980, Lisp survives not because programmers grudgingly accept it as the best tool for each job, but because it hits 'some kind of local optimum in programming language space'. It endures even though most programmers never touch it, sustained by reports from those who've experienced its particular form of computational enlightenment. Until we can imagine God creating the world with some newer language – and I doubt that day is coming soon – Lisp isn't going anywhere. Read the full article at Two-Bit History: https://twobithistory.org/2018/10/14/lisp.html How solving a real music notation problem revealed the perfect transducer use case The Problem That Started It All I found myself confronting what appeared to be a deceptively simple requirement for Ooloi: 'Resolve slur endpoints across the musical structure'. Rather straightforward, one might assume: simply traverse the musical structure and locate where slurs terminate. But then, as so often is the case, the requirements revealed added complexity:
It became apparent that I needed a general-purpose piece traversal utility: something handling temporal coordination whilst remaining flexible enough for multiple applications. Rather than construct something bespoke (and likely regrettable), I researched the available approaches within Clojure's ecosystem. That's when I recognised this as precisely what transducers were designed for. The Architecture RecognitionAllow me to demonstrate the pattern I anticipated avoiding. Without a general traversal utility, each application would require its own approach: Three functions, identical traversal logic, different transformations. Exactly the architectural smell I wanted to avoid from the outset. This was precisely Rich Hickey's transducer insight made manifest: "What if the transformation was separate from the collection?" The Transducer RevelationWhat if I could write the temporal traversal once, then apply different transformations to it? Objective achieved: one traversal algorithm, many applications. But its architectural reach turned out to be even more profound. The Architectural InsightThe design decision hinged upon recognising that I was conflating two distinct concerns: the mechanism of traversal and the logic of transformation. This wasn't merely about avoiding the tedium of duplicated code (though that would have been reason enough) but rather about establishing clean architectural boundaries that would serve the system's long-term evolution. Consider the conceptual shift this separation enabled: Rather than thinking in terms of specific operations upon musical structures:
The transducer approach encouraged thinking in terms of composed processes:
The traversal thus became reusable infrastructure, whilst the transformation became pluggable logic. This distinction would prove invaluable as the system's requirements expanded. The Broader ApplicationsWhat I hadn't anticipated was how broadly applicable the resulting abstraction would prove. After implementing the piece-walker for attachment resolution, I discovered it elegantly supported patterns I hadn't originally considered, each demonstrating the composability that emerges naturally from separating traversal concerns: Each is built from simple, testable pieces. And they all inherit the same temporal coordination guarantee. This composability emerged naturally from the transducer design: a pleasant architectural bonus. The Performance Characteristics As one would expect from a well-designed transducer, memory usage remained constant regardless of piece size: a particularly crucial consideration when dealing with the sort of orchestral scores that might contain hundreds of thousands of musical elements. Consider the alternative approach, which would create intermediate collections at each processing step: The transducer version processes one item at a time: Same result, constant memory usage. This exemplifies what Rich meant by 'performance without compromising composability'. Demystifying Transducers Transducers suffer from an unfortunate reputation for complexity, often relegated to 'advanced topics' when they needn't be. This is particularly galling given that they're fundamentally straightforward when you encounter the right use case, which the musical domain provides in abundance. Think of transducers as 'transformation pipelines' that work with any data source, much as one might design AWS data processing workflows that operate regardless of whether the data arrives from S3 buckets, database queries, or API streams: The pipeline stays the same. The data source changes. In Ooloi: Why This Matters Beyond MusicThe piece-walker solved a universal software problem: How does one avoid duplicating traversal logic whilst maintaining performance and composability? This pattern applies everywhere:
Transducers provide the infrastructure for "traverse once, transform many ways." The Bigger PictureBuilding the piece-walker demonstrated that transducers aren't an abstract functional programming concept. They're a practical design pattern for a specific architectural problem: separating the concerns of traversal from transformation. The musical domain made this separation particularly clear because the temporal coordination requirements are so explicit. When you need the same traversal logic applied with different transformations, transducers provide the elegant answer. This separation makes code:
What's Next?The piece-walker is documented thoroughly in our Architecture Decision Record for those wanting technical details. But the real value lies not in the musical specifics but in observing how transducers address genuine architectural challenges with apparent effortlessness. The next time you find yourself contemplating similar data processing logic across multiple contexts, you might ask: 'What if the transformation was separate from the collection?' You may well recognise your own perfectly suitable transducer use case. References and Further ReadingRich Hickey's Essential Talks
Official Documentation
Educational Resources
Advanced Topics
Claude & Clojure It's no secret that I use Generative AI, specifically Claude Sonnet, to assist with the Ooloi project. I use it for writing Clojure tests TDD fashion, for generating Clojure code, for generating documentation, READMEs, architectural design documents and much more. Above all, I use Claude for exploring architectural strategies before coding even begins. It's somewhat reminiscent of pair programming in that sense: I'd never just task GenAI with generating anything I wouldn't scrutinise very carefully. This approach works very well and allows me to quickly pick up on good design patterns and best practices for Clojure. Claude & Python Overall, working with Claude on Clojure code works surprisingly well. However, this is not the case when I try to involve Claude for coding in Python, the main language I use as an AWS Solutions Architect. Generative AI struggles with creating meaningful Python tests and code – especially tests, which rarely work at all. This hampers its use as an architectural discussion partner and a TDD assistant. In fact, I've given up trying to use Generative AI for coding in Python. DifferencesI have a deep background in Common Lisp and CLOS, dating back to the 1970s. I've written Common Lisp compilers and interpreters, as many Lispers did in those days. The standard practice was to write a small kernel in assembler or C or some other low-level language, and then use it to write an optimising compiler on top of it to replace the kernel in an iterative fashion, sometimes using transformations of source code based on lambda calculus. (I still remember that paper by Guy Steele.) I see Common Lisp essentially as a big bag of good-to-haves (a really excellent one, mind you). As such, it was designed by committees over a period of decades. Clojure, on the other hand, is much tighter and rests solidly on consistently applied computer science design principles. Common Lisp is pragmatic and eclectic and thus somewhat sprawling in design. Clojure, in comparison, is smaller and much more focussed, even opinionated in nature, and for clear reasons. People attracted to Common Lisp and Clojure tend to be pretty well versed in computer science, especially Clojurians who generally have a good understanding of functional programming and immutable data structure concepts. Thus, the public code "out there" on sites like GitHub tends to be fairly advanced and of high quality. Python is an entirely different ballgame. It's one of the most commonly used languages today, and the public code base is absolutely enormous. This also means that the quality of that public code varies considerably. Also, Python is not functional at heart, and its data structures aren't immutable: side effects is the name of the game. Python programmers, though much greater in number than Clojure programmers, range from script kids to computer scientists. Thus, public Python code is much more all over the place and of varying quality. This may make it harder for a large language model to reason about. I wondered whether these differences accounted for the discrepancies in the usefulness of Claude and other LLMs as coding assistants in Clojure and Python. Asking ClaudeSo I decided to ask Claude 3.7 itself. I shared the Clojure codebase with it and asked why it thought results were so much better for Clojure than for Python. This is what it said:
It then continued, quoting the code base:
I guess this answers my question about Clojure vs Python. It's not just the functional and immutable aspects of Clojure, it's also specifying the domain stringently through design, architectural discussons, specs, and tests. The Ooloi project in particularWith all that out of the way, I then went on to describe how I use Claude as a discussion partner before code is generated, and the TDD approach I'm using where the tests of course describe the domain. Claude was almost embarrassingly enthusiastic:
I continued: "I also use Claude to create ADRs, READMEs, introductions for newcomers, Dev plans, etc. I'm quite open about this; transparency is paramount in an open-source project, and the idea is to facilitate collaborators' understanding of the Ooloi project as much as possible. This means that adherence to best practices, the use of sane architecture, abstracting away the complex stuff without compromising on performance or flexibility, etc, all are central." Claude responded:
We then went on discussing open-source strategies, tutorials and onboarding materials for contributors and much more which I'll spare you from for now. Finally, I asked it to summarise its views on Ooloi as a project:
Now, this level of enthusiasm and praise from an anthropomorphic-presenting LLM (essentially a glorified Markov chain) always makes me deeply suspicious – I'm absolutely allergic to toxic positivity, especially the kind from the USA – so I asked it "Are you sure you're not overly enthusiastic just to please me?". It replied:
I then asked Claude 3.7 to comment on my journey from Common Lisp to Clojure and on the influence from Common Lisp and CLOS on Ooloi:
And finally, I just couldn't resist asking: "What would Rich Hickey say?"
I guess that hypothetical assessment is good enough for me at this point. Still not quite sure that Claude isn't giving me a friendly reach-around, though... ;)
As I windsurf through parentheses on my holiday, reviving the spirit of Igor Engraver in the form of FrankenScore, I'm struck by a profound realisation: this is how programming should always feel. Free. Uplifting. Intellectually stimulating. A far cry from being shackled to the oars of enterprise galleys, with some middle manager shouting "ATTACK SPEED!" at bewildered code monkeys. But why should this freedom be a holiday exception? As programmers (not "developers," please!), we should be grounded in computer science thinking. We need to regularly return to these ancient founts of wisdom, like Lisp, and apply their lessons to our everyday work. Otherwise, we're just highly paid button-pushers in a digital sweatshop. Remember when computer science curricula started with Scheme? It wasn't about the language; it was about learning to think algorithmically. Then Oracle, in its infinite wisdom (read: hunger for "cannon fodder"), saw Scheme replaced by Java Enterprise. And thus began the great shitshow that's lasted for decades. Yet, for all its faults, we must tip our hats to Java for gifting us the JVM. And here's where Clojure enters, marrying Lisp's elegance with the JVM's robustness and interoperability. It's like finding out your eccentric uncle and strait-laced aunt had a brilliant love child. But thanks to the JVM, your weird uncle can now fit into the enterprise world. Diving into Clojure led me to Rich Hickey's talks. The man veers into philosophical territory faster than a Silicon Valley startup pivots to blockchain. He ponders things like what names are, and why we use them - essential musings for any first-class programmer. It reminds me of my friend Niklas Derouche, architect and coder extraordinaire, who insists you must read Derrida to be a proper architect. Because nothing says "I understand this codebase" like a healthy dose of deconstruction theory. And he is right. Make no mistake. In three weeks of holiday hacking, I've made more progress and felt more fulfilled than in months of enterprise work. It's a stark reminder of what's possible when we shed unnecessary constraints and return to first principles. So, fellow coders, I challenge you: When was the last time you felt truly free in your programming? Perhaps it's time we all took a holiday to rediscover the Lisp arts. Who knows, you might just find your programming parentheses - I mean, paradigms - shifted. P.S. If you're about to comment that 'modern' languages and frameworks are just as good, save your breath. I'd sooner believe in the tooth fairy than in the supposed superiority of JavaScript or the 'agility' of SAFe. P.P.S. If you missed the Ben Hur reference (you uncultured git), this is sprint execution according to SAFe, with the CTO watching: |
AuthorPeter Bengtson – SearchArchives
January 2026
Categories
All
|
|
|
Ooloi is a modern, open-source desktop music notation software designed to produce professional-quality engraved scores, with responsive performance even for the largest, most complex scores. The core functionality includes inputting music notation, formatting scores and their parts, and printing them. Additional features can be added as plugins, allowing for a modular and customizable user experience.
Ooloi is currently under development. No release date has been announced.
|



RSS Feed