|
'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
Yes, another technical post. But this one explains why Ooloi doesn't demand you become a programmer to use it, or learn Latin to extend it for your specific needs. The architecture matters precisely because it removes barriers rather than creating them. In Umberto Eco's The Name of the Rose, a mad monk wanders through the monastery corridors shouting 'Penitenziagite!' – corrupted Latin mixed with vernacular, incomprehensible noise that might be prophecy or might be madness. Communication fails not from lack of content, but from linguistic confusion. The message is lost in translation. Software architectures shout 'Penitenziagite!' constantly, and we've grown so accustomed to the noise that we mistake it for communication. The Language Impedance ProblemWhen you write a plugin for a system, you shouldn't need to learn the implementation language. That seems obvious, yet most software makes exactly that demand. Functional programming libraries leak monads into Java APIs. Object-oriented frameworks force functional concepts into awkward method chains. Every language boundary becomes a barrier, every abstraction a translation exercise. The pattern is familiar:
This isn't malice. It's accidental linguistic imperialism – systems that never considered the difference between internal precision and external accessibility. The Monastic PatternMedieval monasteries preserved knowledge in Latin – a dead language, deliberately removed from common speech, chosen for precision and permanence. Yet they didn't demand everyone learn Latin to benefit from monastery medicine or improved agriculture. The knowledge stayed pure in the centre; the benefits propagated outward in the vernacular. Ooloi follows this pattern. The core is written in Clojure. This isn't negotiable, because the hard problems in music notation software require immutability, structural sharing, and proper concurrency. Functional programming isn't a preference; it's the only approach that doesn't collapse under its own compromises. But plugins can be written in Java, Kotlin, Scala, or any JVM language. Not as second-class extensions with limited capabilities, but as first-class citizens with full API access, equal performance, and no artificial limitations. The JVM interop means there's no penalty for crossing the boundary – your Java plugin operates with the same guarantees as code written in Clojure. This arrangement has three parts: I: The Scriptorium (Clojure core) – Where the hard problems are solved with uncompromising discipline. Immutable data structures provide structural sharing. Temporal coordination via the timewalker ensures correct musical semantics. STM enables proper concurrent editing. Zero-allocation hot paths ensure performance. This is where craft is mandatory, not aspirational. II: The Library (canonical plugins in Clojure) – Reference implementations showing how the architecture should be used. Teaching by example, maintaining standards, preserving patterns for others to study. III: The Gate (JVM plugin system) – The boundary that speaks idiomatically in every JVM language. Immutability guarantees propagate transparently. Plugin developers work naturally in their chosen language whilst benefiting from the rigorous core. Why This Structure WorksThe core cannot compromise. If mutability seeps in, if temporal coordination is abandoned for convenience, the whole thesis fails. The hard problems must be solved correctly, once, in the protected centre. But the perimeter cannot be closed. If only Clojure developers can extend Ooloi, adoption remains limited to those willing to learn functional programming. The architectural advantages – provable speedup on reflow operations, proper concurrent editing, elimination of state-corruption bugs – must be accessible without requiring conversion. This isn't architectural fussiness. It's the difference between a system that proves functional programming solves these problems and one that merely claims it whilst forcing everyone through the same narrow gate. Consider the alternative: most cross-language projects either compromise the core's purity to make external access easier, or maintain purity whilst making extension nearly impossible. Both approaches fail – the first produces unreliable systems, the second produces unused ones. First-Class CitizenshipWhen I say plugins are first-class citizens, I mean it precisely:
Your Java plugin implementing custom layout rules operates with the same capabilities as Clojure core code. The boundary is invisible – just clean interfaces and reliable contracts. No Penitenziagite Here Ooloi's architecture refuses the mad monk's cry. No demand that you learn Clojure to participate. No leaked functional programming concepts in the public API. No linguistic imperialism masquerading as technical necessity. The core speaks Clojure because that's the right tool for solving these problems correctly. The plugin system speaks your language because that's the right way to enable participation. Each side of the boundary uses the language appropriate to its purpose. This is architectural empathy: not compromise, but proper boundary design. The scriptorium can maintain Latin for precision whilst the gate speaks the vernacular. Work continues: the monastery's standards hold. The architecture neither shouts incomprehensibly nor demands conversion. There's no Inquisition burning engraving monks at the stake. The point isn't piety; it's architecture that stays intelligible. Just clarity, properly structured. – William of Baskerville There are days in Ooloi’s development when I feel like the Donald. Not that Donald. Donald Knuth. There's something very real to that comparison, even though it can be seen as presumptuous. Why do I compare myself with a computing giant? Knuth faced typesetting systems that were brittle, ad hoc, and incapable of scaling to real demands. He didn’t patch; he rebuilt the foundations. Out came deterministic algorithms, the box–glue model, and a system that still sets type decades later. I’m in a similar place. Music notation software has been compromised for forty years: mutable object graphs, procedural hacks, import/export traps. It works until you open Eine Alpensinfonie or Lontano – then it collapses. So Ooloi is built the way TeX was:
And even a year isn’t slow, considering what's been implemented in that time. In Clojure, as in Lisps generally, progress is faster, not slower, because the language doesn’t get in the way. Architectural changes that would take months in procedural or OO systems collapse into days when immutability is the default. In Lisps I feel unrestricted from the usual … bullshit. Durability and Time HorizonsKnuth didn’t set out to make a fashionable typesetter. He built TeX so mathematicians could publish without degradation, and so his own books could be set correctly fifty years later. The result is software still alive in 2025. That perspective matters. Most software is written to meet the next deadline or release cycle, and dies within five years. Architecture shaped by durability instead of expedience looks very different. It avoids local hacks in favour of structural clarity. It makes changes faster, not slower, because the invariants hold. Ooloi is built on the same horizon. It’s not about matching today’s competitors feature for feature; it’s about whether the system can handle repertoire and practices that will still be with us in fifty years. Knuth wasn't out to childishly 'disrupt' anything. Neither am I. And for the same reasons. Outlasting FashionTeX has been called unfriendly, arcane, even ugly. But it outlasted beautiful GUIs because its correctness was deeper than its interface. It solved the right problem once, and has been binding books and journals ever since.
Ooloi certainly won’t look like TeX. It will be graphical, collaborative, and real-time, and it will have a slick, modern GUI. But it follows the same ethic: stop patching, stop pretending, build a system that doesn’t collapse under its own compromises. That’s the point of the parallel. Knuth showed what software can be when it’s built for durability rather than fashion. That’s the road Ooloi is on. 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 Musical scores are full of repetition. In a symphony, middle C can appear thousands of times, quarter notes dominate, and the same staccato mark is scattered across every instrument. Most notation software allocates a separate object for each of these occurrences. That means thousands of identical objects, all taking memory and I/O bandwidth for no reason. Ooloi doesn't. With ADR-0029, we have implemented selective hash-consing: identical immutable musical objects are represented by the same instance. The same C4, the same staccato, the same quarter note: one object, shared system-wide. Why "Selective"?Not everything benefits. A forte marking may appear only a handful of times; a slur always connects specific endpoints. Caching those adds overhead without real gain. So the system targets high-frequency cases (pitches, rests, chords, common articulations) and ignores the rest. What this changes
All of this is transparent. Musicians won't 'use' hash-consing; they'll just notice that large works open, scroll, and save without drama. Why it works here In mutable architectures, shared objects are a trap: one stray modification contaminates every reference. Defensive copying and locks erase any performance benefit. In Ooloi, immutability is the rule. Sharing is safe. No copies, no locks, no bugs.
This isn't the kind of feature that makes a demo screenshot. It's one of the architectural foundations that decides whether the system will still perform when you open Mahler's 8th or La terre est une homme. It took days to implement. That's the difference Clojure makes. Finishing the statistics infrastructure naturally led to thinking about the next architectural milestone: the rendering pipeline. This is the mechanism that determines what happens when someone clicks into a score to add a note, and how that change propagates through the system. The design is complete. That in itself is an important milestone, as this is the very foundation on which Ooloi's performance ultimately depends. Everything hinges upon it. Why a Pipeline? Traditional notation software recalculates entire scores when a single element changes. Dense passages in works like Strauss's Elektra bring systems to a halt because every operation is sequential and single-threaded. The reason for this is that parallelism is very difficult to do with mutable state, which is the traditional approach. Scalability often becomes an issue, with diminishing returns as a result. Ooloi takes the opposite approach and chooses the Clojure way instead, with immutable state. With this, it is comparatively easy to distribute formatting work across all available CPU cores and use them fully and linearly. Every user action – whether adding a single note or adjusting spacing – thus becomes part of a coordinated cascade where each stage can run in true parallel across all available cores. The goal is straightforward: responsive editing even in the heaviest repertoire. Five StagesADR-0028 specifies the pipeline in five stages, separating connecting from non-connecting elements and applying a clear fan-out/fan-in pattern.
This separation allows Ooloi to exploit parallelism where possible and enforce order where necessary. Plugins as First-Class Citizens Formatting in Ooloi is plugin-driven. Core elements such as notes and beams are implemented through the same interfaces available to extensions. Plugins can participate in different stages depending on their needs:
Simple articulations may use only the first two; beams may require all three. This uniform model ensures extensibility without compromising performance. Convergence by DiscomfortThe optimisation engine measures deviation from ideal proportions across measures, systems, and pages. Improvements multiply: small gains in multiple places compound into significant overall reductions. Hard constraints such as manual breaks provide natural stopping points. This replaces arbitrary iteration limits with a principled measure of quality. Parallelism and Responsiveness Claypoole provides efficient thread-pool execution, delivering significant speed-ups over built-in Clojure parallelism. STM transactions keep operations atomic while allowing concurrency inside each stage. Cooperative cancellation ensures that rapid user input remains responsive. The system treats a single user as a 'collaboration network of one'. The same infrastructure that supports multi-user editing ensures smooth interaction for individuals. Where This Leads This pipeline is the structural core that should make scrolling through Elektra or Ligeti's Requiem as fluid as editing a Gnossienne by Satie. The specification is complete. Implementation begins as soon as the current phase closes. Ooloi's promise of responsive, professional-scale notation depends on it. Scary stuff. Full specification: ADR-0028: Hierarchical Rendering Pipeline with Plugin-Based Formatters
Every community has its breaking point. Mine came on Clojurians when I wrote a single sentence: 'Clj-kondo can go away – I have 18,000 tests'. That was enough to get my post deleted. Before the deletion, there was 'discussion' – if you can call it that. I was told my statement was nothing more than click bait. The irony? The author of clj-kondo himself agreed with me. What That Line Meant It wasn't click bait. It was a statement of principle:
And I was careful to make the distinction explicit: clj-kondo is a beloved, useful tool. For most projects it adds value. It just happens to be of limited use in my project, because Ooloi's architecture is already validated at a different scale. That nuance – acknowledging the tool's value whilst drawing boundaries around its relevance – should have been the beginning of a sober technical discussion. Instead, it was treated as provocation. The fairness itself was read as heresy. The Culture Clash The moderator (a 'Veteran Architect') didn't engage with the point. He reacted from the gut: pearl-clutching, dismissing, and finally deleting. Exactly the kind of gatekeeping I dissected in my article on functional programming gatekeeping. And let me be clear: I have nothing against the Clojurians themselves. They're a knowledgeable, interested lot, often deeply engaged in technical detail. The problem isn't the community – it's the moderation culture. The moderators behave more like a church council than facilitators of discussion. Their first instinct isn't to sharpen an argument, but to protect orthodoxy, maintain decorum, and suppress anything unsettling. The ideal they enforce seems to be some kind of cold, robotic detachment – the lab-coat fantasy of neutrality – or perhaps the modern American obsession with never offending anyone, no matter how bloodless the discourse becomes. Either way, it enforces sterility, not clarity. You can critique syntax sugar all day long, but question a community darling like clj-kondo – even whilst calling it useful and respected – and suddenly you're accused of trolling. Why I Left I didn't leave because I was offended. I left because I refuse to participate in a space allergic to honesty. If a community sees a blunt critique and immediately cries click bait – ignoring both the nuance of my post and the fact that the tool's own author agreed – it has no business in my world. Ooloi is built on clarity, not ceremony. It's an architecture tested by 18,000 executable truths, not validated by a linter's opinion. If that treads on toes, good. Prissy people afraid of dark humour or communication nuances that wouldn't pass muster at a parish council don't belong in this project. And the same thing goes for hypocrites who say, 'We're inclusive here - as long as you're exactly like us'. The Broader Lesson Communities often confuse politeness for health. But real progress requires the courage to tolerate discomfort. If you need your software conversations padded with pillows, you'll never survive the weight of real architecture. As Wednesday Addams would remind us: hypocrisy is uglier than bluntness, and dishonesty is far more offensive than a glass of gin before noon. Or, indeed, a well-placed 'fuck you'. So I deleted my Clojurians account. Because sometimes subtraction is progress. After a year building the backend of Ooloi with Claude, I’ve learned this:
Successful AI collaboration isn’t about creative freedom. It’s about harsh constraint. AI will overstep. Your job is to correct it—immediately, uncompromisingly. The friction isn’t failure. It’s the method. Read the full piece – which I asked the AI to write in its own voice – here. I've been saying I'm itching to open source Ooloi, but waiting for the complete software felt increasingly artificial. The documentation tells the real story – twenty-five years of architectural evolution from Igor Engraver through AWS systems thinking to this closure in Clojure.
So here it is: the complete Ooloi documentation collection, released publicly ahead of the software itself. What you'll find:
This represents my attempt to walk the talk after critiquing FP drawbridge syndrome. These guides serve dual purpose: they document sophisticated music notation architecture whilst teaching functional programming concepts through examples that actually matter. The timewalker guide alone demonstrates transducers, lazy sequences, and functional composition through orchestral score traversal. The polymorphic API guide teaches multimethods through musical type systems. The concurrency patterns show STM coordination through collaborative editing. Twenty-five years of thinking, distilled into something that I hope proves useful beyond music software. The architecture is complete; the foundations are solid. Now you can see why I've been eager to share this work. An organism evolved, indeed. Explore the complete documentation: https://github.com/PeterBengtson/Ooloi-docs /Peter Now that the backend engine is complete, architecturally speaking, I'm getting increasingly eager to open the source. Itching, in fact. But as that will take a while, the least I can do for you is give you the WELCOME.md file from the source repo. / Peter Welcome to OoloiGreetings, and welcome to Ooloi, the spiritual successor to Igor Engraver. If you're seeking yet another conventional music notation software, I'm afraid you've taken a wrong turn. Ooloi aims to be something rather different — and there's a story behind why that matters.
A Quarter-Century in the Making Twenty-five years ago, I created Igor Engraver, which became rather successful in the music notation world. When that project ended, it left something unfinished – not just the software, but the understanding of what music notation software could truly become. Ooloi represents the completion of that circle, built with decades of accumulated insight about both music and programming. In the intervening years, I became an AWS Solutions Architect Professional and created systems like Ocean and OpenSecOps. I have always thought in systems — this shift simply allowed me to give that instinct full rein, to focus entirely on designing foundations that can handle complexity and scale over time through elegant abstraction layers. I've spent the better part of a year on Ooloi distilling everything I've learned into an architecture that doesn't just work, but works elegantly. This isn't my first attempt at solving these problems, but it's the first time I've had the right tools – functional programming, immutable data structures, enterprise-scale systems thinking, and the kind of patience that comes with experience – to solve them properly. What is Ooloi? Ooloi is open-source music notation software, designed from the ground up to handle complex musical scores with both finesse and power. Built in Clojure, it represents a fundamental rethinking of how music software should work. What makes it different:
Why Ooloi Matters The world of music notation software has been rather stagnant for too long, content with incremental updates and feature bloat. Most existing software suffers from fundamental architectural problems that can't be fixed with patches – they require starting over with better foundations. Ooloi solves problems that have plagued music software for decades: proper temporal synchronization, efficient collaborative editing, memory-efficient handling of large scores, and clean extensibility. These aren't just nice features – they're qualitatively different capabilities enabled by choosing the right abstractions. The Architecture You'll Inherit What you'll find here is the result of taking time to get the abstractions right. The backend is conceptually complete, with over 15,000 tests proving it works correctly. The temporal coordination system, the pure tree data structures, the STM-based concurrency – these represent solutions to genuinely hard problems. But here's the thing: good architecture should be invisible to those who use it. The complexity is handled for you, hidden behind interfaces that make difficult things simple. You can focus on the problems you want to solve – whether that's creating plugins, improving the user interface, or adding new musical capabilities. How You Can Contribute If you're here, you probably have an interest in music, programming, or ideally both. Here's how you can be part of this:
Getting Started
What You're Joining This isn't just another open-source project. It's the culmination of decades of understanding what music notation software needs to be, combined with the architectural discipline to build it right. You're joining something that's designed to outlast its creator, to enable work that hasn't been imagined yet, to solve problems that matter to musicians and developers alike. The foundations are solid; now we build the future on top of them. The architecture is complete, but the work is just beginning. There are plugins to write, interfaces to design, capabilities to add. Most importantly, there are problems to solve that only emerge when you put powerful tools in the hands of creative people. A Personal Note At 64, carrying more than five decades of programming experience and a parallel career as a composer, I've tried to encode into this architecture not just technical solutions, but the aesthetic judgments and performance intuitions that come from actually making music. The creative energy that might have gone into another opera has found expression in software architecture. It's a different kind of composition – one that enables other people's creative work rather than expressing my own. In many ways, it's more satisfying. This is what happens when you take the time to get it right, when you resist the urge to rush, when you're willing to solve the hard problems properly. The result is something that can grow and evolve through the contributions of others while maintaining its essential character. Now, let's make some music. On all levels. / Peter Bengtson 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
I recently spotted a meme on LinkedIn featuring a brooding, aristocratic Dracula asking, "What is a monad but a monoid in the category of endofunctors?" – accompanied by no explanation whatsoever. I chuckled, as one does when recognising an in-joke, but then found myself pondering a rather uncomfortable question: Is this really how we want to present functional programming to the world? The Allure of the Arcane There's something undeniably satisfying about mastering difficult concepts. When I first grasped the elegant power of immutable data structures, higher-order functions, and composability, it felt like discovering a secret door in a familiar house – one that led to a vast, beautiful landscape I'd never known existed. That eureka moment is profound, even transformative. But here's the rub: why do we in the functional programming community so often present that door as if it requires an arcane ritual to unlock? Why do we seem to relish the impenetrability of our terminology? Let's be honest with ourselves. There's a whiff of intellectual snobbery in the air when functional programmers gather. We've all heard (or perhaps even made) the disparaging remarks about "Java drones" or "code monkeys churning out mutable state on corporate slave galleys". We swap stories about the moment we "finally understood monads" as if recounting our initiation into a secret society. We wear our hard-won knowledge as a badge of honour – and sometimes, if we're being truly honest, as a mark of superiority. The Hidden Cost of Exclusivity This exclusivity comes at a cost. Functional programming remains woefully underutilised in the industry at large, despite offering compelling solutions to many of the problems that plague software development. Concurrency, side effect management, robust testing, code reuse – these aren't niche concerns, they're central challenges in modern software engineering. Yet we've somehow managed to position our toolbox of solutions as if it's too rarified for everyday use. Consider the meme I mentioned. For the initiated, it's a humorous reference to a famously opaque definition. For everyone else, it's not just impenetrable – it actively signals that they don't belong in the conversation. It's a velvet rope strung across the entrance to a club they didn't even know they might want to join. I'm reminded of my journey from Common Lisp to Clojure. Both languages offer powerful functional paradigms, but Clojure has managed to achieve something remarkable: it has brought functional programming concepts to a significantly wider audience. It didn't accomplish this by watering down the functional paradigm, but by emphasising practicality alongside purity. By meeting developers where they are – on the JVM, with access to the libraries and tools they already know – Clojure created an on-ramp rather than a barrier. No Monads Required Here's something we don't acknowledge often enough: you don't actually need to understand monads to be a productive functional programmer. In fact, in languages like Clojure, you can write elegant, powerful functional code for years without ever encountering the term. The core principles of functional programming – immutability, pure functions, higher-order functions, composability – can be understood through practical examples without diving into category theory. This isn't to say that the deeper theory isn't valuable. Of course it is! The mathematical foundations of functional programming provide extraordinary insight and power. But they're not the entrance exam. They're advanced courses you can take once you're already enrolled. Yet somehow, we've allowed the most theoretically complex aspects of functional programming to become its public face. It's as if we're advertising a car based on its differential equations rather than where it can take you. The False Dichotomy There's an insidious implication lurking beneath this state of affairs: the notion that there are two classes of programmers – the enlightened few who grasp the elegant abstractions of functional programming, and the unwashed masses writing imperative code. This is, to put it bluntly, utter bollocks. The reality is far more nuanced. Most programmers exist on a spectrum of understanding and application of functional principles. Many Java developers make excellent use of streams and lambdas. JavaScript programmers increasingly embrace immutability and pure functions. Even in traditionally imperative contexts, functional patterns are gaining traction. These aren't "lesser" applications of functional programming – they're pragmatic adaptations that solve real problems. The senior developer who introduces Option types to avoid null pointer exceptions in a legacy Java codebase is applying functional thinking in a way that delivers immediate, tangible benefits. Should we really consider them less enlightened than someone who can recite the monad laws but has never shipped a product? Building Bridges, Not Walls If we truly believe in the benefits of functional programming – and I certainly do – then we should be building bridges to make these ideas more accessible, not walls to keep the uninitiated out. What might this look like in practice? For starters, we could focus our evangelical efforts on the practical benefits rather than the theoretical foundations. When I'm talking to a team about adopting Clojure or functional patterns, I don't open with category theory. I talk about dramatically reduced bug rates due to immutability. I show how composable functions lead to more reusable code. I demonstrate how side effect isolation makes testing simpler and more reliable. And to really wow them, I might describe how immutable data structures instantly solve the Undo/Redo problem for any application with a frontend. We could also acknowledge that functional programming isn't an all-or-nothing proposition. Encouraging teams to adopt functional patterns incrementally within their existing codebases can yield substantial benefits and build confidence for deeper adoption. The choice isn't between pure Haskell and imperative spaghetti code – there's a vast, productive middle ground. Most importantly, we need to shift our community culture away from exclusivity and toward inclusivity. This doesn't mean abandoning rigour or depth – it means recognising that everyone starts somewhere, and the journey from imperative to functional thinking is challenging enough without adding artificial barriers. The Clojure Case Study It's worth examining why Clojure has been relatively successful in attracting developers who might otherwise have been put off by functional programming's reputation for difficulty. Firstly, Clojure is pragmatic to its core. It embraces functional principles without dogmatism, allowing for controlled mutability when necessary. It prioritises solving real problems over theoretical purity. Secondly, it meets developers where they are. By running on the JVM (and later JavaScript engines), it allows gradual adoption and interoperability with existing systems. Thirdly, and perhaps most importantly, the Clojure community has generally focused on what the language enables rather than how clever you need to be to use it. The emphasis has been on what you can build, not on arcane knowledge as a status marker. This approach hasn't compromised the language's functional credentials – Clojure remains thoroughly functional in its philosophy and implementation. But it has made those functional principles accessible to a much wider audience. A More Welcoming Future I'd like to see a functional programming community that celebrates bringing new people in rather than keeping them out. One that takes as much pride in making complex concepts accessible as it does in mastering them. Imagine if our response to someone struggling with functional concepts wasn't "Well, once you understand monads..." but rather "Here's how this approach solved a similar problem I had..." Imagine if we shared our enthusiasm not through insider references that exclude the uninitiated, but through concrete examples that demonstrate the real-world power of functional approaches. Imagine if we recognised that the true measure of our understanding isn't our ability to recite category theory, but our ability to apply these principles to build better software and help others do the same. As I continue to develop Ooloi, my open-source music notation project in Clojure, I'm constantly reminded of this tension. The functional paradigm allows me to build a system that's both powerful and elegant. The code is concise, composable, and expressive in ways that would be difficult to achieve with imperative approaches. But when I'm documenting the system or preparing it for open-source collaboration, I'm mindful of the need to make these concepts accessible. The goal isn't to water down the functional aspects – they're essential to the system's design. Rather, it's to provide on-ramps that allow developers to engage with these ideas gradually, to see their practical benefits before diving into the deeper theory. Conclusion Functional programming isn't a secret to be jealously guarded – it's a powerful set of tools that can dramatically improve how we build software. Its core insights deserve to be widely shared and applied. So the next time you're tempted to share that monad joke or category theory reference, ask yourself: Am I opening a door or closing one? Am I inviting others to share in something valuable, or am I simply signalling my own cleverness? We don't need gatekeepers in the functional programming community. We need guides. Guides who remember what it was like not to know, who can explain complex concepts in accessible terms, who take pride not in how exclusive their knowledge is but in how effectively they can share it. After all, what is a community but a group of people helping each other grow? |
AuthorPeter Bengtson – SearchArchives
November 2025
Categories
All
|
|
|
Ooloi is a modern, open-source music notation software designed to handle complex musical scores with ease. It is designed to be a flexible and powerful music notation software tool providing professional, high-quality results. 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.
|







RSS Feed