How Software Is Built Today
I spent about a day this week polishing a detail of Tinderbox Six. I’d like to walk you through some of the design because it’s interesting and accessible, and because I think it demonstrates why our expectations of software are leading us into such a terrible mess.
Under the hood, this feature is called Tansey Tabs, named for the distinguished university administrator who first suggested it. Tinderbox encourages you to open lots of windows on different facets of your document. You might have a map of the section you’re working on, an outline of references and sources, another outline of tasks remaining to be done, perhaps a treemap overview of everything. This gives you lots of flexibility and lets you tailor your workspace. But using lots of windows can sometimes be tricky, and increasingly it’s not something people discover for themselves; why not use tabs within one window to provide quick and easy access to as many views as you need?
This isn’t off the shelf, but that’s OK — we’ll just build it, it’s not rocket science. And it’s a feature that’s nice, not one that’s essential. Lot’s of people won’t use these tabs.
So, what do we need to think about when adding a bar of tabs like this?
- The whole point is to have a view state that summarizes what you’re looking at and how it’s presented. You want to switch between view states. So we need a new object that encapsulates the View State, methods for updating the view state when the view changes or you switch tabs, methods for allocating memory for the view state and cleaning up afterward.
- You need a bar in which the tabs live. That bar needs to have something drawn on it, which means choosing a suitable gradient or texture.
- The tab needs a suitable shape. That shape is tricky enough to draw that we define an auxiliary object to frame and draw it.
- Whoops! It gets drawn upside down! Slap head, fix that.
- We need a way to add new tabs. Make a subtle button, attached to the right edge of the tab bar. Make sure that the tabs are arranged so the button won’t be covered by tabs, even if there are a ridiculous number of tabs.
- The tab needs a label. That also means choosing a font, color, and type size.
- When a tab is clicked, we need some feedback. So, while the mouse is down, we’ll change its color slightly and change the label color as well.
- The currently-selected tab needs to be distinguished. It has a lighter color. And, because it’s notionally in front of the other tabs, perhaps it needs a slightly more pronounced shadow.
- We need a way to delete tabs we no longer want. It’s easy enough to add a close button to each tab, but that adds a lot of visual noise. So, we’ll only show the close button when the mouse is over the tab.
- There’s always a current tab, the place where the view you’re looking at puts its view state. So you can only delete other tabs, not the current tab. This requires a little extra logic.
- Tabs needs to be saved with the document. That means we need to be able to encode a ViewState as XML, and we need to be able to read that XML and create a ViewState from it next year. And this needs to be done right, because if you make a mistake in the XML, you’re going to be writing code to work around it next month — and you’ll still be working around that mistake in ten years.
- As soon as you save a file and start to actually use the tabs, you realize that you want to reorganize them. Everyone will want to reorganize them. So, allow the user to drag a tab inside the tab bar to change the order of tabs.
- If the user drags tab A over tab B, the tabs swap places in the bar. This might look nicer with an animation, so try one. It does look nicer. Now, when tab B moves to its new place, does it slow down when it gets close, like a car applying the brakes? Or does it speed up, like a magnetic clasp? How fast should it move?
- If the user drags tab A all the way to the right, it’s over the place tab 7 would be if there were a tab 7. But there isn’t a tab 7, so we crash. There’s no tab −1 either. Fix those.
- If the user clicks too forcefully, the tab thinks it’s being dragged, not clicked. So, treat tiny drags as if they were clicks.
- That’s functionally good, but now clicking the tab makes the tab jiggle a little bit. It doesn’t feel solid. At this point, I’m getting to hate tabs. But let’s add logic so the tab doesn’t move until you’ve clearly started to drag it, and then “tears off” to catch up.
- Writing “Outline” or “Map” on each tab makes the kind of view clear, but it takes up a lot of space. Let’s add an icon or thumbnail that shows a little bit of what the view looks like. The obvious approach is to draw a tiny picture of the view. Getting this to look good seems to require more vertical space than I’m willing to spend on this feature.
- It turns out that the thumbnails look pretty terrible. Instead, we’ll hand-draw the icon. We use the color scheme from the selected view as a hint. We could go further and draw a highly abstract picture of the view, optimized for a tiny space. Put that on the ToDo list.
- Today’s computers have several processors, so we can ask another processor to help out when we need to set up a new view. And when the view changes, we can animate the transition. But with lots of tabs, we might click tabs so quickly that we start setting up a new view, begin a lot of animations, and then switch tabs again before those animations are done. Yikes! And what if you asked for a wakeup call when the animation was finished? And then the user closed that tab? Now, you’re gone and there’s no one to answer the call. Crash!
- And we need some additional unit tests to ensure that all of this continues to work as the ViewState object and the views that use it change.
This is a hell of a lot of design and implementation for a small feature. The old answer was “reusability,” but that’s no good; we need more than NSSegmentedControl can give us.
This kind of detailing gets lots of attention in the tech press, because it’s thought to be a secret of Apple’s success and talking about (or against) Apple is always good for circulation.
This is a hell of a lot of design and implementation for $0.99. But that’s increasingly what people expect to pay for software. OK: maybe $19.95 for something really terrific. But can you sell an extra 100 copies of the program because it’s got draggable tabs? If you can’t, don’t you have better things to do with your time?
This is a hell of a lot of design and implementation for an auxiliary feature. Tinderbox isn’t about tabs. Tinderbox is a tool for notes, for visualizing, analyzing, and sharing. Tabs are just a nice things that some people will use and others won’t. And some people will give you 1-star reviews because they don’t like the shadows, or the typography looks bad in Sanskrit. There’s always something you forget.
But it can be done. One day to implement the tab bar. One day for dragging and saving tabs. OK: a pretty good day both times, but just a day. And if I can just string about 270 of those days together, we’ll be ready for beta.