Meta Redux: Sayid 0.8

Wait 5 sec.

Sayid 0.8 is out! It’s the third release since Ibrought Sayid back from the deada couple of weeks ago, and it has a clear theme: making the tool easy to pickup. The revival releases were mostly about the engine - bounding the recording,consolidating the API, getting the data out. This one is about the experience.If you’ve ever bounced off Sayid because you couldn’t figure out what to press,or what it was trying to tell you, 0.8 is for you.It started with a bug reportShortly after the revival post, someone reported that pressing c i in theworkspace view - “inspect this captured value” - printed Def'd as $s/* andthen… nothing. The fix turned out to be a one-liner: Sayid was calling aCIDER function whose signature changed years ago, and nobody had noticed since.Which tells you everything about how many people were actually using thatcommand.1The one-liner was easy, but the report got under my skin. If the inspectorintegration could sit broken for years, what else about Sayid was quietlyhostile to anyone trying it for the first time? So I sat down and did a properUX audit of the Emacs client, wrote down everything that made me wince, and 0.8is the result.Here’s the current state of affairs in one take - trace, run, explore:Catching up: 0.6 and 0.7Before we get to the UX work, a quick recap of the two releases I never gotaround to announcing (the revival post covered things up to 0.5).Sayid 0.6 rebuilt inner tracing - the mode that records everyintermediate expression inside a function - on top of tools.analyzer.jvm.The old implementation re-read your source and rewrote raw forms, with specialcases for individual macros; the new one works off the analyzed AST. Thatkilled the long-standing bug where an inner-traced try/catch would swallowexceptions, along with the per-macro special-casing that made the oldinstrumenter so fragile.Sayid 0.7 made the trace itself data. sayid.data/trace-datareturns the recorded call tree as plain Clojure data with the live capturedvalues, and tap-trace! sends it to tap>, so you can explore a recording inPortal or your data tool of choice. It also added sayid.golden - capturea run’s call tree as a baseline, then assert future runs still match it, whichis a surprisingly pleasant way to pin down the behavior of gnarly legacy codebefore refactoring it.The highlightsNow, the 0.8 goodies. The full list is in the changelog, but here’s what I’mmost excited about: There’s a proper entry point now: C-c s pops up a transient menu(sayid-menu) that groups the commands along Sayid’s core loop - tracesomething, run your code, explore the recording - and shows you how much istraced and recorded right now, or what’s missing (a REPL, the middleware) whenyou’re not connected. The menu uses the same key sequences as the classicprefix map, so your muscle memory keeps working, and sayid-use-menu bringsthe plain keymap back if popups aren’t your thing. sayid-trace-fn (C-c s t t) is the new “just trace this” command. You nolonger need to know what inner and outer traces are before you can trace yourfirst function - the default does the right thing, and you can graduate tothe fancier variants later. Empty views teach instead of scolding. Opening the workspace before anythingwas recorded used to greet you with an error; now you get the buffer anyway,with a short walkthrough of how to get data into it. The first five minuteswith Sayid should no longer require reading the manual. The commands talk back like a human. Tracing a function now tells you whathappened and what to do next (“Outer-traced acme.checkout/subtotal - run somecode, then C-c s w shows what was recorded”), and trying to enable a tracethat doesn’t exist tells you the actual problem instead of pretendingeverything went fine. The workspace tree is now the one view to rule them all: on any call you caninspect a captured value in CIDER’s inspector (c i - yes, it works now),def it to a var for REPL poking (c d), pretty-print it (c p), or copy anexpression that reproduces the call (c r). C-c s f - show the recordedcalls of the form at point - renders there too. A pile of small courtesies that add up: tracing a function no longer stealsyour window with a popup, g refreshes the Sayid buffers like every otherEmacs buffer, and resetting the workspace asks before irreversibly droppingyour traces and recording. The client and the middleware now tolerate version skew - if your deps.ednpins an older Sayid jar than your Emacs package expects, things degradepolitely instead of erroring in strange ways. The Emacs client now requires CIDER 2.0, which let me drop a bunch ofcompatibility shims and lean on the new cider-tree-view throughout. And the README finally shows the tool instead of just describing it -screenshots and the GIF above included. A picture of a call tree is worth athousand words about one.Upgrading notesNothing here should break a working setup, but two things are worth knowing.The Emacs package now requires CIDER 2.0 (released earlier this week), sothey’ll need to be upgraded together. And C-c s now opens the menu instead ofacting as a bare prefix - every old key sequence still works exactly as typed,but if you prefer the old silent prefix, set sayid-use-menu to nil. A fewcommands got more consistent names (sayid-trace-fn-outer and friends); theold names live on as obsolete aliases.OnwardWhen I wrote the revival post I asked people to kick the tyres and tell me whatfeels rough. This release is what acting on that feedback looks like, and it’sexactly the kind of contribution I need more of - a two-line bug report turnedinto the biggest usability overhaul in the project’s history. So thanks toeveryone who has been trying out the revived Sayid, and please keep the reportscoming on the issue tracker.[mx.cider/sayid "0.8.0"] is on Clojars, the Emacs package is on MELPA, andtracing your first function is now a single C-c s t t away. Give it a spin!Keep hacking! In fairness, it also tells you something about me - the bug shipped withmy own resurrection releases. Reviving a decade-old codebase meansinheriting a decade of API drift, and some of it only surfaces when a realuser presses a real key. ↩