Last year, I worked my way through Lisp In Small Pieces, implementing several variants of the Lisp engine Queinnec described, most of them in Coffeescript. I’ve decided this year that I’m going to continue building out my language experience and write a scripting language. I’m still working out the details, but I’m working my way now through Scott’s Programming Language Pragmatics while reading a lot of extra stuff on the side.

One of the gems I found recently was a copy of the Smalltalk-80 Implementation Guide. It is, to say the least, a fascinating book. It introduces a virtual machine in the context of programming in 1980, which was 37 years ago, and the assumptions the authors make as to what I’m expected to know as a potential developer of a Smalltalk environment fascinated me.

The book describes a stack-based, tree-walking virtual machine. As Smalltalk is a purely object-oriented language, the tree is completely reified by the OO environment; you choose an object and a function to start, and the interpreter walks that function’s statements and subroutines until execution ends at the end of the start function. Methods are dispatched according to a lookup table, and primitives are encapsulated in a large switch() statement.

What fascinates me about reading this is that I know, at least theoretically, so much more about writing VMs. The VM described here is a nightmare of cache misses and branch prediction failures; fully a third of a modern CPU’s efforts will be going into loading, evaluating, and then disposing of anticipated operations that the VM will throw away unused. There’s no mention at all of JITting the program’s functions (converting long sequences directly into machine code) or even just its spine (writing the sequence of primitives as indirect, or even direct, unconditional branches such that the CPU’s branch predictor works most of the time; direct is cool but requires the primitives themselves be copied and modified for direct uncoditional branching back to the spine).

Since in Smalltalk almost any object could be a launching point and since relationships between objects can be changed with the swipe of a mouse, the speed with which we’d have to recalculate any given set of relationships would have to be a priority. It would have to have Go’s internal speed of recompiling, only to put the results into an executable anonymous mmap()’d space, and then map everything than needs it to be able to find that code.

A modern Smalltalk VM could be a marvel to use. It would be a nightmare to write.

Be that as it may, choosing to write programming languages today, even ones on top of a system language like C or Rust, is to confront an embarrassment of riches. There are so many interesting ways to do something now. We have JITs! We have Algorithm W! We have concurrency problems like you wouldn’t believe! 37 years ago, they had two options: compiled code, or a stack-based switch statement on top of compiled code. The writers assumed you knew more about those two ways, and absolutely nothing about all the other stuff.

Joe Wright has an excellent blog post about Anti-If Patterns that I naturally believe everyone who write programs ought to read, but there’s a detail that’s missing that I think is absolutely crucial to getting anti-if programming correct.


Yeah, you can yawn and leave now, if you don’t care. But I’m with Guido von Rossum on this, that once your software reaches a certain size the only way to stave off chaos is to demand more of the programmer up front, and that demand comes in the form of requiring programmers to understand the shape of the data, and to make sure that the pieces being passed between units of code fit perfectly.

Wright glances off the issue in his second pattern, “Use polymorphism instead of switch().” This is a common piece of advice, although it really only works when you have more than one switch statement; at that point, your switch statements are collections of methods that apply to different objects.

It’s his first (Boolean Params) and fourth (Conditional Expressions) patterns where he falls down a little. The most critical issue in both of these is the shape of the data. “Boolean Params” is just “Conditional Expressions” written as a lookup table. If we play the classic programmer exercise of zero, one, or many, a lookup table is a conditional expression taken from the “one” state to the “many” state. It is therefore absolutely critical to put your foot down and state for the record, In any conditional expression, for all sub-expressions, all left-hand values must share the exact same type, and all right-hand values must share the same type.

If this isn’t the case, you’ve created a way to sneak if back into the system, with separate code paths that must be unit tested. And down that road lies madness and unreliability.


The DIM Epiphany

Posted by Elf Sternberg as Uncategorized

When I was 13 years old, I laid my hands on my first true computer. It was a DEC PDP-11/44, later upgraded to a PDP-11/70, running RSTS/E and the BASIC/PLUS shell environment. Live every teenage boy, I started out by writing video games. Bad ones, naturally, since all we had was the ANSI escape codes on a black-and-white monitor. And while my code kinda worked, there was a statement in the BASIC language that escaped my insight. DIM.

DIM A(100)

I really didn’t “get” what this statement meant or why it was necessary. Indexing didn’t make any sense to me at all. There wasn’t anyone to explain it to me, and the magazines and books I had weren’t helping. It was literally a year before I finally had an epiphany: DIM was creating a row of boxes in which to store things, and the index numbr let me say which box I wanted. Variables were no longer just storing things; they were storing things that pointed to other things.

I had to visualize it before I understood it.

Djikstra once said that “As potential programmers, students who have had prior exposure to BASIC are mentally mutilated beyond hope of reconstruction.” While that may sound a little harsh, I suspect there’s some truth to it. For years that need to be able visualize what a program was doing before I could trust that it was correct hampered me from moving forward with a lot of different and interesting projects. To this day, I still feel like I need concrete, working examples of something before I understand what it’s doing.

It gets worse when I’m working with highly abstract material. Learning to trust that singly linked lists do what they’re supposed to do was actually hard for me. It took more than a dozen tries, and to this day if we get past five links of responsibility I have to find a way to abstract the thing I’m working on into a singular concept, beating it into my brain that it’s okay, that chunk of code is going to do what I want it to. I want to know down to the electrons flowing through the wires what’s going on with my code.

A friend of mine, a highly accomplished mathematician in his own right, is fond of the notion of notation as a tool for thought, and that getting past the need to visualize is a critical stage in mathematical thinking. That’s probably true, and I fear I’ll never get past that critical stage. Indeed, at my age, it may already be too late.

That’s not going to stop me from trying, of course. I am not going to treat programming as applied demonology, which is what most developers do these days.  Giving is just not in my nature.

I wrote an example of Bob Nystrom’s “Baby’s First Garbage Collector,” which I’ve been wanting to implement for a while in order to understand it better. To make the problem harder (as I always do), I decided to write it in C++, and to make it even more fun, I’ve implemented it using the new Variant container from C++17.

I’ve never written a garbage collector before. Now I know what it is and how it works.

The collector Nystrom wrote is a simple bi-color mark-and-sweep collector for a singly threaded process with distinct pauses based upon a straightforward memory usage heuristic. That heuristic is simply, “Is the amount of memory currently in use twice as much as the last time we garbage collected?” If the answer is yes, the collector runs and sweeps up the stack.

Nystrom’s code is highly readable, and I hope mine is as well. Because I used Variant, my Object class has an internal Pair class, and then the Variant is just <int, Pair>, where “Pair” is a pair of pointers to other objects. The entirety of the VM is basically a stack of singly-linked lists which either represents integers or collections of integers in a Lisp-like structure.

The allocator creates two kinds of objects, then: pairs, and lists. A pair is created by pushing two other objects onto the stack, then calling push(), which pops them off the stack and replaces them with a Pair object. The VM class has two methods, both named push(), one of which pushes an integer, the other a pair. Since a pair is built from objects on the stack, the Pair version takes no arguments, and since C++14 and beyond have move semantics that Variant honors, Variant<Pair> only constructs a single pair. Pretty nice. I was also able to use both lambda-style and constructor-style visitors in my Variant, which was a fun little bonus.

In the end, this becomes a pair of linked lists with different roots; one pair can orphan the lists, the other can’t. We traverse up the spine of the stack, following each scope’s list and marking the objects as found. We then traverse the other list and, for every object not marked, we get a pointer to it, collapse the list around it, and delete it. Very simple and elegant.

I hope, eventually, to move onto tri-color, multi-threaded garbage collectors someday. According to Nystrom, this garbage collector is the actual algorithm used in early versions of Lua, so it’s not a toy.

I have included the header files for the Mapbox version of Variant since the C++17 committee’s standards haven’t quite reached the general public and the Variant implementation is still a subject of some debate. This implementation looks straightforward enough and is a header-only release. It works with both GCC 4.8.5 and Clang 3.8, and that’s good enough for me.

The Mapbox variant is BSD licensed, and a copy of the license is included in the Include directory.  The source code is here.


From the base directory of the project:

mkdir build
cd build
cmake ..

And you should be able to run the basic tests. It’s just one file. Unfortunately, I was simpleminded with the include paths, so it can’t be built anywhere but from the base directory without fiddling with the CMakeLists.txt file.

At work, I’ve earned a bit of notoriety for being a code style commisar. I’ve been part of the group that from the bottom has been pushing people ot use flake8 and eslint, and I even wrote a tool to make polyglot testing easier. My latest kick is types. After experimenting with them for two years, I’ve decided that they do make a difference, a huge difference, in the quality of code. They won’t catch every bug; today I discovered that a documented defaulting option hadn’t actually been included in the parser I’d written. Yay for unit tests. But also: yay for types. By switching to types, and actually using them, I’ve discovered where my thinking was weak and vague. Type checking is a constraint. Great art is always made within constraints.

It’s still not enough. You have to have good taste. You have to have an aesthetic sense for how the code communicates. You need to design everything. Design adds clarity. It’s not enough to make it work. I tell people you need to design and write, then redesign and refactor, every project, and you need to book time into doing so. Function and variable names need to be clear and communicative– keep a thesaurus. in your bookmark bar! If you’ve got an excessively clever bit of code, break it into smaller units and name them with variable and function names. If your company has a preferred organization for classes and modules, use it consistently. If not, use an organization that best tells a story. Use nested functions to isolate unique functionality. Do the same thing with the filenames in modules.

This stuff takes practice.

There’s a saying in software design that I have come to loathe: “Write your code as if the guy who has to maintain it is a violent psychopath who knows where your desk is.” I heard a guy up from the San Francisco office say this the other day and my reaction was, “Nobody works well when they’re afraid. If you want great software, you have to have, like, Buddha-levels of respect for the next person.” I then went into a (small part) of my rant above.

I guess I must have been rather forceful and passionate in my defense of good taste in software design, but he next said, “Why do you care so much?” I found the perfect formulation:

Programmers work at the limits of their understanding, with their brains full. Maintaining code is harder than writing it anew because you have to understand what the original writer was trying to do while they were writing code at their limits. If you have respect for the next person who has to modify your code, including the skills they’re likely to have, then you will write software that’s as clear and easy to understand as you possibly can. This means that any problems, any future extensions, and any customer requests can be met in hours instead of days, or days instead of weeks. The maintainer is happy because they aren’t frustrated by code ugliness or made to feel stupid by excessive code cleverness. Instead, they can fix the problem easily so they’re happy. Happier maintainers get stuff to market faster, and that makes customers happy. Happier customers buy more of your stuff. That makes stockholders happy. Happier stockholders reward you with bigger raises.

Aside from the money, I’m happier when I feel pride in my workmanship. Don’t you?

In my ever-shrinking spare time, I write stories. When I’m writing a particularly long story, or dabbling in the 300-odd episodic space opera I’ve been working on for twenty-five years or so, I have to read and re-read the story to make sure that every plot thread of the story has been closed in a satisfying manner, every macguffin has been stowed away, and every character’s character has been fully revealed and shows consistency throughout. Even then, when I go back and re-read some of my work, I see lines that were supposed to lead somewhere, but didn’t, and sometimes a character says something about an event in the past, but the actual scene being referenced has been cut out for whatever reason.

Even in the best books, while the main plot remains resolved, a sub-plot might not actually be completely hooked up. The most famous of these is in Raymond Chandler’s The Big Sleep: we still have no idea what happened to victim Owen Taylor.

Human beings can forgive an omission like that if something else about the book is good. For Chandler, it’s all about style, and the style he invented, private detective noir, is breathtaking in its originality.

Computers, on the other hand, are spare and unforgiving. If a user forgets to hook something up, a crash is inevitable. It’s only a matter of when and where.

I recently praised MyPy, a new type hint system for Python that, I claimed, eliminates an entire class of errors while writing Python.

I think it’s important to emphasize how important I think MyPy is, because here’s the horrible truth: computer programmers have no idea what they’re doing.

Imagine, if you will, a newly installed private inventory management system (PIMS) for a large company. Different offices will send you spreadsheet of data, rows of inventory, and column headers to describe what the rows mean. Meaning is the most important thing here; computers are just glorified calculators, it’s human beings that apply meaning to what they’re doing.

Without the column headers, though, a row of spreadsheet data is meaningless. It’s just numbers and names. A human might be able to guess that the column with entries like “New York” and “Boston” is cities, but what do all those numbers mean? And without specialized software, the computer doesn’t care about cities at all; they’re just strings of letters.

The PIMS system lets you upload the spreadsheet, and then you, the human, apply meaning. “That’s a computer.” “That’s a piece of software.” “That’s a chair.” Programmers tend to abstract things to their basics. “Computers and chairs need to be shipped; software can just be sent via email; real estate can’t be transferred at all.” That sort of thing. Inventory may have location, and ownership: “That is Bob’s chair in the Chicago office.”

So here’s the horrifying truth: most programs, internally, don’t apply any meaning to what it is they’re handling. This means the programmer didn’t apply meaning. The programmer had meaning in his head, but was so busy getting from input to output, applying that meaning and rules along the way, trying to hit a deadline, that encoding that meaning in the code gets lost. A spreadsheet starts out as rows of hand-labeled columns; it ends up in the database as entries in various hand-labeled tables of rows and columns. In the middle, it lives as blobs.

Blobs. That’s it. A Python list or a Javascript array is arbitray: it can contain lists of anything: numbers, strings, other lists, a mix of all of the above. The same is true of the dictionary. They’re just “objects”; they have no meaning. The programmer writes functions that handle ListsOfShippableThings, which in turn calls functions that handle OneShippableThing, which in turn call a TransportCompany, and so on. But what he passes them is a List. He could accidentally call ShipShippableThings with a List of RealEstateThings. That might be found in testing; it might be found when someone tries to ship something; it might actually work, in that an InventoryItem is marked to be shipped even though it’s a square city block in downtown Manhattan!

Almost all web software is written this way. We call it “Duck Typing:” if it walks like a duck and quacks like a duck, it’s a duck. If a RealEstateThing is an inventory item with a location, the ShipShippableThings function might say, “It’s an inventory item at a place, yep, we can ship that.”

The beauty of MyPy and Typescript is that, with good taste in naming things, and proper training, you can’t write software where you try to ship a RealEstateThing; long before the code runs, your editor or repository checker will say, “You have code here where you’re passing a RealEstateThing to a TransportCompany through ShipShippableThing. That doesn’t make sense.”

And it doesn’t. But when you’re a programmer, it’s easy to forget, in the hundreds of things you might be keeping track of, you might just try to run everything through “CheckIfNeedsShipping” code, never realizing that your list contains things that can’t be shipped.

There are all sorts of examples. Grocery stores have things that can’t be eaten and don’t spoil; pharmacies are full of things that can’t be injected. Constraint is one of the most powerful ideas in computer science, and when we wrote software that freed us from the constraints of having to tell the computer how much memory we needed for an object, we also lost the constraints we had on having to describe that object clearly.

I was very disappointed when I read Eric Elliot’s You might not need Typescript (or Static Types), because he claims that Typescript, and its constraint checking, slowed him down and didn’t reduce bug count. He talks about how typing is “distracting”; his developers would rather just use blobs of text that know exactly what they’re passing around. He says unit tests are a great way to know if his code is working, but that’s true only if he tests the right things.

I’ve been writing in Javascript and Python for twenty years now. (Not kidding about that, either. Seriously. In 1996 I’d been working in Perl for four years professionally already.) Nothing, and I mean nothing, is more exciting, more useful, and more indicative that the software industry is finally growing up than the popularity of static typing for these languages.

Elliot describes duck typing as “checking that looks at the structure of a value rather than its name or class.” In older, rigid languages like C and C++, a similar thing is called Structural Typing; it doesn’t matter what I, the programmer, claims that thing is; all that matters is that it has the right layout in memory. If coincidentally the “PizzaDeliveryGuy” and “LaunchNukesOrders” have similar layouts in memory (Maybe a launch code is the same number of bytes as a phone number!), well…

What MyPy and Typescript do is called Nominal Typing. Computer functions are about intent. “I intend to order a pizza.” We teach how to name functions because we want to clearly communicate intent. The same thing should be true of the data we work on: it should describe what it encapsulates.

I have no idea how big Elliot’s programs are, or how much time he spends trying to figure out why something crashed. Nominal typing has reduced the amount of time I spend it on by half. To me, that’s a strategic benefit no amount of “go fast and break things” will ever match.


If you write Python, you should use MyPy.

Posted by Elf Sternberg as Uncategorized

I’ve discovered MyPy at work, and it works with Python 2.7 so amazingly well that I’m here to say, if you haven’t added it to your workflow, you need to immediately.

The last project I worked on at my day job, an automated inventory and services manager, was 2200 lines of one class object. When I was done, it was 1800 lines and 145 functions split over ten files, with separate classes for services and inventory, intake and output, local and network transformation, authorization, and utility. It’s primary purpose was to take in CSV (comma separated values– the text format for spreadsheets) and output JSON. We wanted to add other input formats, we wanted the output to be able to handle different formats as well, and we wanted to move the network transformation phase to an asynchronous handler with recovery-on-failure.

Doing that took a lot of heavy lifting. Figuring out what functions were for, what the dataflow looked like, what each step of the transformation required, how to handle conflicts with objects already in the inventory. Like most shops, we have rules about how to use docstrings that look a lot like jDoc, but by complete luck I found PEP-484 and MyPy the program that actually does Python type-hint checking, and immediately started using it aggressively.

The internals of the original, a one-off written for a single customer, had very strong assumptions about CSV inbound and JSON outbound. Functions were literally named with csv_ and json_ prefixes, even though internally everything was just Python dictionaries and lists!

I named things, and by their purpose: Classes called InventoryItem and TrackingService. I named collections of things. I named containers. And I added MyPy type hints to everything, like this (Code is from a personal project, mp_suggest, an early MP3 inventory manager I wrote a while ago.):

def make_album_deriver(opts, found, likely):
    # type: (Dict[Text, Text], Text, Text) -> Text
    if 'album' in opts:
        return opts[u'album']

    if 'usedir' in opts:
        return found

        return (ascii_or_nothing(likely) or sfix(found))

That little one-line comment there guarantees that anyone calling this function must send it what’s listed in the type line, and nothing else. MyPy will track back and make sure that the variables passed by the caller are actually created as a dictionary, a string, and a string! It will track forward and make sure that the receiver always uses the results as a string! It will ensure that the dictionary is created with strings as keys and values— no lists, no sets, no nested dictionaries are legal values. It will make sure that ascii_or_nothing and sfix take strings and return strings.

Programmers in dynamic, duck-typed languages like Python (and Javascript, Perl, Ruby, even Lisp) tend to assume we know what we’re doing. Given a problem, we come up with a solution, and then we start coding toward the solution, as if building and assembling a jigsaw puzzle along the way. On a very big project, we can miss things. Often, what we miss is error handling and corner cases. We can write a function and twenty minutes later call it, all the while assuming we can correctly remember what the calling protocol was. Often, we are wrong, and learning we’re wrong is sometimes a painstaking effort in type management. I believe half my debugging time is being a human typechecker: “Wait, it’s supposed to be passing back class X, but I’m getting a list. Why?”

PEP-484 eliminates all of that, and that makes PEP-484 the biggest leap forward in high-quality Python development since PEP-8. By eliminating the single most common class of running errors in all of Python, you can double your productivity. If you are not using MyPy, you are at a tactical disadvantage, and you will remain so until you adopt it.

Infoworld has an article entitled “The seven most vexing problems in programming.” The first two are “multithreading” and “closures.”

I call bullshit. Neither of those are hard problems. Both of those are problems of programmer laziness. (Not compiler laziness, of which I’ve recently become a fan.) It’s really hard to believe closures are a problem when we’ve had object oriented programming for over thirty years now and classes are nothing more than a specialized syntax for describing a closure.

You know what’s really broken about these two issues? Mutation. Objects (in the abstract, categorical sense, rather than the OO sense) changing and being changed in the code in such a way that it’s impossible to reason about the code in front of you. It’s impossible to say “This is what the object is.” It’s impossible to say “This is what this function does.”

There are times and places where mutation has a place, but they’re actually exceptionally rare. Mutuation can be used when performance is the only thing that matters; but if performance is the only thing that matters, then locks, semaphores and monitors are the performance drags and your code shouldn’t be involved with them.

Wayner’s complaint is wrong. These issues aren’t hard. These issues exist because programmers have been taught poorly. They’ve been taught that in-place mutation is the right way to do these things. They’ve been taught that lock-free data structures are “too hard” (but apparently debugging multithreaded is just fine). They’ve been taught to save unnecessary microcycles at the expense of their employers time and money.

The other day I debugged someone’s code where he looped through a very large list of objects. There was a bug where some of the first items didn’t get saved to the database with all the data the specification required. I discovered that he was pulling new data from the database every iteration, and saving some of it in a mutating array. Eventually it had enough data to do the job right, but not at the very beginning. When I asked him why he did it that way he said, “I’d have to iterate through the data twice, once to get all the keys, then to perform the updates. This was more efficient.”

It was also broken. “You mean, you accumulate mutations as you go along?” I said.

“Yes.” And then he broke out into a grin. “Isn’t that called evolution?”

“No,” I said. “99.999% of the time, that’s called cancer.”

And so it is with most programmers these days. They think cancer is preferable to thinking harder about the problem. I blame Python and Ruby, where mutation is easy, cheap, and often “gets the job done,” but makes it much harder to understand what the Hell is going on underneath the code.


“Huh. So UML is actually useful?”

Posted by Elf Sternberg as chat, Design

Since I’m generally opposed to giving Hacker News oxygen, I refuse to comment there on a recent question, Do You Still Use UML?

As I’ve made clear, I have both anxiety and confidence about being an older developer in this world of high-tech startups and high-speed, high-burnout “only twentysomethings can do anything” world. Bloomberg the other day pointed out that almost all productivity gains over the past four years are in the hands of people like me, folks in our forties or later, folks who know stuff, folks with experience.

Anyway, to answer the question: Yes. When I was at CompuServe, they were kind and crazy enough to go through a full-on UML phase. It was a huge drag and it produced terrible software, mostly because the powers that be thought they could buy Rational Rose and jump straight into Class Diagrams and Sequence Charts without, you know, actually caring if anyone on the team knew about SOLID, DRY, KISS, YAGNI, etc. (I heard a great one the other day: TYKD, pronounced “Ticked:” Test, YAGNI, KISS, DRY. An acronym of acronyms.) The promised productivity never showed, and we ditched it after a year or so.

This cycle I have the responsibility for developing a fairly complicated piece of data analysis software, and while trying to describe my ideas for it, other members of the team weren’t getting it. Desperate to make myself clear, I actually plunked down $70 for a piece of UML software (StarUML, and pretty good, actually) and designed a sequence diagram to show how I expected the system to work with failures and fallbacks clearly described.

It was a rough diagram, and it had some ad-hockery because UML was designed before asynchronous and reactive programming became a thing. But when I showed it to my review committee, they were like, “Wow. That really does explain what’s happening here. That’s amazing. What is this?”

I explained what it was, and the reaction was, “Huh. So UML is useful?”

They approved my project quickly, and things are underway. And so far, it really is looking much like what I drew, which is fabulous. But I was able to get approval because I had bothered to learn UML.

Because I know things.


Will there ever be a Flying Shuttle for Software?

Posted by Elf Sternberg as chat

Fred Brooks once famously wrote that there was no silver bullet for software development. Once a project and its tooling were agreed upon, software development took the time that it took. Brooks’s insight was that software developers spend their days more or less at the limits of their intellectual capacity, and no amount of tooling or management could expand that limit. Since a developer is usually fully engaged with any given task, adding a second developer to that task will actually slow production down: the two developers now have the overhead of communicating with each other the nature of the task and each may be blocked by the other to accomplish a signifcant subtask.

The term for this “No Silver Bullet,” and the book by that title has gone on to be a perennial best-seller, usually purchased by harried software developers and left anonymously on the desks of clueless project managers.

Treadle-based handlooms for weaving cloth have existed for almost two thousand years, and their current form is unchanged from the one that emerged in Germanic and Italian forms a thousand years ago. A loom has a frame of vertical threads in two alternating sets; each press of the foot peddle pulls one set apart from the other, and the user strings a spool of thread called a “shuttle” across this horizontally, then cycles the foot peddle to close the lifted threads down, then lift the other set up, giving the weaver that alternating over-under sequence that holds cloth together. Skilled users were known to “throw” the shuttle across the loom field, but cloth could only be woven as wide as one person could reasonably reach.

In 1733, a man named John Kay built a narrow wooden track, put the shuttle into the track, and with a piece of string and a handle, “jerked” the shuttle back and forth across the loom field. A few improvements later, he had made a loom three times as wide as existing looms, and one that could be operated twice as fast. Kay’s “flying shuttle” replaced the thrown shuttle almost instantly, and the industrial revolution had its first major component.

The more I write software, the more I have this sensation that something is very wrong with the way we write software. I listen to developers describe their projects and my overwhelming thought is, “Didn’t someone do that already?” I can’t begin to count the number of times I have implemented the same small algorithms over and over. Consider Stack Overflow, in which questions “How do I find a substring?” has several different code snippets that dozens of people will now simply cut and paste into their own code. Programmers get paid like princes these days mostly to know how to know these things, and glue them together in the right order for our corporate masters, and make them work profitably.

If there’s No Silver Bullet, could there be a Flying Shuttle waiting for us? I don’t have an answer, but I fear that there is: there’s an answer that glues everything from the hardware to the UI together into a meaningful whole, that answers the questions people want answered, and does the things people want done. I suspect it’s already here; we just haven’t identified it for what it is yet.

Subscribe to Feed



November 2017
« Oct