29 December 2007

Exam prep: 1

I'm taking the opprtunity of the holiday slack time to restart my exam preparation for certification as an MCPD: Windows Developer. I currently hold an MCAD, so I need take only one exam to bump up to the next cert. I had been studying in August and September, but I let myself get distracted, so it's almost like I'm starting over. I've set myself a new goal of passing exam 70-552 by April 30.

I'm reading selected chapters of Jeffery Richter's CLR via C#, largely for background and a refresher on concepts like boxing and unboxing. The heavy-lifting prep is working through Microsoft's self-paced training books MCTS 70-536, MCTS 70-526, and MCPD 70-548. Fortunately, all of these are available through Safari, albeit at two slots a piece. I'm not looking forward to the long units on crypto and security, because, try as I might, it's an area I find it hard to get excited about.

18 December 2007

Happy birthday, Perl

Tony Long celebrates Perl's twentieth anniversary. But his copy editor must have been writing ironically when he headed the post, "Perl Simplifies the Labyrinth That Is Programming Language." I've written smallish apps in Perl, and I consider it an effective tool, but for me it will always be the Pathologically Eclectic Rubbish Lister.

27 October 2007

SurveyNOW

The current project to which I contributed, SurveyNOW, has been launched into the webby wide world.

11 October 2007

The Pragmatic Programmer

When I was just starting out in the field, the best way to get all of us wound up (at happy hour, say) was to restart the argument, "Is software development an art or a science?" And after all of us had talked ourselves out, my team leader Larry would quietly smile and say, "But of course, it's neither: it's a craft." Larry would find lots of common ground with Andrew Hunt and David Thomas, authors of The Pragmatic Programmer: From Journeyman to Master. Their instructive, enjoyable, at times even inspiring book, published in 2000, is a blend of theory and practice. Dedicated to software engineering principles yet refusing to become enslaved by formal methods, the authors believe that it is possible to carry out a tradition of craftsmanship within an engineering discipline. In a tidy 321 pages, they have assembled a philosophy of software design and construction, illustrated with current industry best practices.

Thomas and Hunt's target reader is an object-oriented programmer in a command line environment, but the bulk of their advice applies equally well to the developer in a legacy language (and, as they point out in a footnote, "All software becomes legacy as soon as it's written") or to the practitioner in the latest whizbang development studio. Theirs is one of the most literate works in the field: they have a gift for metaphor ("tracer bullets," "broken windows," "orthogonality," "rubber ducking") and a penchant for epigraphs from sources ranging from Wittgenstein to Oscar Wilde, Santayana to Arlo Guthrie.

The authors are perhaps best known for promulgating the DRY principle—Don't Repeat Yourself:

Every piece of knowledge must have a single, unambiguous, authoritative representation in a system.


Violations of this principle, in other words, duplication, are multivalent—redundant bits of code, documentation that must explain difficult code (or worse, that contradicts it), the exposure of class members to direct manipulation rather than through accessor methods—and Hunt and Thomas recommend code generators and automated builds, configuration files, MVC techniques, and vigorous and proactive refactoring as ways to forestall duplication.

They also advocate tight interlacing of documentation and code (à la Knuth's Literate Programming). In much the same way, the book is constructed from interlocking elements: 70 pithy tips and eleven checklists (indexed at the back of the book), section cross-references, and sidebars. This material isn't book-designer fluff, but rather the essence of the book. For use in a course, the book offers chapter exercises; as a stepping stone to further knowledge, Thomas and Hunt annotate books and other resources in a bibliography.

The companion website for the book also links to the authors' more recent publishing and training endeavors.

Table of contents:


  • Foreword
  • Preface
  • 1 A Pragmatic Philosophy

    • 1. The Cat Ate My Source Code
    • 2. Software Entropy
    • 3. Stone Soup and Boiled Frogs
    • 4. Good-Enough Software
    • 5. Your Knowledge Portfolio
    • 6. Communicate!

  • 2 A Pragmatic Approach

    • 7. The Evils of Duplication
    • 8. Orthogonality
    • 9. Reversibility
    • 10. Tracer Bullets
    • 11. Prototypes and Post-It Notes
    • 12. Domain Languages
    • 13. Estimating

  • 3 The Basic Tools

    • 14. The Power of Plain Text
    • 15. Shell Games
    • 16. Power Editing
    • 17. Source Code Control
    • 18. Debugging
    • 19. Text Manipulation
    • 20. Code Generators

  • 4 Pragmatic Paranoia

    • 21. Design by Contract
    • 22. Dead Programs Tell No Lies
    • 23. Assertive Programming
    • 24. When to Use Exceptions
    • 25. How to Balance Resources

  • 5 Bend, or Break

    • 26. Decoupling and the Law of Demeter
    • 27. Metaprogramming
    • 28. Temporal Coupling
    • 29. It's Just a View
    • 30. Blackboards

  • 6 While You Are Coding

    • 31. Programming by Coincidence
    • 32. Algorithm Speed
    • 33. Refactoring
    • 34. Code That's Easy to Test
    • 35. Evil Wizards

  • 7 Before the Project

    • 36. The Requirements Pit
    • 37. Solving Impossible Puzzles
    • 38. Not Until You're Ready
    • 39. The Specification Trap
    • 40. Circles and Arrows

  • 8 Pragmatic Projects

    • 41. Pragmatic Teams
    • 42. Ubiquitous Automation
    • 43. Ruthless Testing
    • 44. It's All Writing
    • 45. Great Expectations
    • 46. Pride and Prejudice

  • Appendix A: Resources

    • Professional Societies
    • Building a Library
    • Internet Resources
    • Bibliography

  • Appendix B: Answers to Exercises
  • Index

05 October 2007

Fonts for coders: 2

Jeff Atwood gives an update on monospace fonts for software development. He presents screen shots of the same piece of specimen code viewed with ten different fonts, popular and more obscure. His favorite is Consolas, and I have to admit that I could be tempted to give up Bitstream Vera Sans Mono for it. Consolas slashes zeroes and it puts an aggressive hook on the comma so that you can separate colons from semicolons.

17 September 2007

Cheapo productions surfing

I was shuffling reference books about, generally moving the less frequently-used ones to the shelves in the basement, and I picked up Shishir Gundavaram's CGI Programming on the World Wide Web (O'Reilly, 1996). Definitely one to move to the archive shelves. And yet—there is a sticky note on page 373, and it's there to mark a passage that describes a low-tech way to check on a web server using telnet:

% telnet www.google.com 80
Trying 64.233.169.104...
Connected to www.l.google.com.
Escape character is '^]'.
GET / HTTP/1.0

HTTP/1.0 200 OK
Cache-Control: private
Content-Type: text/html; charset=ISO-8859-1
Server: gws
Date: Tue, 18 Sep 2007 02:16:00 GMT
Connection: Close

<html><head><meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"><title>Google</title>
...
</body></html>Connection closed by foreign host.
%

You can use this technique to see the unvarnished HTML payload without doing a View>Page Source, as well as the HTTP headers. Best way to find out who's running Apache, who's running IIS, who's running something custom.

It's easy to run telnet from a Mac OS Terminal window: just remember to hit the enter key twice after you type type the GET line. I was less successful running telnet from a Windows Command Prompt window.


% telnet www.microsoft.com 80
Trying 207.46.19.254...
Connected to toggle.www.ms.akadns.net.
Escape character is '^]'.
GET / HTTP/1.0

HTTP/1.1 302 Found
Cache-Control: private
Content-Type: text/html; charset=utf-8
Location: /en/us/default.aspx
Server: Microsoft-IIS/7.0
X-AspNet-Version: 2.0.50727
P3P: CP="ALL IND DSP COR ADM CONo CUR CUSo IVAo IVDo PSA PSD TAI TELo OUR SAMo CNT COM INT NAV ONL PHY PRE PUR UNI"
X-Powered-By: ASP.NET
Date: Tue, 18 Sep 2007 02:26:39 GMT
Connection: keep-alive
Content-Length: 136

<html><head><title>Object moved</title></head><body>
<h2>Object moved to <a href="/en/us/default.aspx">here</a>.</h2>
</body></html>
Connection closed by foreign host.
%


When I hit the server at Amazon.com, the last line of HTML consisted of the comment string <!-- MEOW -->. Go figure.

29 August 2007

DUCET not dulcet

So I was working on a little piece of code that was responsible for sorting a list of names—titles of surveys, to be specific. And I noticed that my test data was sorting a little funny. I had a couple of surveys named "Case 4310-1" and "Case 4310/2" and I saw that the former sorted after the latter, even though the crib sheet that I always keep in my Day-Timer says that "-" is ASCII 45 (decimal, hex 2D) and "/" is ASCII 47 (hex 2F). How could this be?

Well, the first thing that I did was explicitly specify the method that I wanted to use to perform the sorting. We're developing in .NET 2.0, and I'm using a generic SortedList to build up the list of survey titles. If I chose, I could specify a strict binary character-by-character sort with this constructor


SortedList sortedList = new SortedList(StringComparer.Ordinal);


and I would get the sort that I "expected." But an ordinal comparer is case-insensitive, and I really want to be able to sort "case 10" and "Case 10" together. Now, fortunately, this code runs only on our servers and there is no provision in the app (at present!) to allow a user to specify a culture (what we called a "locale" in my old UNIX days) for sorting: one size fits all. So instead I wrote


SortedList sortedList = new SortedList(StringComparer.InvariantCultureIgnoreCase);


and I was back to the odd behavior that initially puzzled me. Furthermore, inserting space around the punctuation changed the sort order: "Case 4310 - 1" sorts ahead of "Case 4310 / 2".

It was clear that some culture-based behavior was in play—some kind of special treatment of a hyphen in certain cases—and I was perfectly happy to ship the app this way: all we really cared about was getting the names sorted into some usable order. But I was curious: what is the sort order for the "invariant culture"? I prowled around the Microsoft documentation and found little more than this explanation:

InvariantCulture retrieves an instance of the invariant culture. It is associated with the English language but not with any country/region.


and the hand-waving

The .NET Framework uses three distinct ways of sorting: word sort, string sort, and ordinal sort. Word sort performs a culture-sensitive comparison of strings. Certain nonalphanumeric characters might have special weights assigned to them; for example, the hyphen ("-") might have a very small weight assigned to it so that "coop" and "co-op" appear next to each other in a sorted list. String sort is similar to word sort, except that there are no special cases; therefore, all nonalphanumeric symbols come before all alphanumeric characters. Ordinal sort compares strings based on the Unicode values of each element of the string.


and a pointer to the Unicode docs.

So I opened up Unicode Technical Standard #10: Unicode Collation Algorithm, and OMG life is so much more complicated than the old POSIX days when about you had to know was that "ll" sorted after "l" in Spanish. Consider this tidbit from the introduction:

For example, Swedish and French have clear and different rules on sorting ä (either after z or as an accented character with a secondary difference from a), but neither defines the ordering of other characters such as Ж, ש, ♫, ∞, ◊, or ⌂.


I was taken back to the days when I worked in the music library, where the librarians had to figure out how to shelve a score whose title was in Russian.

I also learned about the concept of equivalence: different sequences of Unicode characters that can be treated exactly the same for collation purposes. For instance, there are three different ways to represent the angstrom symbol, a capital A with a ring.

UTS #10 points to the Default Unicode Collation Element Table (DUCET), a huge text file that provides, for one collation, all the data to the sorting algorithm for all Unicode characters and their combinations. Here's a snip of what I think is the relevant data for my question:


002A ; [*02FB.0020.0002.002A] # ASTERISK
002B ; [*04B8.0020.0002.002B] # PLUS SIGN
002C ; [*0232.0020.0002.002C] # COMMA
002D ; [*0222.0020.0002.002D] # HYPHEN-MINUS
002E ; [*0266.0020.0002.002E] # FULL STOP
002F ; [*02FF.0020.0002.002F] # SOLIDUS
003A ; [*0241.0020.0002.003A] # COLON
003B ; [*023E.0020.0002.003B] # SEMICOLON



With a little more patience, and some stumbling through the algorithm, I may be able to derive an explanation for the sorting behavior I've observed. But it's too bad that it can't just be reduced to a brief explanation in words, like "ignore a hyphen when it's followed by another alphanumeric character." The problem is just too elaborate now.

17 August 2007

Caveat

Jeff Atwood critiques Yahoo!'s Thirteen Simple Rules for Speeding Up Your Web Site.
There's some good advice here, but there's also a lot of advice that only makes sense if you run a website that gets millions of unique users per day.

16 August 2007

How not to do it

Mark Liberman points to his own irreverent guide to using the web interface to FacilityFocus, an automated system for submitting and tracking building maintenance requests on the University of Pennsylvania campus. The irreverence is necessary, because the interface is appallingly bad. Consider Step 2 in Liberman's guide, which helps you get past a search page that also gateways the "add new work request" page:
You may be tempted to fill out some of the 23 temptingly-empty text boxes on this screen, with information like e-Mail (that's easy) and "Desired Date" (that one's a little personal, don't you think?) -- BUT DON'T! This is a search screen, and you've got nothing to search for yet, since you haven't actually gotten your work request into the system.

Yes, I know that it says "Search Criteria Required!" at the top of the screen, in red letters, with an exclamation point. But that's just to fool you into thinking that search criteria are required. In fact, the only thing that's required (or even permitted!) for you to do at this point is to click on the large button labelled "Insert" at the top of the page...

It only gets worse. The popups for specifying what the problem is, and in what building, are populated with pages and pages of codes, and apparently these can't be sorted (it's a little hard to tell from the screen shots). A column labelled PROBLEM DESC has unhelpful entries like "HVAC" (Liberman glosses this abbreviation for the users), "HOT," and "COLD." Does "HOT" mean "it's too hot" or "I need more heat"?

Liberman, who wrote the guide as if it were a handbook for an adventure/role-playing game, comments:
But adventure-game interaction is really the wrong metaphor. The designers of good adventure games have a excellent idea of what their target users are like, and they've carefully planned and tested for their users' reactions to each display and each event in the game. The obscurity and difficulty of the interaction is carefully crafted to be suspenseful, entertaining -- and eventually overcome. In contrast, an interface like FacilityFocus seems to be "mind blind". The obscurity and difficulty of the interaction is a random result of an apparent failure to try to model user reactions at all.

27 July 2007

Scaffolding

I've been trying to implement some of the ideas in Steve Pavlina's scaffolding exercise, which is designed to improve personal productivity. At present, my workflow at work is such that I'm not frantic with getting everything done; rather, I'm trying the exercise out on my personal life. That said, Pavlina's technique is really tuned for on-the-job productivity enhancement.

A personal productivity scaffold is like wearing braces. It's a way to redirect your time and energy back onto the "straight" course and away from the crooked one. Once you've set it up, it's fairly easy to maintain, although you may still regard it as a small sacrifice.

Perhaps the most important function your scaffolding must perform is keeping your attention focused on what you want and off of what you don’t want.


(Link via Lifehacker.)

11 July 2007

Fonts for coders

The monospaced fonts that come with your Windows box (like Courier New) aren't particularly good at distinguishing capital O's from zeroes and semicolons from colons, and that can make debugging more difficult.

Andale Mono slashes 0's, so it's very helpful on that score. It was once freely available from Microsoft, but is now discontinued. There are undoubtedly some illicitly-available copies rattling around somewhere.

My preferred font now is Bitstream Vera Sans Mono, which does a better job of sorting out :'s from ;'s.

Read this comment thread for more options.

27 June 2007

The Black Knight is learning Python

Mary Brandel recaps the top 10 dying computer skills. Number 1 is COBOL: I'm not sure whether the top slot means closest to dead or most likely to survive.
... you can actually learn Cobol at Southern Illinois University at Edwardsville, which according to Mary Sumner, a professor there, still offers a Cobol course. "Two of the major employers in the area still use Cobol, and for many of their entry-level jobs, they want to see that on the transcript," she says. "Until that changes, we'd be doing the students a disservice by not offering it."

All the same, it's probably worth deleting this bullet point from your resume.


(Link via kottke.org.)

25 June 2007

Stone soup

Joel Spolsky takes a little time getting to the point, but it's a good one: A top-quality software product is achieved incrementally:
Commercial software—the kind you sell to other people—is a game of inches.

Every day you make a tiny bit of progress. You make one thing just a smidgen better. You make the alarm clock default to 7:00am instead of 12:00 midnight. A tiny improvement that will barely benefit anyone. One inch.

There are thousands and tens of thousands of these tiny things.

This past week I began contributing to the development team's wiki: a compendium of product management information that includes everything from profiles of our competitors, to product plans for the next year or so, to resources for software engineers like tips on debugging. Just a few pages, but they will make the wiki just a bit more useful, and therefore make it just a bit more likely that other people on the team will contribute and read. And ultimately, our product line will be just a bit better.

14 June 2007

Why didn't I know that?

Via Lifehacker, ChuckOp points out that Ctrl-C can be used to copy the complete contents of a Windows message box to the clipboard: no text-selection required (or possible, of course). V. handy for grabbing an error code on the way to Googling a diagnosis.

13 June 2007

Version 22?

Good Lord, EMACS is still being actively maintained. Who knew?

Back in the day, I could hack my way to a couple of useful macros: reformatting tricks, and I seem to remember making a VT100 act like a Prime Computer block-mode terminal, something like that. But I never drained the cup of Kool-Aid, like using the editor to run the COBOL compiler and my regression test suite.

(Link via Compiler.)

31 May 2007

Don't Make Me Think

Here's a couple of snippets from Steve Krug's Don't Make Me Think: A Common Sense Approach to Web Usability. He makes some points that are pretty obvious, but easy to overlook.
Pulldowns are most effective for alphabetized lists of items with known names, like countries, states, or products, because there's no thought involved. If I'm looking for VCRs, for instance, I can just scroll down to the V's.

But they're much less effective for lists where I don't lnow the name of the thing I'm looking for, especially if the list isn't alphabetized or is long enough to require scrolling. (p. 110)

...the Web experience is missing many of the cues we've relied on all our lives to negotiate spaces. Consider these oddities of Web space:

No sense of scale. Even after we've used a Web site extensively, unless it's a very small site we tend to have very little sense of how big it is (50 pages? 1,000? 17,000?). For all we know, there could be huge corners we've never explored. Compare this to a magazine, a museum, or a department store, where you always have at least a rough sense of the seen/unseen ratio.

The practical result if that it's very hard to know whether you've seen everything of interest in a site, which means it's hard to know when to stop looking.

This is one reason why it's useful for links that we've already clicked on to display in a different color. It gives us some small sense of how much ground we've covered. (p. 57 and note)

Imagine a browser extension that lets you specify how soon to revert links to the univisited color on a per-domain basis, instead of the global setting that Internet Explorer and Firefox provide. I would be all over that.

21 May 2007

Plot this

Check out FooPlot, an online graphing calculator. If I'd had this 35 years ago, I might have really understood polar coordinates.

(Via Compiler.)

Mystery solved?

I may have figured out the intermittent problem that manifested itself with the error message:

The file web.sitemap required by XmlSiteMapProvider does not exist.


It turns out that the web server on my development box was configured to allow anonymous access, with the "Internet Guest Account" identified as the proxy account. This is the account named IUSR_<server name>. Fairly standard set-up.

What we changed, what seems to have dealt with the problem, is to specifically grant permissions to IUSR_<server name> to the file system folder that the virtual directory was mapped to. From Windows Explorer, context-click the folder, pick Properties, then pick the Security tab. Because the web app writes log files under that folder, and the web site admin can also use the app to add and delete uploaded files (themes, templates, that sort of thing) under that folder, we granted Full Control to the Internet Guest Account.

YMMV. Reflecting on this, it occurs to me that it's probably not the best choice from a security point of view to allow the web app this degree of access. Config parameters that point to the log files and templates and themes would be a good idea: I will bring it up with the team.

Tap tap-tap

Jim Horning has started a thread on the Risks Digest about slow keyboard response in Internet Explorer 7, apparently when lots of JavaScript has been executed in the browser window's lifetime. Multiple tabs exacerbate the problem.

04 May 2007

Still collating

Douglas W. Jones, on the CS faculty of the University of Iowa, maintains an online museum of punchcards (originally known as Hollerith cards) and related technology.

(Link via things magazine.)

20 April 2007

Yet another mystery

I am bedeviled by an intermittent fault when I run our web app from an IIS virtual directory on my own workstation (Win 2003 Server). Sporadically, the site map object won't get initialized, the result being that an exception gets thrown, with the associated error message:

The file web.sitemap required by XmlSiteMapProvider does not exist.

Needless to say, the file does exist and is accessible—so nearly all of the forum postings against this error message aren't very helpful. I don't have this problem when I run the app using the web server built into Visual Studio. A solution rebuild seems to make the problem go away for a short while.

I will post again if I ever figure out this problem.

11 April 2007

Software Tools

Shortly after I started working for Gary at Lupfer & Long, Peter lent me a copy of Software Tools, by Brian W. Kernighan and P.J. Plauger. Published in 1976, the book remains a classic text: beginning with programming in the small, the authors work up to the implementation of an automatic programming language translator—all in the span of fewer than 350 pages. Along the way, they illustrate the philosophy of the Unix operating system from the viewpoint of the applications programmer.

Granted, today's readers may find some of the material quaint, and be baffled by the absence of object-oriented concepts. The book was written at a time when structured programming and top-down design were key concepts of the curriculum, when programmers had to be cautioned against goto statements. (Dijkstra's seminal letter had been published only eight years before; it wasn't until decades later that the industry solved the goto-problem by devising widely-accepted languages that lacked the statement.) The book's power is that it accomplishes so much with nothing more than simple data structures, good algorithm design, and careful separation of function.

Kernighan and Plauger use a vendor-neutral language dubbed Ratfor (short for Rational Fortran) for their code examples. Influenced by the then-new language C (p. 318), Ratfor is a cleaned-up version of the various Fortran dialects of the era. In its lack of line-ending punctuation, it bears a slight resemblance to Python. Here is the word-counting program from page 15 (extracted from the source code, still online, astonishingly):


# wordcount - count words in standard input
character getc
character c
integer inword, wc

wc = 0
inword = NO
while (getc(c) ¬= EOF)
if (c == BLANK | c == NEWLINE | c == TAB)
inword = NO
else if (inword == NO) {
inword = YES
wc = wc + 1
}
call putdec(wc, 1)
call putc(NEWLINE)
stop
end


The book introduces the concept of programs as filters—again, something familiar to us but rather revolutionary at the time—very early, in Chapter 2, with examples like entab, which replaces strings of blanks with tab characters; translit; and crypt; as well as other analogues of Unix command shell utilities. The shell syntax for a pipeline caps off this chapter. And from there, the material ramifies. The full table of contents:

  • Preface
  • Introduction
  • 1. Getting Started
  • 2. Filters
  • 3. Files
  • 4. Sorting
  • 5. Text Patterns
  • 6. Editing
  • 7. Formatting
  • 8. Macro Processing
  • 9. A Ratfor-Fortran Translator
  • Epilogue
  • Appendix: Primitives and Symbolic Constants
  • Index of First Lines
  • Index


Those of us who subscribe to the "Code is Poetry" philosophy appreciate the felicitously-named "Index of First Lines." In this case, since the first line of every program is a comment describing its function, the index is a synopsis of all the code in the book.

For modern audiences, the book functions not so much as a general reference as it does as a guide to thinking about how to approach a programming project. (And yet, for those of us today who rely on class libraries to do our sorting for us, Chapter 4, with its functioning implementations of Bubble Sort, Shell Sort, and Quicksort, may be the only sorting reference we ever need.) Everything is explained in a clear, simple, no-hype style, one that infuses the several titles that Kernighan has co-authored. Here's an example from very early in the book (pp. 14-15), dealing with the chewy problem of static analysis and testing:


How should we test linecount to make sure it really works? When bugs occur, they usually arise at the "boundaries" or extremes of program operation. These are the "exceptions that prove the rule." Here the boundaries are fairly simple: a file with no lines and a file with one line. If the code handles these cases correctly, and the general case of a file with more than one line, it is probable that it will handle all inputs properly.

So we feed linecount an empty file. The while test fails the first time and the body is never obeyed. No lines are counted when none are input. Fine.

If we feed linecount one line, the while is satisfied for every character on the line; the if is satisfied when the NEWLINE is seen, and the line is counted. Then the test is repeated and the while loop exits. Again fine.

A multi-line file. Same behavior as for one line, only now we observe that after each line, the program ends up at the test part of the while—the proper place to begin handling the next line, or EOF. The program checks out.

This may seem like excruciating detail for such a simple program, but it's not. There are common coding blunders which could have caused any one of those three tests to fail, sometimes even while the other two tests succeed. You should learn to think of boundary tests as you code each piece of a program—try them mentally as you write and then physically on the finished product. In practice, the tests go much quicker than we can talk about them and cost but a little additional effort. It is effort that is well repaid.


The intended audience for this book was originally undergraduates taking a second course in CS, but anyone who has moved beyond Logo or Excel macros would benefit from the book, at least its early chapters. And all of us can use a gentle reminder about boundary conditions.

The volume is put together without distracting book designer tricks to pad out the page count: goofy icons, space-wasting figures. It's nothing but text and code, with exercises and bibliographic notes at the end of each chapter. It probably helps that the authors set the text themselves using a PDP-11/45-driven phototypesetter.

A version of this book with Pascal as the coding language appeared in 1981. The newer book perhaps makes it easier to get up and running with the code examples, but it lacks that nifty Ratfor translator. If you've ever thought that it would be cool to build TECO from scratch, pick up a copy of this book.

09 April 2007

New FogBugz plugin

I've just downloaded the FogBugz for Visual Studio 2005 plugin, and I'm taking it for a spin. Generally, I don't mind switching windows to get things done, and I find the multiplicity of tabs sprouting up in a Visual Studio window to be one big fumble. But I thought I'd give it try, anyway.