books chapter three
How big is the ideal team? How do we organize it?
coders
Douglas Crockford, inventor of JSON. At the time of the interview, a great battle was being waged between standardization of ES4 vs ES3.1, which became ES5. He learned to program long ago, when memory was small and CPUs were small, which required a lot of effort to make things fast. “Eventually we got over that, so today we’re writing big applications in JavaScript that run in a browser. It’s such a profoundly inefficient environment compared to the stuff that we used to do, but Moore’s Law sort of made it all OK.” Sort of OK sounds about right. People do it and it does work, but not so well I don’t complain about it.
On the standardization of JavaScript, he feels it happened too fast, and thus encoded a lot of mistakes. It’s better to allow some different implementations evolve in parallel, see what works, and then standardize the winner. If the standard is simply a reflection of the first implementation, or even no implementation, that’s a lot less real world experience. A lot of unexplored solutions, and then it’s too late. If you add more features later, you still can’t take away any features, and now your langauge is far too complex. Probably not much of a surprise that the author of JavaScript: The Good Parts advocates for making JavaScript better by making it smaller.
One of the problems not being solved by adding new features to JavaScript, or making it faster, or writing larger applications in it, is making web pages more secure. All the scripts on a page have equal access to the DOM and the network. And you can have bits of script embedded in CSS embedded in HTML, etc., all with different quoting and escaping and commenting conventions. This makes it difficult to work and reason with large applications, but probably not something arrow functions will fix.
At the time of writing there were too many Ajax libraries, because they’re so easy to write, so everybody made one. I wonder what he’d say now.
Douglas likes doing code reviews. Put some code up on a screen, then walk through it and explain what it does to everyone in the room. Pair programming for large values of pair, but really mostly after the fact. The code is written, now we’re just reading it. We did this once, one day, at a previous company and I thought it was kind of amazing. All this code which you know exists, but now you’re seeing it as if for the first time, and it’s ridiculous how many ways there are to improve it. I’m not sure why we never did it again, it was a great exercise. It’s a little different than just change review. One of the advantages of doing these code reivews is that everybody can see where everybody else is, progress wise. This avoids late surprises, much like Brooks discussed in chapter two.
Is there a right and wrong style? Douglas thinks K&R got the braces correct, but regrets they didn’t define that as the official style with tools to pretty print C. Maybe the go authors read this book? And of course, in JavaScript, you can put the braces here or there, but that changes the program meaning, so probably best to do things the right way.
Every six cycles let your code lie fallow, just like it says in the Bible. A 6:1 development and refactor ratio sounds pretty reasonable. I don’t think the OpenBSD release cycle technically qualifies, since the quiet month before release isn’t really dedicated to refactoring, but with much the same benefit. Take a little time off to breathe, and let the code breathe too.
Some more thoughts on advances in hardware vs software. “Most of our improvement is due to the fact that we don’t have to make it fit anymore. We don’t have to make it fast anymore. So that should have liberated us to just making it good. But we don’t spend enough time doing that, I think.” Some more insights about progress sometimes runs backwards. Long ago, the MULTICS had robust program and user isolation. Then we got the PC, which doesn’t. Now we’re trying to build sandboxed software on PCs (and much more so in the last few years), but it has to fit into a computing model which kind of assumes every program can do anything at any time. Programs aren’t written to read files through the filesystem broker because there is no filesystem broker. In a sense, the internet is a larger (much larger), but worse (much worse?) time sharing system.
More than some of the other interviews in the book, I think this one reflected a certain moment in time. But it’s still true today, and the parts that are perhaps less relevant are still interesting to see how things turned out.
founders
Dan Bricklin founded Software Arts to write VisiCalc. This is somewhat confusing, because the program was distributed by a company called VisiCorp. A somewhat different business model than is common today, where some people write code and then some other company sells it, markets it, and supports it. The ultimate in development team isolation I guess.
Early word processors were very limited because they were stuck with a paper metaphor. If you filled up one page, you would have to manually move the text from one page to the next. Because that’s how paper works, and the word processor is just paper, but in the computer. Sometimes it takes a while to realize when a restriction has been removed.
Dan focused on making VisiCalc really easy to use. It should be easy to use without much instruction, and without ambiguity. Which is why cell coordinates look like A1 and B3. People are already familiar with maps, so the syntax is familiar. A grid coordinate like 4,3 is more likely to be used mistakenly in a formula.
Some serious hardware limitations also influenced the design. There’s not much memory for features, of course, but there’s not much room for documentation either. Which makes for an interesting design criteria. Imagine all your program documentation has to fit on a double sided reference card. If the documentation doesn’t fit, the feature must either be self evident or omitted.
Eventually, just as H&R Block, via their CompuServe division, was going to buy the company, VisiCorp sued VisiCalc (so confusing) and killed the deal. And then they were basically bankrupt and had to be swallowed up by Lotus, mostly as a mercy killing.
Which brings us to Mitch Kapor, founder of Lotus. He started with a graphing program, VisiPlot, distributed by VisiCorp, but had a fight over royalties, so they bought him out and he founded his own company. He had a noncompete agreement, but carved out an exception for an integrated graphing calculator program. He was granted the exception because they didn’t think he could do it. But he did do it! Strange and confusing times, to be sure.
Lotus decided to target the new IBM PC for their initial product. Lots more memory, faster processor, etc. And so where VisiCalc was limited to 64K even on a PC, Lotus could use 640K. Mitch’s explanation is a little fuzzy, something about 8-bit code vs 16-bit code, and it doesn’t entirely square with my understanding of how things work, but the salient point is by taking advantage of the new hardware, they were able to improve the product. It wasn’t the same old product running on new hardware. It was an entirely new product.
One might compare to 64 bit processors today. It’s not just a 32 bit processor with a bigger address space. It is that, for sure, but the address space is so large we can rethink how we use it. Tag bits, etc., no longer have a practical effect on available memory.
This new design let them do things that couldn’t be done by existing competitors, like one button graphing. Instead of exporting a spreadsheet to a data disk, then swapping program disks, then swapping data disks, then graphing, then swapping it all back to make a change, you could do everything in one program using the same working set. Given the speed of floppy drives, I can see why Lotus would be popular.
The trend towards integrated software hasn’t really gone away. Usually explained that users like it, having everything in one program. Of course, I’m the outlier. I like separate programs for everything. Comparing how one would use VisiCalc to Lotus, what stands out to me isn’t so much the integration as the reduced friction. The real selling point wasn’t the integration per se, but the time and effort that was saved. If it’s easier to switch between programs, and transfer data between them, they don’t necessarily need to be integrated.
man-month
The surgical team, in which we are introduced to the 10x programmer. Even with the best possible team, 10 10xers, if a project consists of 5000 man-years of work, that’s still going to be a very long development time. Sometimes we really do need to go wide.
The best way to do that is to organize the team like surgical units. In an operating room, there’s a large group of support staff, but only one surgeon. One person cuts, not ten. A programming team then has only one programmer, but many other support stuff.
There’s a copilot, a junior programmer of sorts, who doesn’t really code anything but watches and learns and talks to outsiders as s technical liaison. There’s an editor, who doesn’t necessarily write the documentation (the surgeon does that, too) but maintains it and cross references it and prepares it for publication. There’s two secretaries, primarily because it’s 1970 and why not, although I imagine one could be a much more productive programmer with a dedicated email reader. There’s a program clerk, who is responsible for backing up punch cards or what have you and maintaining archives of sources and outputs. This would be an interesting position today. Full time git jockey. There’s a toolsmith, who creates custom text editing and debugging tools for the programmer to use. There’s a tester, responsible for coverage and reproducing issues. And finally, there’s the language lawyer, someone who really knows how to squeeze the Algol compiler and make it perform as desired, a micro optimizer.
So that’s a lot of people. I’d probably get more done if I never had to think about any of those tasks. Most of the time it seems everybody does a little bit of everything. Here at X Corp, everybody writes their own tests. Or maybe there’s a programming team, and a testing team, and a documentation team, etc. Sometimes they all work on one product, but rarely with such one to one to one individual assignments. (At least in my experience.) Within a product, teams are often divided up according to functional organization. But we can take divisional organization to the extreme, right down to the individual level.
Is it better or worse (in today’s dev environment)? It would certainly be interesting if I could write code all day, and somebody else would be responsible for running git and branching and rebasing. There’s a lot of tooling involved in development, and lots of tooling means lots of time spent learning tooling, which is perhaps inefficient. Am I using the optimal vim config? Why not have someone else on my team explore that?
pragmatic
7. The evils of duplication, when knowledge about a system is duplicated in many places and results in a maintainence burden. There are many causes of this duplication. Writing a client and server in different languages or for different environments, for example, suggests using a code generator for the common parts. Everybody has experienced the problem of comments diverging from the code described, which is why you should never write comments. Sometimes data structures inadvertently denormalize data, which can cause runtime inconsistencies. In short, don’t repeat yourself. Working as a team, put someone in charge of reviewing code for common functions and maintaining a shared library.
8. Which brings us to orthogonality, where unrelated changes should not affect unrelated systems. An example of a nonorthogonal system are the flight controls for a helicopter. I thought this was a pretty good example, although it does require knowing a bit about how helicopters work. There’s no simple up down control. In order to descend without spinning or tilting requires adjusting a variety of controls to compensate for the change in pitch. Then there’s some examples of enterprise Java code, whatever that is, but the general idea is that if you integreate a library into your project, it should not require reworking code that doesn’t use the library.
9. Reversibility is the idea that you should be able to change as many decisions as possible. Nothing should be set in stone. This is probably easier if you’re building with orthogonal components, which can be swapped around as needed. If you build upon some tech stack, database, etc., be prepared for the day when you find out it doesn’t really work.
I liked this idea. It’s an extension/consequence of the above, but it’s important. Sometimes it’s really convenient to insert a few quick calls to the database right in the middle of a function, but this makes changing the database a tedious endeavor later. And you will need to change the database, because it’s not possible to pick the right database the first time.
code
We’re going to take our knowledge of circuits to build some messaging systems. This requires a lot of wiring, but if we connect some of the circuits to ground, we can use one less wire. Alas, using the kind of wiring we can afford means our distance will be limited by the resistance of the wire. We could use jumper cables, but a mile long cable would be kind of expensive. We have reinvented the same problem encountered in stringing a telegraph cable across the country.
Samuel Morse was born the same year that Mozart died, so maybe they’re the same person. Morse invented the telegraph using electromagnetism, and it’s interesting to note that the early versions wrote on paper. That’s how one sent messages, after all. It took a little while before operators decided it was faster and easier to simply listen to the clicking and decode the audio signal instead. Stuck in an old paradigm. Although, that said, I don’t think many people could keep up with a 9600 baud telegraph, but it’s pretty simple to read the paper after transmission. So there’s something to be said for that.
Telegraph wires were limited in range, requiring operators to sit out in little huts scattered about, listening to one receiver and duplicating the message on an adjacent transmitter. Of course, it doesn’t take long to realize the incoming message is a metal bar dancing up and down, and the outgoing message is a little lever dancing up and down. Why not connect the two? And now we have a fully automatic relay. The wonderful property of a relay is it takes an incoming signal and boosts it. We also now have a circuit that can be operated at a distance, controlled by another circuit. This should be cool.
coda
A lot of emphasis on using the wrong paradigm and not adapting to changes in technology. Sometimes a difference in degree becomes a difference in kind and we don’t even notice. Other times we notice, but don’t really make the best use of the difference. Also awareness of how things are going. From don’t repeat yourself to whole team code reviews to team liaisons, don’t let things get away from you.