Feedback after making a very large notebook

I used Observable to build a board game engine and I’d be surprised if it’s not one of the largest notebooks anyone has made. At some point soon I’m going to start migrating to a more traditional JS IDE (slowly, for reasons we’ll see) but meanwhile I had a lot of fun and learned a lot along the way. Thanks for making this cool product!

First I want to highlight the delightful, unique advantages of Observable I have at best rarely seen in any other environment:

  • Completely reorderable cells make development very nice. Group together an “active set” and have everything you need on one page where other environments would have you toggling between different files.
  • Viewofs and Mutables make complicated listener wiring a breeze and are, to my mind, hallmarks of Observable. The tutorial custom view,, is particularly useful, and exposes their innards enough to make them and observable notebooks in general much easier to manage. Setting up this wiring in almost any other framework I’ve used is difficult, buggy and hard to refactor Observable makes prototyping complex coordinated cells a pleasure, and I’m sure I’ll use it in the future to prototype dashboards and visualizations that require that.
  • The autosave function is immaculate, and the convenience of working on notebooks on any computer I happened to have available made me develop a much more ambitious project than I might have otherwise (though I did not make any tweaks on mobile).
  • All of this makes it great, already, for prototyping below a certain scale.

Unfortunately there’s a variety of problems related specifically to a large notebook:

  • No way to search collapsed cells. At a certain point I gave up and expanded everything.
  • Moving cells around one at a time is a major pain. It should be possible to select multiple cells, cut and paste them, and also manage them in a collapsible hierarchy (based on markdown headers seems like a nice way).
  • No version control beyond forking. There’s other threads that express this better but let me add my voice: this is an urgently needed feature for anything above tiny scale.
  • Errors lack necessary detail, especially in large cells with functions defined within a block the error can appear only where the function is called not where it actually happens. Just logging stacktraces to console or cell output would be nice, even if it’s hard to represent them better in the notebook.

Even though I’ve reached a scale at which I need to migrate it’s difficult to do so:

  • Mutable and Viewof and anything not in the stdlib, and finally the reactive setting in general, have no straightforward translation to settings outside observable. That is, to replicate my notebook in pure JS I’ll have to carefully add a bunch of eventlisteners in just the right way.
  • Even if I’m only interested in working in observable, refactoring mutables and observers so a notebook can be made presentable or useful exportable cells created can be difficult. At one point to run the tic tac toe game above required a total of a dozen cells with mutables, viewofs, or functions that nontrivially relied on them. I condensed it to four with a moderate effort, but to improve on that probably means manual eventlistener wiring.
  • I wish mutables could be passed as arguments to functions. It would be a little bit like having a templated cell with a mutable. I think observable cell templates have a lot of potential too, but that’s more of a feature request.
  • On top of this refactoring I’ll have to write a script or do a bunch of manual copy-pasting to even get the raw text I wrote out. I’d be grateful for even a very dumb export feature that produced my cells in the partial order of the reactivity graph. I know export code is another topic, but give us other options than just external runtime? (git would solve this)

Straightforward bugs:

  • alt+cmd+up moves the window to keep the cell in view, alt+cmd+down does not.
  • Output cells were occasionally misaligned, so they’d be partially cut off. Tended to fix itself eventually including by window resize, but more persistent than just rerunning cells.

Miscellaneous issues without recommendations:

  • Observable is almost underopinionated on async methods. There’s a dozen ways to do anything. I mostly skirted this by sticking to mutable and then viewof if that had issues, but there’s a whole zoo of ways I could have handled inputs, and I’m also sure my mutable usage was suboptimal.
  • Narrow (~900px) center notebook column is very constraining.
  • I like mutables by I did at one point get very confused because my underlying model depended on a mutable and I didn’t realize it and I kept finding my state reset when I re-ran the cell even though it wouldn’t when the value was changed. I factored it out.

Miscellaneous features requests:

  • Notebook-wide find and replace! The fundamental basis of refactoring!
  • Jump-to-definition. Especially useful when cell=def.
  • Pin any or several cells or a copy of its output to a floating panel (Other topic has mentioned it).
  • When a cell has an error show it’s last valid name/title (in red or pink?) to indicate it’s no longer valid without making it harder to search for.
  • UnitTest cell type with assertions, show red or green depending on passing or failing.
  • Move main notebook column to right with left-hand side navigation and workbench. Ties in with cell hierarchy.
  • Make it easy to navigate to cells with errors, maybe a text fingerprint (a la sublime) with red highlights, or a side popup?
  • Expose dependency graph, both in aggregate and in cell-centric views. (e.g. highlight on edges to/from chosen cell). Addressed in another Topic.
  • Super rerun to simulate notebook refresh. Especially useful for notebooks with “this” and other subtle state-ish stuff.
  • Collapse All/Expand all/Collapse all that aren’t pinned toggling.

Wow, excellent and super useful feedback - thank you Jacob!

Just filed a bunch of issues to cover the parts of this we aren’t already working on. A few folks have asked about testing, and I’ve thought that should be doable in userspace but haven’t done it, so I took the time to do it:

This notebook uses the excellent tape module and adds just enough wiring to add cell output.