# HG changeset patch # User Sean Russell # Date 1309186126 14400 # Mon Jun 27 10:48:46 2011 -0400 # Node ID 64b6459784b48d31957f5561e9e3e615aaf5afb0 # Parent e18d142ab1eb32f6926484983cf063019ef26e90 Removes the commentary on Ruby and Go; fixes some of the usage documentation. diff --git a/README.rst b/README.rst --- a/README.rst +++ b/README.rst @@ -33,13 +33,17 @@ Dependencies ================================================================================ -- Ruby >= 1.8 +- Ruby >= 1.8 (for the Ruby version) +- `Google Go `_ (for the Go version) - Mercurial >= 1.6 (for versioning) Usage ################################################################################ -The application follows a simple contract: +Currently, the Ruby and Go versions differ in behavior. This will be fixed, to +make the Ruby version behave like the Go version. + +The Ruby application follows this contract: - Any object X may descend from any objects B0, B1, ..., Bn - X inherits all attributes from all parents in a defined order @@ -47,6 +51,24 @@ - X is versioned - X must not be an ancestor of itself (a config forms a directed, acyclic graph) - Inheritance is determined at creation time, not at run time + +The Go application follows this contract: + +- An object X may descend from another object Y. There is only a single + direct inheritance, but there may be multiple ancestors +- The ancestor objects of X may or may not exist +- X inherits all attributes from all parents +- X may override any attribute inherited from a parent +- X is versioned + +The Ruby version is entirely encapsulated in the file ``config.rb``; to run it, +run ``ruby config.rb``, or ``ruby config.rb --help`` for usage instructions. + +The Go version must be compiled; run ``gomake`` to compile it -- the output is +a native executable called ``conv``. Run this to run the server. Run ``conv +--help`` for usage instructions. Run ``gomake functional`` for the functional +test suite; run ``gotest`` to run the unit tests. + REST API ================================================================================ @@ -116,98 +138,6 @@ The path to the version control executable (including the executable name itself). Currently, only Mercurial is supported. - - -An implementation note -================================================================================ - -The original version of this application was written in Ruby, a language that I -was once extremely well-versed in, but which I haven't used for anything but -one-off command-line scripts in a few years. It took me about 6 hours to write -the thing. - -Out of curiosity, and since the project was so small, I decided to re-implement -it in `Go `_. This was the second time I'd looked at Go -syntax; the first was to fix a small benchmark program that was comparing Go to -`Vala `_, so it really was the first time I'd -written any Go; I was utterly unfamiliar with the packages. This second version -took me about 20 hours. That time includes unit tests and a couple of -refactorings to improve segregation of responsibility; I guesstimate that if I -performed the same refactoring and writing unit tests for the Ruby code, I could -probably spend another 6-10 hours -- on the one hand, I know the shape of the -modules/packages; on the other, writing unit tests always takes a lot of time. - -`Cloc `_ tells us this: - ----------------------------- -------------- ------------ ----------------- ---- -Language files blank comment code -============================ ============== ============ ================= ==== -Go 7 104 43 482 -Ruby 1 59 55 326 ----------------------------- -------------- ------------ ----------------- ---- - -This excludes unit tests. So here's my (subjective) take on this: - -- I'm frankly amazed that the Go LOC is so close to the Ruby LOC (33% - larger). If I refactored the Ruby code to be more well-structured and - encapsulated (and unit-testable), that LOC delta would shrink even more. -- The Ruby program is a single, executable-and-library file. This was - intentional. I was able to break up the Go code into more files because the - end artifact would also be a single executable. -- The Go compiler is wicked, stupid fast. ``gomake`` is nice, in that it uses - standard Makefiles but provides includes to greatly simplify the Makefiles. -- The Go unit test package is anemic, providing only the bare minimum of - functionality. -- Go has such potential for mixing in, but the language spec disallows it (you - can only define functions on structures that are within your own package). -- Even if I were as knowledgeable about Go as I am about Ruby, I'd still have - been able to whip the Ruby version out faster. On the other hand, the Go - version is much safer, and I trust that program a *lot* more -- it is, after - all, type-checked. I guarantee that no matter how much I look at the Ruby - code, if it runs for any length of time I'll eventually encounter a typing - error because of a bug in the code. -- Go has an amazingly useful set of built-in libraries, without being package - and class bloated (like, say, Java). Although, the crypto package is - curiously huge. -- http://golang.org/pkg FTW! -- Doing system exec stuff is easier in Ruby, but not by a lot. - -All in all, Go surprises me; it's concise, easy, encourages good separation of -concerns, is easy to read, and much more functional in feel than you'd expect -from looking at the tutorial. At the same time, it has some unfortunate quirks: -it's (currently) relatively slow for a compiled language, and builds large -executables; some language constructs are just baffling in their constraints, -such as ``range`` only being applicable to a small set of built-ins, rather than -working on some well-defined interface; tail-call optimization is extremely -limited, which is such a shame for a language as close to being a functional -language as Go is; and the lack of ability to mix in to extra-package types is -limiting. - -To the first point in my list of Go quirks, I have no doubt that this will -change rapidly, and Go will catch up; it's a very young language, after all. As -to the last point, the explanation put forth by the Go developers is, frankly, -weak. It's the same argument Gosling made about not supporting multiple -inheritance in Java, which basically boils down to "programmers are stupid, and -this feature will confuse them." I don't buy it; I'd rather have extra-package -mix-ins with limitations based on technical merit than none at all. - -I've learned that I vastly prefer the cost of slower development time to gain -reliability and safety, as long as the cost isn't too high. Haskell is even -safer, but it pushes the boundaries of how much pain I'm willing to endure -trying to get code to pass through the type checker. - -Right now, I'm thinking Go's a keeper. It is more productive than C, more -reliable than Ruby, easier than Haskell, is superior to Erlang in a whole host -of ways I won't enumerate here (although, I do like the features that the OTP -brings to the table, many of which are "killer" features unavailable in any -other language, which keeps Erlang highly relevant), and is far better than Java -in terms of simplicity, syntax, typing, threading, native compilation, and -memory use. Each of these languages surpasses Go in their own ways, but I -believe that Google has successfully found that sweet spot in a practical -language that minimizes the annoying attributes and boiler-plate, and provides -strong typing, resulting in a highly "writeable" language that compiles to -native executables. We'll see how I feel with a few gross more hours under my -belt. Links @@ -216,3 +146,4 @@ * `Project page `_ * `Status `_ * `Repository `_ +* `Thoughts about Ruby and Go `_