Colossal Cave Adventure was the origin of many things; the text adventure game, the dungeon-crawling D&D (computer) game, the MOO, the roguelike genre. Computer gaming as we know it would not exist without ADVENT (as it was known in its original PDP-10 incarnation).
A marvellous thing has just occurred.
Colossal Cave Adventure, the original progenitor of the D&D-like dungeon-crawling game genre from 1977 and fondly remembered as ADVENT by those of us who played it on PDP-10s, is one of the major artifacts of hacker history.
The earliest version by Crowther and Woods (sometimes known as 350-point Adenture) was ported to C by Jim Gillogly in ’77 just after it first shipped. That has been part of the bsd-games collection forever.
What I have have just received Crowther & Wood’s encouragement to polish up and ship under a modern open-source license is not the Gillogly port; it’s Crowther & Woods’s last version from 1995. It has 18 years of work in it that the Gillogly version doesn’t.
I feel rather as though I’d been given a priceless Old Master painting to restore and display. Behooves me to be careful stripping off the oxidized varnish.
My exercise in how small you can make a version-control system and still have it be useful, src, does seem to have a significant if quiet fanbase out there. I can tell because patches land in my mailbox at a slow but steady rate.
As the blurb says: Simple Revision Control is RCS/SCCS reloaded with a modern UI, designed to manage single-file solo projects kept more than one to a directory. Use it for FAQs, ~/bin directories, config files, and the like. Features integer sequential revision numbers, a command set that will seem familiar to Subversion/Git/hg users, and no binary blobs anywhere.
Maintaining cvs-fast-export is, frankly, a pain in the ass. Parts of the code I inherited are head-achingly opaque. CVS repositories are chronically prone to malformations that look like bugs in the tool and/or can’t be adapted to in any safe way. Its actual bugs are obscure and often difficult to fix – the experience is not unlike groping for razor-blades in the dark. But people expect cvs-fast-export to “just work” anyway and don’t know enough about what a Zeno’s tarpit the domain problem is to be properly grateful when it does.
Still I persevere. Somebody has to; the thought of vital code being trapped in CVS is pretty nervous-making if you know everything that can go wrong with it.
This release fixes a bug introduced by an incorrect optimization hack in 2014. It should only have affected you if you tried to use the -c option.
If you use this at a place that pays developers, please have your organization contribute to my Patreon feed. Some of my projects are a pleasure to do for free; this one is grubby, hard work.
Yes, to a certain segment of the population I suppose I define myself as a relic of ancient times when I insist that one can write good and absorbing computer games that don’t have a GUI – that throw down old-school in a terminal emulator.
Today I’m shipping a new release of the game greed – which is, I think, one of the better arguments for this proposition. Others include roguelike dungeon crawlers (nethack, angband, moria, larn), VMS Empire, the whole universe of text adventure games that began with ADVENT and Zork, and Super Star Trek.
I maintain a bunch of these old games, including an improved version of the BSD Battleships game and even a faithful port of the oldest of them all: wumpus, which I let you play (if you want) in a mode that emulates the awful original BASIC interface, all-caps as far as the eye can see.
Some of these I keep alive only because somebody ought to; they’re the heritage grain of computer gaming, even if they look unimpressive to the modern eye. But others couldn’t really be much improved by a GUI; greed, in particular, is like that. In fact, if you ranked heritage terminal games by how little GUIfication would improve then, I think greed would probably be right at the top (perhaps sharing that honor with ski). That in itself makes greed a bit interesting.
Much has been gained by GUIfying games; I have my own favorites in that style, notably Civilization II and Spaceward Ho! and Battle For Wesnoth (on which I was a developer for years). But the very best terminal games retain, I think, a distinct charm of their own.
Some of them (text adventures, roguelikes) work, I think, the way a novel does, or Scott McCloud taught us minimalist cartooning does; they engage the user’s own imagination as a peripheral, setting up a surprisingly strong interaction between the user’s private imagery and the bare elements of the game. At their best, such games (like novels) can have a subtle imaginative richness that goes well beyond anything this week’s graphical splatterfest offers.
More abstract puzzle games like greed don’t quite do that. What they offer instead is some of the same appeal as tiling window managers. In these games there is no waste, no excess, no bloat, no distraction; it’s all puzzle value all the way down. There’s a bracing quality about that.
Ski is kind of hermaphroditic that way. You can approach it as a cartoon (Aieee! Here comes the Yeti! Flee for your life!) or as a pure puzzle game. It works either way.
Finally, maybe it’s just me, but one thing I think these old-school terminal games consistently do better than their modern competition is humor. This is probably the McCloud effect again. I’ve laughed harder at, and retained longer, the wry turns of phrase from classic text adventures than any sight gag I’ve ever seen in a GUI game.
So, enjoy. It’s an odd and perhaps half-forgotten corner of our culture, but no less valuable for that.
UPDATE: I probably shouldn’t have described wumpus (1972) as “the oldest of them all”, because there were a few older games for teletypes like Hammurabi, aka Hamurabi (with a single ‘m’) aka The Sumer game from 1968. But wumpus is the oldest one that seems to be live in the memory of the hacker culture; only SPACEWAR (1961) has a longer pedigree, and it’s a different (vector graphics) kind of thing.
An important part of the Way of Unix is to try to tackle large problems with small, composable tools. This goes with a tradition of using line-oriented textual streams to represent data. But…you can’t always do either. Some kinds of data don’t serialize to text streams well (example: databases). Some problems are only tractable to large, relatively monolithic tools (example: compiling or interpreting a programming language).
Can we say anything generatively useful about where the boundary is? Anything that helps us do the Way of Unix better, or at least help us know when we have no recourse but to write something large?
Most hackers know how the twos-complement representation of binary numbers works, and are at least aware that there was an older representation called “ones-complement” in which you negated a binary number by inverting each bit.
This came up on the NTPsec development list recently, with a question about whether we might ever have to port to a non-twos-complement machine. To my utter, gob-smacked astonishment, it turns out ones-complement systems still exist – though, thankfully, not as an issue for us.
I thought I could just mumble something about the CDC 6600 and be done, but if you google “one’s-complement machines” you’ll find that Unisys still ships a series of machines with the brand “Clear-Path Dorado” (latest variant introduced 2015) that are emulations of their old 1100-series mainframes running over Intel Xeon hardware – and these have one’s-complement arithmetic.
This isn’t a practical port blocker for NTPsec, as NTP will never run over the batch OS on these things – it’s about as POSIX-compatible as the Bhagavad-Gita. It’s just weird and interesting that ones-complement machines survive in any form at all.
And a bit personal for me. My father was a programmer at Univac in the 1950s and early ’60s. He was proud of his work. My very first interaction with a computer ever was getting to play a very primitive videogame on the oscilloscope-based video console of a Univac 1108. This was in 1968. I was 11 years old, and my game machine cost $8M and took up the entire ground floor of an office building in Rome, Italy.
Other than the 1100, the ones-complement machines Wikipedia mentions (LINC, PDP-1, and CDC6600) are indeed all long dead. There was a ones-complement “CDC Cyber” series as late as 1989, but again this was never going to implement POSIX.
About other competitors to twos-complement there is less to say. Some of them are still used in floating-point representations, but I can find no evidence that sign-magnitude or excess-k notation have been used for integers since the IBM 7090 in 1959.
There’s a comp.lang.std.c article from 1993 that argues in some technical detail that that a C compiler is not practical on ones-complement hardware because too many C idioms have twos-complement assumptions baked in. The same argument would apply to sign-magnitude and excess-k.
UPDATE: It seems that Unisys is the graveyard of forgotten binary formats. I have a report that its Clear-Path Libra machines, emulating an ancient Burroughs stack machine architecture, use sign-magnitude representation of integers.
I haven’t announced a reposurgeon release on the blog in some time because recent releases have mostly been routine stuff and bugfixes. But today we have a feature that many will find interesting: reposurgeon can now read BitKeeper repositories. This is its first new version-control system since Monotone was added in mid-2015.
I’ve been thinking a lot about language design lately. Part of this comes from my quite successful acquisition of Go and my mostly failed attempt to learn Rust. These languages make me question premises I’ve held for a long time, and that questioning has borne some fruit.
In the remainder of this posting I will describe a simple syntax extension in C that could be used to support a trait-centered object system similar to Rust’s (or even Go’s). It is not the whole design, but it is a simple orthogonal piece that could fit with several different possible designs.
Here’s my first new project in a while – loccount, inspired by David A. Wheeler’s sloccount tool but much faster and with broader language coverage.
I actually wrote this as a learning exercise in the Go language. You can find more details in my NTPsec blog post on Grappling With Go.
If you like it, please remember that open source may be free but my time is not and join my Patreon feed.
In my last blog post I expressed my severe disappointment with the gap between the Rust language in theory (as I had read about it) and the Rust language in practice, as I encountered it when I actually tried to write something in it.
Part of what I hoped for was a constructive response from the Rust community. I think I got that. Amidst the expected volume of flamage from rather clueless Rust fanboys, several people (I’m going to particularly call out Brian Campbell, Eric Kidd, and Scott Lamb) had useful and thoughtful things to say.
I understand now that I tested the language too soon. My use case – foundational network infrastructure with planning horizons on a decadal scale – needs stability guarantees that Rust is not yet equipped to give. But I’m somewhat more optimistic about Rust’s odds of maturing into a fully production-quality tool than I was.
Still, I think I see a problem in the assumptions behind Rust’s development model. The Rust community, as I now understand it, seems to me to be organized on a premise that is false, or at least incomplete. I fear I am partly responsible for that false premise, so I feel a responsibility to address it square on and attempt to correct it.
I wanted to like Rust. I really did. I’ve been investigating it for months, from the outside, as a C replacement with stronger correctness guarantees that we could use for NTPsec.
I finally cleared my queue enough that I could spend a week learning Rust. I was evaluating it in contrast with Go, which I learned in order to evaluate as a C replacement a couple of weeks back.
I just shipped what was probably the silliest and most pointless software release of my career. But hey, it’s the reference implementation of a language and I’m funny that way.
Because I write compilers for fun, I have a standing offer out to reimplement any weird old language for which I am sent a sufficiently detailed softcopy spec. (I had to specify softcopy because scanning and typo-correcting hardcopy is too much work.)
In the quarter-century this offer has been active, I have (re) implemented at least the following: INTERCAL, Michigan Algorithmic Decoder, and a pair of obscure 1960s teaching languages called CORC and CUPL, and an obscure computer-aided-instruction language called Pilot.
Pilot…that one was special. Not in a good way, alas. I don’t know where I bumped into a friend of the language’s implementor, but it was in 1991 when he had just succeeded in getting IEEE to issue a standard for it – IEEE Std 1154-1991. He gave me a copy of the standard.
I should have been clued in by the fact that he also gave me an errata sheet not much shorter than the standard. But the full horror did not come home to me until I sat down and had a good look at both documents – and, friends, PILOT’s design was exceeded in awfulness only by the sloppiness and vagueness of its standard. Even after the corrections.
Yes, there was a bug in my vint64 encapsulation commit. I will neither confirm nor deny any conjecture that I left it in there deliberately to see who would be sharp enough to spot it. I will however note that it is a perfect tutorial example for how you should spot bugs, and why revisions with a simple and provable relationship to their ancestors are best
To do large code changes correctly, factor them into a series of smaller steps such that each revision has a well-defined and provable relationship to the last.
(This is the closest I’ve ever come to a 1-sentence answer to the question “How the fsck do you manage to code with such ridiculously high speed and low defect frequency? I was asked this yet again recently, and trying to translate the general principle into actionable advice has been on my mind. I have two particular NTPsec contributors in mind…)
So here’s a case study, and maybe your chance to catch me in a mistake.
The net benefit of having anything that can be called a software development methodology is in inverse proportion to the quality of your developers – and possibly inverse-squared.
Any software-development methodology works well on sufficiently small projects, but all scale very badly to large ones. The good ones scale slightly less badly.
One thing all methodologies tagged “agile” have in common is that they push developers away from the median. Competent developers work better; mediocre developers don’t change; incompetent ones get worse.
Software metrics have their uses. Unfortunately, their principal use is to create the illusion that you know what’s going on.
Structured development methodologies have their uses, too. Unfortunately, their principal use is to create an illusion of control.
Trust simple, crude metrics over complex ones because the simple ones are less brittle. KLOC is best, though a poor best.
Agile development is efficient only in environments where the cost of flag days is low. Otherwise, slow down, and take time to think and write about your architecture.
Good programmers are difficult to control; great ones are nearly impossible to control. Different methodologies require different kinds and degrees of control; match them to your developers wisely.
Process is not a good substitute for judgment; when you have to use it as one, your project is probably too large. Sometimes this is unavoidable, but don’t fool yourself about what that will cost you.
The difference between O(n**2) and O(n log n) really matters. It’s why lots of small teams working coordinated small projects works better than one big team building a monolith.
A million dollars is roughly a 55-gallon oil drum full of five-dollar bills. Large-scale software development is such a difficult and lossy process that it’s like setting fire to several of these oil drums and hoping a usable product flutters out of the smoke. If this drives you to despair, find a different line of work.
Haven’t been blogging for a while because I’ve been deep in coding and HOWTO-writing. Follows the (slightly edited) text of an email I wrote to the NTPsec devel list that I I think might be of interest to a lot of my audience.
One of the questions I get a lot is: How do you do it? And what is “it”, anyway? The question seems like an inquiry into the mental stance that a systems architect has to have to do his job.
So, um, this is it. If you read carefully, I think you’ll learn a fair bit even if you haven’t a clue about NTP itself.
While most of the NTPsec team was off at Penguicon, the NTP Classic people shipped a release patched for eleven security vulnerabilities in their code. Which might have been pretty embarrassing, if those vulnerabilities were in our code, too. People would be right to wonder, given NTPsec’s security focus, why we didn’t catch all these sooner.
In fact, we actually did pre-empt most of them. The attack surface that eight of these eleven security bugs penetrate isn’t present at all in NTPsec. The vulnerabilities were in bloat and obsolete features we’ve long since removed, like the Mode 7 control channel.
I’m making a big deal about this because it illustrates a general point. One of the most effective ways to harden your code against attack – perhaps the most effective – is to reduce its attack surface.
Thus, NTPsec’s strategy all along has centered on aggressive cruft removal. This strategy has been working extremely well. Back in January our 0.1 release dodged two CVEs because of code we had already removed. This time it was eight foreclosed – and I’m pretty sure it won’t be the last time, either. If only because I ripped out Autokey on Sunday, a notorious nest of bugs.
Simplify, cut, discard. It’s often better hardening than anything else you can do. The percentage of NTP Classic code removed from NTPsec is up to 58% now, and could easily hit 2/3rds before we’re done,
The British have a phrase “Too clever by half”, It needs to go global, especially among hackers. It can have any of several closely related meanings: the one I mean to focus on here has to do with overconfidence in one’s intelligence or skill, and the particular bad consequences that can have. It’s related to Nassim Taleb’s concept of a “fragilista”.
I’ve been getting deeper into timekeeping and calendar-related software the last few years. Besides my work on GPSD, I’m now the tech lead of NTPsec. Accordingly, I have learned a great deal about time mensuration and the many odd problems that beset calendricists. I could tell you more about the flakiness of timezones, leap seconds, and the error budget of UTC than you probably want to know.
Paradoxically, I find that studying the glitches in the system (some of which are quite maddening from a software engineer’s point of view) has left me more opposed to efforts to simplify them out of existence. I am against, as a major example, the efforts to abolish leap seconds.