July 14, 2007

Raindrops from a brainstorm

Every now and then, I have a really good idea, something that I think would shake up the authoring/editing community and add simple, useful capabilities we've never seen before. Basically, I run into a problem when I'm working on code, and I come up with a solution... but I just don't have the time to prototype it, implement it, and see how it works out. I figured today that I might as well throw a few of these ideas out for the community to chew on.

UPDATE: I forgot to mention - if anyone wants to implement these ideas, go right ahead. :-) I'm posting them because I don't have time to do them myself right now.

I'd like to see what the Mozilla community - and the authoring / editing tools community at large - think. The ideas I'm sharing now are in the extended entry.

Interpreted files through a preprocessor

Problem: When working on chrome files or component files, often the object directory file is an exact copy of a source file. In cases like this, the operating system can create a symbolic link, or "symlink", between the two. However, for files that go through a preprocessor, where other files can be included, or sections of the source file dropped, it's not an option. Despite this, the source file and the object file aren't that different. Sections of one match up with sections in the other.

More specifically, when I get a stack trace from a JavaScript file that's been preprocessed, the JS source lines rarely line up to the object source line numbers.

Solution: Create an annotation (either in the files or outside them) which links sections of source files to corresponding sections of object files. I call this concept a "sub-symlink". (I don't know if anyone else has come up with the idea.) A smart editing program can read these sub-symlinks, and when you edit a section of code in the source file, it can update the corresponding section in the object file. Even better, if I want to edit the object directory file (which for XUL, JavaScript, CSS, etc., don't need to be compiled), then the changes can reflect in the source directory file right away, and I don't have to call make on the object directory again. The smart editor becomes responsible for propagating the change, including to multiple object directories based on a single source directory if the user so desires.

Experimental change sets

Problem: Whenever I go into debugging mode, trying to fix an error, I'll try a bunch of different things. Usually, three or four different approaches don't work. Unfortunately for me, I tend to forget when I've tried an approach - so I end up trying it again thirty minutes later. On the other hand, I'll also tend to forget what changes I've made, so if I end up taking a path that can't work, I want to go back to a set of changes which are better than the original state of affairs.

Solution: Use a revision control system instead of the ordinary file system for storing changes - and when saving a file, export from the VCS to the file system. By this, I don't mean "check changes into the remote repository and see if they work" - rather "check changes into a local repository, which has its own version tracking separate from the remote repository. Then see if the local changes work."

This also has the benefit of permitting comments for each change set, so that I can annotate what I'm trying to do. You could also store all kinds of metadata (including annotations for sub-symlinks!) in the repository. Additionally, undo/redo takes on a whole new meaning - tree-based instead of linear. Just creating the user-interface for that should be interesting.

Subversion could work for this (especially if the editor has access to svnadmin and is very careful about how it interacts with Subversion). However, a distributed revision control system such as Mercurial would work even better, since you have a local copy of the full repository already, and full rights to commit to your local repository without affecting the primary one.

(I didn't understand this at all - what a distributed RCS does better than a centralized RCS, until I read this sentence from the unofficial Mercurial book: "What distributed tools do with respect to forking is they make forking the only way to develop a project." To track a series of change sets while keeping those change sets from reaching the central repository, you essentially have to create a forked copy of the repository - even if it only lives for a few hours. So, a local repository can hold unstable, not-ready-for-bug-attachment changes - and the editor can interact with the local repository.)

The downside is that your project then becomes beholden to the license of the revision control system. This can present real problems, when you want other neat capabilities from open-source projects with incompatible licenses. This is one of those cases where the LGPL is more useful than the GPL...

Distributed editing and reviewing

Problem: For all the strengths Bugzilla has, it's really hard to make a change to a patch. What happens is the reviewer says "Do this instead of what you're doing here. r+ with that change." Then the original patch author makes the change locally, submits a new patch to Bugzilla, and checks it in.

Solution: Review approvals are really about agreeing to sections of a patch, and more specifically about disagreeing to sections of a patch, suggesting improvements. (I am ignoring r- issues for "this patch is not even close to being ready".) Here, distributed RCS's may offer us a new working model:

  1. Alice makes changes A, B, and C to a file.
  2. Alice then submits it to Bugzilla as an attachment.
  3. Bugzilla makes a copy of the central repository for that bug and applies the patch. If the patch doesn't apply cleanly, Bugzilla rejects the patch and tells Alice.
  4. A week later, Bob tells Bugzilla "I want to review this patch." Bugzilla updates the bug's repository from the central repository and finds a conflict. Bugzilla says to Bob, "Sorry, there's a conflict, don't waste your time." Bugzilla then e-mails Alice, "Hey, your patch has bit-rotted. Clean it up, please." Alice works with the bug's repository (possibly her own first) to resolve the conflict.
  5. Bob, reviewing the patch, doesn't like a few lines of change B. He knows what he wants, though, and modifies change B in the Bugzilla repository for that bug. We'll call this change B1.The remaining sections he marks as r+.
  6. Alice sees B1 applied to the bug's repository and agrees that's better. Alice then marks r+ on B1. Bugzilla reminds Alice the patch has r+ for all sections. Alice then requests super-review.
  7. Catherine, doing super-review, objects to a part of change C, and submits an alternative, C1, to the bug's repository. She marks A and B1 as sr+.
  8. Alice disagrees with Catherine's change, and amends it again, offering C2.
  9. Catherine likes it and marks C2 as sr+. Bugzilla tells Catherine that the patch has r+ and sr+ for all sections directly, and e-mails a notice to Alice.
  10. Alice checks it into the central repository.
  11. The Firefox tinderbox goes orange. :-) Alice fixes the bustage, posts a note to the bug, and everyone's happy.

It's a few more steps, and Bugzilla has to do a bit more work (needing a bigger hard drive), but it allows for interactive editing of a patch. Less work on the part of Alice, and Bob's and Catherine's suggested changes go right in.

Posted by WeirdAl at July 14, 2007 5:37 PM
Comments

Two things:

1) Brendan implemented line number annotations that the preprocessor should be outputting so that exception line numbers match the source file... except then view-source to see the error is broken. It's not clear what to do about this.

2) Requiring any sort of large patch to merge cleanly to be reviewable means it'll never be reviewable. Those rot on a weekly basis for sure, some more often.

(From Alex: Hmm. Good point.)

Posted by: Boris at July 14, 2007 7:08 PM

The Bugzilla part sounds very useful to me. Making distributed patch handling optional and/or automatically turning it off based on the patch size and/or number of touched files should already be enough to cover cases like the one brought up by Boris.

Posted by: Dao at July 15, 2007 1:39 AM

JDeveloper 1.3 has an in-built change history that lets you restore or delete snippets of changes that you've made.

I don't know if it's powerful enough (or even appropriate) for your needs, but I suspect that your experimental change sets problem could be and may already be solved by such an implementation. The obvious downside is that you'd be tied to specific IDEs if you depend on the feature.

Posted by: Ben Basson at July 15, 2007 3:25 AM

Doesn't the preprocessor already emit source lineno annotations?

(From Alex: Yes, it does, but it's not enough, not nearly enough. I want a tool that will read those annotations, let me edit in one file, and reflect the changes in the matching file.)

Posted by: Benjamin Smedberg at July 15, 2007 10:12 AM