A Library Story
or, How the STL Changed my World, by Dave Abrahams
To explain why I’m so passionate about libraries, let me take you back to 1995, when I was in charge of the development of a professional sheet music publishing software application.
It was fascinating work because the program’s requirements were so diverse. I got to think about user-interface design, system architecture, and portability, of course, but also more exotic problems like how to process input from a MIDI keyboard and translate that into intelligible notation in real-time (an AI problem that’s harder than it looks), and how to produce publication-quality printed output. To face all of these difficult design aspects at once was both exhilarating and daunting, because each one clamored for my full attention. I suspect this experience is familiar to many software engineers.
Addressing these challenges demanded software infrastructure, from basic data structures and algorithms—like dynamically resizeable arrays and fast searches—to support for memory management, MIDI I/O, undo/redo, serialization, rational arithmetic, error handling, GUI, and vector graphics. At the time I began this project, there were no libraries for my platform that could help me in these areas; any infrastructure I needed, I had to build myself. Looking back on the results today, I can see a few weaknesses.
First, some obvious infrastructure was just missing. In these cases, I had written ad-hoc low-level code in place and never designed the abstractions that would have kept the code maintainable. The effect is similar to what happens when you write object oriented programs with C instead of C++. You can do it, but it’s hard to manage.
What infrastructure I did have was limited in capability to just what my program had needed so far. For example, my dynamic arrays could only store certain kinds of data, or the program might crash. That was fine as long as I was the only one working on the code, or the code was adequately commented to alert the unsuspecting maintainer, but, well…
There had been no time to fully document the code.
Undocumented components always make a program brittle under maintenance, because there’s no clear boundary between stable interface and changeable implementation detail.
As the demands on infrastructure expanded, these components evolved by accretion, not by design. When some new capability was needed, the answer was to “glom on” a new part rather than go back and reconsider the abstractions I was using. Also, the components themselves were one-offs. There were no unifying idioms, and in some cases they didn’t interoperate well with one another.
Finally–and I hate to admit it–my infrastructure was buggy. How many times did I have to tweak my binary search algorithm before we stopped finding cases that failed? I lost count.
I truly believe that none of these problems occurred because I was a bad programmer. My job was to produce shrink-wrapped software products, not to build libraries, and I was eager to show real results. I think that’s true of most developers.
Great programmers are focused on solving problems in their application’s domain, not on writing reliable, efficient, general-purpose building blocks.
Eventually, any structure pays a price for having a weak foundation, and my program was no exception. As you might expect, adding new features and bugfixes became increasingly difficult because my software building blocks were no longer suited to the job. There was also a subtler effect: thinking about infrastructure design problems had been costing me valuable brain cycles that I ought to have been spending on difficult problems specific to music publishing software. It became a daily challenge to think less.
Fortunately, the STL came along and changed everything. It gave me reliable containers and algorithms with clearly documented requirements and guarantees. Instead of being limited to just a couple of data structures, I now had a variety of capability and performance tradeoffs to work with, so I could choose the components most appropriate to the problem at hand. Because the STL was on the standards track, I knew that when I used it I would be speaking a future “lingua franca” that maintainers would understand. Everything in the STL was based around an elegant idiom, the iterator, ensured that the components were all interoperable, and yet, somehow, they were not highly coupled. I could use STL algorithms on my existing data structures, for example.
Perhaps most important of all, the simple, well-chosen idioms of the STL established a framework for my own design choices, so that programming required less thinking and I was better able to focus on the problems in my own application domain.