cat -v harmful stuff

Tom Lord - Diagnosing Subversion

People have recently said things here along the lines of "svn fails to
significantly improve upon CVS and, to the degree it does, meta-CVS
and dcvs do the same job in a better way" (I pretty much agree) and
"it looks like an ego driven project" (perhaps, but then I'd like to
think that arch is a pride driven project and ultimately, isn't that
just a slight difference in spin?).

I've thought a lot about "what went wrong" with svn (and take it as
axiomatic, on this list, that _something_ went wrong) for two reasons:
(1) like Bob, I really tried to like svn; (2) as I started to think
about "what went wrong" -- it seemed like what went wrong was a bunch
of mistakes of exactly the sort that I am inclined towards myself and
therefore have to actively resist: there, but for the grace of
something, stand I.

Here's what I think went wrong.  This is just my unscientific
impression based on following news of the project over the years.

A) It started with a brilliant idea for a hack: a transactional,
   write-once, versioned, hierarchical filesystem database.

   Around the time svn started, that idea was "going around" -- I 
   even had my own version for a little while.

   As an abstract data structure, that kind of database is a neat
   thing with many potential applications.  If you ever spend time
   trying to write robust data-intensive apps on top of a unix
   filesystem without using a database, you really long for that kind
   of functionality.

   Moreover, it's _conceptually_ simple to implement: it's essentially
   just trees written in a functional (side-effectless) style.  To
   "modify" a tree, you build a new tree, sharing unmodified nodes
   with the previous tree.  Seems relatively cheap and transactions
   just fall out of that nearly for free.

   So here's the first mistake:  the idea of a transactional FS is 
   like a shiny new hammer.  It's pretty natural to let it possess
   you and start running around looking for nails.


B) It took off from there with an underdeveloped notion of revision
   control.

   Suppose you have the same intuition that Walter expressed a while
   back, which I'll paraphrase as:  "The first and most fundamental
   task of a revision control system is to take snapshots of working
   directories." 

   If you don't believe that that's a seductive (even though wrong)
   intuition, go back and look at how I replied.  It took many, quite
   abstract paragraphs.  What revision control is really about
   (archival, access, and manipulation of changesets) is subtle and
   _non_-intuitive.  (Anecodtally, a few years before arch, I made an
   earlier attempt at revision control based on, guess what:
   snapshotting.)  What's worse is that a set of working tree
   snapshots combined with a little meta-data is a kind of dual space
   to the kinds of records rev ctl is really about (they're logically
   interconvertable representations).  Anything you say to a
   snapshotting fan about what you want to do with a
   changeset-librarian orientation they can reply to with "Yeah, but
   we could do that, too."  So it's not even that the snapshot
   intuition is completely wrong: it's just putting an emphasis on the
   wrong details.

   Now the transactional filesystem DB takes snapshots handily.  It's
   ideal for that.  So if you have the snapshot-intuition, and the
   transactional fs hammer -- you're apt to leap to a wrong
   conclusion: you've solved the problem!

   And if, as some of the original svn contributors were, you're
   coming from hacking CVS and it's screwy (historically constrained)
   repository format, an apparent escape route from that mess is just
   going to strengthen your convictions.

   Second mistake: The assumption that "a filesystem DB pretty much
   solves revision control -- all the rest is just a small matter of
   hacking".


C) It underwent fuzzy design conceptualization.

   I infer from some of the design documents and other materials that,
   early on, there must have been some bull sessions to plan out
   how svn would work.  As an example, "history-sensitive merging" 
   has been part of the plan (such as it is) for as long as I've been
   aware of the project.

   Whatever planning there was: it didn't nail the details.  Instead,
   it reduced a lot of problems, in a sort of hand-wavy manner, to
   meta-data mechanisms.  I'm guessing (and inferring from docs), for
   example, that somebody straw-manned an intelligent merge operator,
   never really worried about its limitations, but worried more about 
   what kind of meta-data it needed.   Since functionality like file 
   properties seemed more than adequate to record that meta-data,
   the problem was considered reduced to "a small matter of hacking".

   Well, that's the problem with some design patterns like attaching
   property lists to everything under the sun:  they don't really
   solve design problems but they give you an operational language
   in which to _restate_ design problems.  It's sometimes very hard to
   recognize the difference between a restatement of a design problem
   in operational terms and its actual solution.   Application of
   patterns like property lists in a design bull session all too easily
   gives rise to the feeling that "all the problems we're thinking
   about have natural solutions in this design" even though all you're
   really saying is "the problems we need to solve can be expressed
   in terms of associative lookup".

   Third mistake: insufficient skepticism about their own design 
   sketches, early on.


D) Narrow design focus combined with grand technology ambitions

   The original contributors included people who worked on CVS,
   people who used CVS, and people working on products that 
   incorporate CVS.   In some sense, the itch they must have had
   in common was "Get this CVS monkey off my back;  I'm sick of it."

   At the same time, they (justifiably) had their eyes on a real
   treasure -- that transactional filesystem database.

   In that context, it'd be hard to get behind the idea of just
   incrementally fixing CVS.  It'd be hard to invent meta-CVS, for
   example.

   As the project has progressed, over the years, those conflicting
   goals have tended to be resolved in the "get 1.0 out the door"
   direction -- a scaling back of functionality ambitions in the
   direction of CVS necessitated by the degree of difficulty of the
   grand technology ambition.

   Fourth mistake: conflicting goals at opposite ends of the ambition
   spectrum -- the low end ultimately defining official success, the
   high end providing the personal motivations.


E) Leaping to unstable proto-standards.

   SVN came into being at a time when it looked to many like HTTP and
   Apache were the spec and best implementation of the new distributed
   OS for the world that would solve everything beautifully.  There
   was a kind of dog-pile onto everything W3C based on irrational
   exhuberence.  Well, they weren't that OS and they don't solve
   everything beautifully.

   Fifth mistake: jumping on the W3C bandwagon.


F) The API Fallacy

   When you lack confidence about your intended way to implement
   something, a common pattern is to decide to hide the implementation
   under an API.   That way you can always change the implementation
   later, right?

   The problems are: (1) unless you have at least one fully worked
   design for how to implement your API, you shouldn't have any
   confidence that good implementations can exist; (2) unless you have
   at least two fully worked designs for how to implement your API,
   and they make usefully contrary trade-offs, you should really start
   to wonder whether doing extra work to make an abstraction here is
   the right way to proceed.

   Sixth mistake: assuming that defining APIs all over the place 
   would improve chances for success.



G) Collision with reality.

   The transactional filesystem idea is, indeed, conceptually simple
   and elegant.   The reality of implementing it, however, is a swamp
   of external considerations and inconvenient realities.

   Supposing you want to achieve high transaction rates and
   size-scalability.  You have a _lot_ to consider: locking
   (contention over the root of the tree is especially fun),
   deadlocks, logging, crash recovery, physical layout of data, I/O
   bottlenecks, network protocols, etc. etc.

   In short, implementing a really good, high-performance,
   transactional fs is an undertaking comperable in scope and
   complexity to implementing a really good, high-performance,
   relational database storage manager -- only while there's tons of
   literature and experience about RDB implementation, transactional
   filesystems are fresh territory.  (As an aside, if you were to
   seriously undertake to make a transactional FS, I think you would
   not want to burden yourself with the extra work of concurrently 
   building a revision control system on top of it -- give that task
   to a separate team after you have something working.)

   Wanting to make progress simply and quickly, they spotted the
   Berekeley DB library.   After all: it provides transactions with
   ACID properties for our favorite handwavy design tool -- the
   associative lookup table.   As we all know, design problems can be
   "solved" simply by restating them in terms of associative tables.
   And anyway, even if Berkeley DB isn't the _best_ choice to
   implement this, it'll be the fastest way to get something working,
   and anyway it'll be hidden behind an API.

   Well, I think Berkeley DB is a lousy choice for this application.
   It creates administrative headaches, and it's optimized for simple
   associations, not hierarchical filessytems.  It doesn't natively
   provide any sort of delta-compression -- you'll have to layer that.
   Ultimately _all_ that it buys you is transactions and locks --
   every other aspect is a force-fit.

   And what resulted?  Sure enough: years of fighting against
   excessive space consumption, disk-filling log files, and poor
   performance, characterized by substantial rewrites of core
   functionality and API changes.

   A similar mistake happened with network protocols: W3C solves
   everything from authentication to proxying to browsers-for-free;
   WebDAV just sweetens the deal, right?  Except, no, as with Berkeley
   DB for physical storage, a lot is left out and, again, the result
   has been years of rewrites and API changes trying to get somewhere
   in the neighborhood of good performance, plus lots of dependencies
   on unstable externally developed libraries.

   Seventh mistake: underestimating the degree of difficulty of a 
   transactional FS.

   Eigth mistake: overconfidence in dubiously selected building
   blocks.


H) Failure to Fail

   If a team went away for six months and came back with SVN as it
   works today, I think it'd be pretty easy to say: "That's a great and
   even useful prototype.  It definately proves, at least
   schematically, the idea of using a transactional FS to back
   revision control.  There are clearly some bad choices in the
   implementation, and clearly some important neglected revision
   control issues that competing projects are starting to leapfrog you
   over.  And there's a heck of a lot of code here for what it does.
   Let's suspend development on it for a little while, and invest in
   a design effort to see how to get this thing _right_".

   That isn't the situation, though.  A team spent _years_ on this
   and they justified the project institutionally and publicly not by
   saying "let's build a proof of concept" but by saying "let's
   replace CVS".

   And, sure enough, if you suggest to them a stop-and-think phase at
   this late date you get back, basically: "Um...no...not gonna
   happen."

   I won't label that one of their mistakes because I don't think
   the root cause is something they could have easily avoided.
   I'll label it:

   First bad circumstance: crappy socio-economic circumstances for
   smart, ambitious programmers in the free software industry and
   community -- way too much weight given to what supposedly
   successful projects "smell like" and too much resulting pressure
   on hackers to project an image resembling that false idol.

So, in summary, I don't think they're a bunch of egomaniacs or
anything.  I think they rushed into something that looked like it
would be easier than it is, got boxed in by the mythologies of open
source and W3C, and now have way too much momentum and contraints to
do much about it.

What's really disappointed me most, though is that, while I do
perceive them as smart and ambitious, they don't seem terribly
open-minded about stepping back to review their project for deep
structural mistakes that need fixing.  My sense is that most of them
are pretty young and several have been associated with some successful
projects (like Apache and CVS) -- good, young programmers, since they
tend to be capable of so much more than their average peers, often
fall into a pit of overconfidence which is hard to recognize from the
inside until you've experienced a few disasters.  The situation is
made worse since there's so little effective mentoring in the industry
from old-salts who are good at making a religion of the
K.I.S.S. principle and making fun of the wealth of bloated, crappy,
yet slow-to-fail stall-ware projects that dominate so much of the
landscape.  If you ask me, explosive growth during the dot-com bubble
really blunted the technology edges of the free software movment and
our industry generally.  It left us collectively struggling to do
things the hard way, svn being just one small example.

- -t