Overriding Scrollbar Behavior in OS X

ScrollbarI recently ran into a situation where I wanted to significantly customize the behavior of a scrollbar in a Cocoa WebView and was disappointed in how little access I had to it. There are two factors that complicated my situation. First was the fact that the text I was displaying in the WebView was being loaded dynamically. As the user scrolls up or down, Javascript methods call into my Objective-C code to request additional blocks of text to display either above or below the text already displayed. As the user scrolls up (or down), blocks that are “too far” below (or above) the displayed text are removed by the Javascript on the page. As a result, the built-in WebView scrollbar is displaying completely irrelevant information.

Second, the feature of OS X 10.7+ that allows the user to control whether or not scrollbars are always displayed interfered with my attempts to simply drop an NSScroller on top of the region of the WebView where the scrollbar appears. If the user turned on “overlay scrollbars”, the WebView would re-wrap the text so that it continued under my scrollbar. On top of that, when the system drew its scrollbar, it would draw it on top of mine, even though mine was on top of the WebView in z-order. Furthermore, the WebView would “scroll” the pixels on my scrollbar in the process of scrolling its own text.

It was a mess.

The solution is fairly simple, though:

  1. Drop an NSScroller instance over the right side of the WebView in Interface Builder. The width doesn’t matter as we’ll adjust it in -awakeFromNib to match the width of a standard-sized NSScroller.
  2. In the window’s -awakeFromNib method, enable the NSScrollbar instance, set its size to NSRegularControlSize, and set its initial knob size and position. Also set the WebView‘s scroller style to “legacy”:
    [[[[[webView mainFrame] frameView] documentView] enclosingScrollView] setScrollerStyle:NSScrollerStyleLegacy];
  3. As blocks are loaded and the Javascript reports its position within the displayed text, update the position of the knob.
  4. Connect the NSScroller action to a handler in the code to position the text appropriately with changes to the knob.
  5. Add a handler to intercept distributed notifications:
    [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(observeDistributedNotifications:) name:nil object:nil];
  6. In the handler for the distributed notifications, look for the notification named AppleShowScrollBarsSettingChanged and when it occurs, call a method that forces the WebView scrollbar back to the “legacy” style. You must call this method on a short delay because notifications are not delivered in any particular order. You need to allow the system to change the WebView scroller style before you change it back.

That’s it. The basic idea is to provide your own NSScroller that is updated by position changes in the WebView and which moves the WebView as the user interacts with it. This scrollbar lays on top of the WebView scroller so the user can’t see it. And to keep OS X from inappropriately drawing, we intercept system preference changes that would alter the style of the WebView scroller.

I think this solution would work with any Cocoa view object that is based on NSScrollView. One notable side-effect is that your scrollbar does not auto-hide. In my case, I can live with this.

Craig 1, Hacker 0

When you purchase a product from our website, you click on a link to download it. The link appears to be legit — just a regular link to a file on our server. But it’s not. The file does not actually exist. We intercept the link and parse it to determine what to download to you.

When geeks like me see something like this, they poke around to see what they can find. When our server sees someone like me poking around, it sends me emails so I can watch them do it, because that’s what geeks like me like to do. No, we don’t tell the customer who’s doing the poking that we’re watching them. In fact, the error message they get tells them to forward the message to tech support. In reality we already know. 🙂

So here’s a customer from Australia doing some late-night hacking. He’s trying to download MyBible 5 for Palm OS without paying for it. Ironically, it’s free so if he really wants it, he can just go through the steps of ordering it and we’ll add it to his legitimate download account. But it’s more fun to try to get a free thing for free without not paying for it.

Two things you need to know: The product code for MyBible 5 is 3MBPGM005, and MyBible 3 is 3MBPGM002. The file name he’s trying to accidentally discover is “mb5setup.exe”. So this is the real link he’s trying to find: http://www.laridian.com/files/1158044/3MBPGM005/mybible5/program/mb5setup.exe

From the log:


http://www.laridian.com:80/files/1158044/3MBPGM005/mybible5/program/MyBibleSetup.exe
The filename requested (\mybible5\program\MyBibleSetup.exe) does not match the product (3MBPGM005). http://www.laridian.com:80/files/1158044/3MBPGM005/mybible5/program/MyBible5Setup.exe
The filename requested (\mybible5\program\MyBible5Setup.exe) does not match the product (3MBPGM005). http://www.laridian.com:80/files/1158044/3MBPGM005/mybible5/program/
The filename requested (\mybible5\program\) does not match the product (3MBPGM005). http://www.laridian.com:80/files/1158044/3MBPGM005/mybible5/program/MyBible51.exe
The filename requested (\mybible5\program\MyBible51.exe) does not match the product (3MBPGM005).

Next he tries to get an older version:


http://www.laridian.com:80/files/1158044/3MBPG3002/mybible3/program/MyBible3.exe
The filename requested (\mybible3\program\MyBible3.exe) does not match the product (3MBPG3002).

Back to looking for MyBible 5:


http://www.laridian.com:80/files/1158044/3MBPGM005/mybible5/program/MyBible5.exe
The filename requested (\mybible5\program\MyBible5.exe) does not match the product (3MBPGM005).

And back to MyBible 3:


http://www.laridian.com:80/files/1158044/3MBPG3002/mybible3/program/mb3setup.exe
The filename requested (\mybible3\program\mb3setup.exe) does not match the product (3MBPG3002). http://www.laridian.com:80/files/1158044/3MBPG3002/mybible3/program/MB3Setup.exe
The filename requested (\mybible3\program\MB3Setup.exe) does not match the product (3MBPG3002).

Here he gets it right! But he can’t download it because he doesn’t own it:


http://www.laridian.com:80/files/1158044/3MBPGM002/mybible3/program/mb3setup.exe
Customer 1158044 is not authorized to download product 3MBPGM002.

Now he switches his customer number to see if he can find a customer who *IS* authorized to download it. But he’s not going to get it without logging in as that customer first:


http://www.laridian.com:80/files/1158045/3MBPGM002/mybible3/program/mb3setup.exe
You are requesting files for customer 1158045 but customer 1158044 is logged in. You must access files through your download account. Exit your browser, then re-launch and go to our Login page to log in again.

Not sure what he’s doing here:


http://www.laridian.com:80/files/1158044/3MBPG3002/mybible3/program/mb3setup.exe
The filename requested (\mybible3\program\mb3setup.exe) does not match the product (3MBPG3002).

And at this point he admits defeat. Craig 1, hacker 0.

Braces and Indenting: You’re Doing it Wrong

Screen Shot 2014-01-28 at 8.33.08 AMJava, C++, Objective-C, and C# all use braces ( { and } ) to delineate the beginning and end of blocks of code. Over the years, several styles have evolved, with the worst of them dominating the literature. Once you see The Light you’ll wonder how we ever let this get out of hand.

Before we begin, let’s remind ourselves what braces are for: They mark the beginning and end of blocks of code. In many contexts a block stands in place of a single statement. It allows us to put two or more statements in a place where a single statement is called for in the grammar. In those contexts a block is functionally equivalent to the single statement it replaces. This will be important in our understanding of the One Right Way to indent.

In other contexts, such as the bodies of functions, surrounding the cases in a switch statement, and surrounding the declarations in a class definition, braces demarcate the contents of the function, switch, and class. For convenience, I’ll refer to any group of lines of code surrounded by braces as a “block”, even though the language definition may not always use that term in every context in which braces are used.

So the the first question is to ask: “To what do the braces belong: the block they surround or the syntactical element (if, for, switch, class etc.) to which the block belongs?”

When braces are used to surround a true block (the else clause of an if statement, for example), it’s clear the braces belong to the block. Together with the lines of code they contain, they replace a single statement.

The implication is that the braces should be indented at the same level as the lines of code in the block they surround, for they are part of that block.

The second question we need to ask is: “Should braces share the line with any other code; either a statement from the block they surround or the statement the block belongs to?”

Clearly we would not format code like this:

    x
    = y
    +
    z
    ;

We might break a very long line into two or more lines, but a short statement should always be on one line. Similarly, we try to avoid code like this:

    x = y + z; if ( x > 10 ) foo(x); bar(z); switch (y) {case 1: x = 2 * y; break; case 2: default: foo(x); break;}

The commonly accepted practice is to put one statement on each line. (There are exceptions but they are rare.) Similarly, I would argue that braces belong on a line by themselves. They are not “inline operators” like + or ==. They do not belong to the statement to their right or left; they surround those statements.

The reason we don’t put two or more statements on one line is that it is more difficult to read. It’s why we break up our thoughts into sentences and paragraphs. It aids in comprehension. The same is true of code. Consider the following:

    if ( x < 10 ) { foo(x);
        bar(y); }

The call to foo(x) belongs to the then-clause because it is inside the brace but it would be easy to glance at the code and assume bar(y) is the only statement executed when the if-condition is true because the call to foo(x) is “hidden” at the end of the if statement.

For this reason I would argue that braces belong on a line by themselves. It is too easy to miss them when they are “hidden” at the end of another line of code. So unless you’re in the habit of writing a dozen statements on one line, it doesn’t make sense to put a brace on the same line as another line of code.

With these two rules (i.e. braces belong to the block they surround and braces belong on a line by themselves), there’s only One Right Way to indent your code:

    if ( x < 10 )
        {
        foo(x);
        bar();
        }
    else
        {
        x += 10;
        foo(x);
        }

Now we can see why the predominant indenting style is so, so wrong:

    if ( x < 10 ) {    // should not be on same line as "if"; should be indented with block
        foo(x);
        bar();
    } else {              // should not be on same line as else (*2); should be indented like block above/below
        x += 10;
        foo(x);
    }                     // should be indented like block above

I realize those of you who grew up doing this wrong and reading all the literature from others who do it wrong will find the One Right Way more difficult to read. But it can be argued that you only find it difficult to read because you’re not accustomed to doing things the One Right Way, while the wrong style as illustrated above is difficult for me to read because it makes no attempt to be logically consistent. This makes it objectively wrong, not just a matter of personal preference.


Postscript
In the spirit of unity and the cause of world peace, practitioners of the One Right Way will accept the following style with the hope that those practicing it will see the one small error in their way and with proper mentoring and encouragement, will correct it:

    if ( x < 10 )
    {
        foo(x);
        bar();
    }
    else
    {
        x += 10;
        foo(x);
    }

An eCommerce Company Wants to Know: Do I Want to Double My Sales?

While searching for something else in my email archives, I ran into this exchange with a sales rep from Digital River who spammed me a few years back asking if I wanted to double our online sales. It’s rather humorous.

Subject: Online Sales @ Laridian

Hi Craig,

How are sales from laridian.com? If we could double online revenue, would you be willing to outsource your web store to Digital River? We have done this for most of our 3,000 software clients and would welcome the opportunity to discuss how we may be able to do the same for Laridian. Please reply if your willing to consider outsourcing your online store.

Sincerely,
John S
Regional Sales Manager
Digital River, Inc.
www.digitalriver.com

Wow. That sounds great. I’m always up for doubling my revenue. Here’s my respose:

From: Craig Rairdin [mailto:[email protected]]
To: ‘John S’
Subject: RE: Online Sales @ Laridian

Hi John!

Sales are great! No reason to make any changes. But you sound like an honest man so I’m willing to simply take you at your word — if you are willing to stand behind it.

Write back if you’re willing to sign a written guarantee that you’ll double our net revenue from Web sales as you’ve claimed you can do in your email.

Of course once we move to Digital River it will be difficult to say what our sales would have been had we not moved, so what we’ll do is take the last three years of sales and find a best-fit line based on monthly net revenue (i.e. revenue less cost of sales). We’ll project that line over the next three years and you will guarantee to send us a check for twice that amount regardless of your actual revenue from our products. At the end of three years we both can decide whether or not we want to continue the relationship.

One-half of each month’s guaranteed payment will be due on the first of the month. The remainder (either the other half of the guaranteed amount or the actual net revenue from sales) will be due within 10 days of the end of the month. If you don’t pay the full amount due in a particular month within 10 days of the end of the month, then we revert back to selling ourselves and the remainder of the 3-year contract becomes due immediately.

I don’t expect to have any expenses associated with the conversion from doing this at our site to doing it at yours. I anticipate that the way the changeover would work is that you would get everything set up on your end at no expense to us, then on the first of some particular month I’d find a check from you equal to that month’s projected net revenue and I’d edit a few lines of code on our site to send customers to your site for ordering, or we’d make a DNS change that would redirect our entire site to your servers.

I don’t expect to have any marketing expenses associated with driving traffic to the site. You’ll handle our online and print advertising as it relates to direct sales. Of course we’ll continue to handle marketing and sales through other channels.

John, I assume you’ve done your homework and you have a rough idea how much money you’re committing your company to, or you wouldn’t have made such claims in an unsolicited commercial email. Of course I trust you implicitly and know that you wouldn’t say something like this if you weren’t fully willing and able to deliver. It must be great to work for a company that can deliver these kind of results! Frankly, I’ve been looking for a Magic Bullet that would double net revenue from our Web site. If you’re willing to stand behind your marketing claims with real money (and I have no reason to doubt that you are), this could be a match made in heaven!

Craig

I assumed that if John was bold enough to claim he could double our online sales that he actually believed he could triple or quadruple them. Otherwise, he’d risk not being able to hold up his end of the deal. So my plan to hold him to his (outrageous) claims should’ve been a no-brainer for him. Apparently not. Here’s his response:

From: John S
To: Craig Rairdin
Subject: RE: Online Sales @ Laridian

Hi Craig,
You sound like a smart business man, so I’m sure you already realize their are no guarantees in business. It is true we have been able to double online revenue for most of our clients, but I’m sorry you misunderstood my email.
Regards,
John

What? I misunderstood that when he said he could double our sales, he meant that he couldn’t double our sales?

From: Craig Rairdin [mailto:[email protected]]
To: ‘John S’
Subject: RE: Online Sales @ Laridian

Hmmm… So when you said “If we could double online revenue, would you be willing to outsource your web store to Digital River?” you never intended to demonstrate your ability to do that in any concrete way? You asked if we’d outsource our store in exchange for double our current revenue, but you had no intention of proving you could do it or standing behind your promises with guarantees.

So what are your potential customers supposed to do? Just believe a guy who spams them and turn over their life-blood to his company with the hope that the spammer knows what he’s talking about? You may have found 3000 other nut-cases with this pitch but you didn’t find one here.

Even though my message was tongue-in-cheek, I’d be willing to actually follow through on the promises made therein. By contrast, your message was a serious invitation to do business together, but you had no intention of standing behind your words with any kind of concrete action. Your willingness to spam me and spew nonsensical marketingspeak with no intention of delivering tells me more about Digital River than you could possibly imagine.

Please remove us from your spam list.

Craig

To his credit, he removed me from his spam list.

I think a business that makes a clear claim in a solicitation for business should be willing to stand behind it. I think my proposal was more than fair, even though I knew he would never go for it. It irritates me when a business makes claims like this and thinks they shouldn’t be held responsible for them.

A Customer Wants to Know: How Stupid Can I Be?

Back in the day, we used a number of email lists run by a program called mailman to communicate with our customers. You could join a list based on the type of device you had, and from time to time we’d email you to let you know about updates and upgrades. We stopped using these lists around 2007 but the server is still running.

Every month, the list server sends each member his password and a reminder that he can unsubscribe or change his preferences by logging into the server and making the changes. When you sign up for the list, you can turn this option on or off. Because so many people sign up by email and have a password generated for them automatically, this behavior (monthly reminders) is turned on by default.

On January 1 I received this email from a subscriber to our iPhone list. I’ve changed his name and anonymized his employer’s company name, which appeared in every email he sent. Note he’s writing from the UK.

You have just emailed me my user name and password in an e-mail in plain text.

Are you stupid or something!

I have closed my account

Jimmy McWeenie

Jimmy’s Employer’s Name Here

Normally, I would send a nice response that explains that there is no financial or personal data exposed by the password, and would explain why we enable this behavior by default. But his “are you stupid” comment irritated me. I crafted a number of more- and less-tactful responses to this email, but ended up sending this one:

On 01/01/2014 15:09, “Craig Rairdin” <[email protected]> wrote:

Jimmy,

When you signed up for this email list, you chose the option to have the server send your login credentials to you every month. We are stupid enough to send you the information that you requested on the schedule that you requested.

We’re also stupid enough to send you the products you purchase and stupid enough to respond to your support requests. We’re stupid enough to continue developing new products for new platforms and stupid enough to give them away for free.

I hope we’re stupid enough to explain this clearly.

Let me know how much more stupid you need us to be.

I hope your new year is off to the same great start that ours is.

Craig

Jimmy replied:

If you still don’t get that sending someones login details, their user name and password in plain text in an e-mail is not just stupid, it’s a breach of the Data Protection Act 1998, then you should be involved in the computer business at all.

You don’t send this data out every month, just four times since 2011, which was when I had a look at your software.

I’ve done my best to ensure that my account with you is now closed, hopefully be can now both enjoy a 2014 equally undisturbed by each other

Best wishes

Jimmy McWeenie

Jimmy’s Employer’s Name Here

I had to look up the “Data Protection Act of 1998”. It was at this point I realized Jimmy is in the UK.

On 1 Jan 2014, at 22:54, “Craig Rairdin” <[email protected]> wrote:

Jimmy,

Our company and our server is in the US. We haven’t been subject to the laws of the UK since the late 1700’s. 🙂 This is an email list you signed up for. When you signed up, you had the option to have your login credentials sent to you every month. You chose that option. The list server is following your instructions.

Every mailman list server list from the beginning of the internet has done this. I get these reminders every month from a dozen lists. I’m glad to hear you figured out how to remove yourself from the list, which is one of the options that is presented to you every month. You have not “closed your account” — just removed yourself from an unused mailing list.

I’m working on that particular server today and will shut down all the lists while I’m there. We haven’t made use of them for a long time and most people have removed themselves already.

Craig

Jimmy replied:

Unfortunately Craig, you are wrong again. Your company is currently offering it’s products through Apples UK App Store, and so those accounts will be liable to UK taxes and jurisdiction.

I very much doubt that any one who signed up, expecting some kind of news letter, thought that you would e-mail out their account details in plain text.

Tell you what, I’ll e-mail our conversation around to a few websites tomorrow, and we’ll see if, generally, people think that your company is behaving irresponsibly or not.

I’ll cc you in so that you can know who I’ve sent them to, as no doubt they will want some comments from you

Regards

Jimmy McWeenie

Jimmy’s Employer’s Name Here

So now Jimmy is threatening to expose this vile breach of privacy to the rest of the world. My experience is that people who make this threat either never follow through, or else the people they notify are used to receiving their crazy rants and just block them. So I’m not worried. Continuing to demonstrate the scope of my stupidity, I chose to respond:

On 2 Jan 2014, at 00:00, “Craig Rairdin” <[email protected]> wrote:

Our relationship with Apple is one where they act as an independent seller of our software. Our agreement with them makes them responsible for all taxes and local laws in the places in which they do business. It does not create nexus in the UK for Laridian. In fact, one of its purposes is to assure us that it is Apple that is doing business in the UK, not us. The people who signed up for the list learned about the purpose of the list on the same page where they opted to have their password emailed to them every month. If they knew they were signing up for a newsletter, they knew they were requesting their login credentials. And if they objected to receiving those, they read the instructions and learned, just as you did, how to remove themselves from the list or change their subscription settings.

Feel free to pass our conversation around to whomever you feel it would benefit. Make sure to let them know that we sent you the information you requested, that we told you how to stop receiving that information, and that you followed those instructions and now are not receiving that information any longer. If that angers them to the degree it does you, I’d be happy to discuss it further with them.

Craig

This morning, Jimmy replied:

On 1/1/14 6:13 PM, “jimmy mcweenie” <jimmy@jimmys_employer.co.uk> wrote:

I’m sure that Apple will be one of the people I send this to. From a brief viewing of Apples terms and conditions, it would seem to me that they make some effort to preclude the type of liability you suggest falling on them. Would you like to take the opportunity, right at the start, to send me a copy the details of where I signed up to have my account information sent to me in plain text? You seem to want to rely on the fact that I asked you to do this, and you were only complying with my wishes.

If you send me evidence that I specifically asked you to email me my account security information as plain text each month, I will include this information with my email of this conversation.

Is there anyone at Laridian you would like to involve in this discussion?

Regards

Jimmy McWeenie

Jimmy’s Employer’s Name Here

By threatening to involve other people at Laridian, he’s hoping to get me worried that my boss will find out how I’ve been treating our customers.  Clearly, Jimmy hasn’t read the Laridian org chart. When it comes to stupid, I’m the top dog here. I decide to bring this to an end.

On 02/01/2014 16:40, “Craig Rairdin” <[email protected]> wrote:

Here’s the documentation for Mailman, our list manager software: http://www.gnu.org/software/mailman/docs.html. It contains everything you need to know.

You may involve as many people in this discussion of the subtle details of your email preferences as you think will be interested. Personally, I’ve lost all my interest. I have explained the situation to you; you have removed yourself from the inactive list you signed up for; I have removed you from any future email we may do (though we probably haven’t sent you a marketing email in the last 10 years or so); and I’m in the process of shutting down this unused mailing list server. I’ve disabled the automatic monthly emails, which is irrelevant since I plan on having the entire physical server offline in the next few days.

I have explained that we’re not subject to the Data Protection Act of 1998 since we have no nexus in the UK. Furthermore, the mailing list does not retain any “sensitive personal data” as defined by the Data Protection Act of 1998, so unauthorized acquisition of your password would not expose any data that is protected by the Act, even if we were subject to it.

This will be my last email to you on this subject, which, as you so tactfully put it, is “How stupid can (I) be.” I believe I answered that question by simply replying to your email. I made it clearer by continuing the conversation as long as I have.

Again, I wish you the very best for the new year.

Craig

But Jimmy will have none of it. He continues:

Craig

In a mission to prove how stupid you really are, you decide to have one last poke at me, when I hadn’t taken my complaint any further.

I had decided that in light of the fact you sold Bible software, I would put the exchange to a down to a bored techie whiling the time away making ill advised comments to a customer.

However if you want to discover how serious this complaint is, I’m e-mailing Apple to see what they think of Laridian distributing customer account details across the weld every month

Enjoy

Regards

Jimmy McWeenie

Jimmy’s Employer’s Name Here

So sometime between when he said he was “sure” he was going to send this all to Apple and when he received my reply, he decided not to. Only when I replied did he decide to cry havoc and let slip the dogs of war. Interestingly, my reply contained no “pokes” at him, only a continuation of the self-depricating theme of answering his question “How stupid are you?” in the affirmative.

I’m sure since Jimmy has no idea that I’m the President of Laridian that he has no idea who to send his email to at Apple. I’ll let you know what happens next.

From the Archives: Managing Craig’s Way

Something recently reminded me of this article I wrote back in September 1994. For you historians, that would have been the month that the Intuit purchase of Parsons technology was finalized. It was revised in 2001. So if any of it sounds dated, it’s because it is.

I assume this would’ve appeared on my original blog back before they were called blogs, but that sounds too early. So I’m not sure why I wrote this.

Management Principles

September 24, 1994

I’ve always been struck by the fact that great people seem to operate on a small set of principles which they consider inviolable. These principles, right or wrong, guide them in all of their decisions. Their decisions, though sometimes wrong because of the wrongness of their principles, are quickly made and internally consistent. Collectively they form the “conscience” or “personality” of the organizations these people inhabit.

I believe it was Ross Perot (or perhaps it was Tom Watson — it was one of those IBM guys) whose management style was described by an employee as “Management by Hanging a Sign.” Mr. Perot would hang signs around the office declaring some axiom of life as only Mr. Perot could have imagined it, and he expected the employees to follow.

Within the religious community, great men of faith are often known by their basic principles. A church I used to go to counted Dr. Bob Jones Sr. as one of their heroes. I can’t count the number of “as Dr. Bob always said…” illustrations I’ve heard in sermons.

And then there’s the Ferengi Rules of Acquisition.

You get the point. I’m not claiming that what follows is anything special, or that I’m the next Bob Jones, Ross Perot, or Grand Nagus Gint. But it seems that there is some value in setting these things down and trying to follow them.

While these principles are not strictly taken from the Bible, I hope they’re at least biblical. I’m a little concerned about “It’s easier to get forgiveness than permission” though I would contend that statement is at least true from a biblical point of view. It may not be the best policy, but it’s true.

This is just a list of those aphorisms I’ve found that I live by in business. Names in parenthesis are the source when I remember where these came from. While the ones I’m claiming as mine are things I really think I came up with on my own, many are pretty simple, and they’re undoubtedly based on principles I’ve heard or read about. When I’m pretty sure I read it somewhere but can’t remember where, I’ve left it unattributed.

Decision Making

It’s better to make a decision than to make a right decision.

Making a decision permits you to move forward. Waiting for all possible information to come in so that the right decision can be made often results in no decisions happening for a long, long time.

This is a good principle to teach to those who report to you, and for you to keep in mind as you report to your boss. A manager doesn’t have time to consider the implications of every decision that has to be made in the organization. That’s why he or she hires people. Those people need to be willing to make decisions and not continuously bring them to the boss. The quickest way to prove you’re dispensable is to be good at gathering facts but slow at applying those facts to daily decisions without the boss’s OK.

Our failures form the basis for our success.

(Russ Novotny)

There’s no such thing as bad decisions and failures. All “wrong paths” taken in the course of getting something done contribute to the overall success of the project. If you hadn’t gone down that “wrong” path, you wouldn’t have learned all those lessons.

Programs which have suffered no false starts nor setbacks tend to be fragile. Making a mistake helps us to identify where the weaknesses are in a plan or design. Once we’ve seen how we can fail, we can take steps to make sure we don’t fall into the same trap again. Not only will the current project benefit, but future ones will as well when we have learned from experience what to avoid.

It’s easier to get forgiveness than permission.

This is an old standby. It basically says that when you’ve got something to do that is risky, it’s better to do it (perhaps hoping you won’t get caught) than to try to get permission. Getting permission involves someone else (usually higher up in the organization) in the risks. It’s likely they will be reluctant to go along, and you won’t be able to get permission to do something you know needs to be done. If you simply do it, you might not get caught. If you do get caught, and the project was even somewhat successful, you come off well by looking like a person willing to take risks to do the right thing. If you get caught and the project failed you’ll probably get by with a reprimand. Worst case is you’ll get a chance for a change of scenery.

Note that this isn’t a license to do all manner of evil. But rather, it’s a way of saying that sometimes you just have to do what’s right even though nobody would agree with you if you tried to explain it to them.

People Management

The three-sided manager: Planner/Cheerleader, Bridge-builder, Wall-builder.

(Craig)

I’ve come to believe that managers (at least of software projects — you’ll have to decide if this applies to you) have three roles in their organizations:

  • As a planner/cheerleader you’re responsible for looking to the future, bringing in new work, getting people excited about what’s coming up, and keeping them excited about what they’re doing.
  • As a bridge-builder you’re responsible for connecting your people to the resources they need to get their jobs done — whether it’s equipment, furniture, training, assistance from others, books, or whatever.
  • As a wall-builder you’re responsible for protecting your people from interference from upper management, policy police, fellow employees, etc.

Interestingly enough, none of these roles is the traditional authoritarian “boss”. People who spend their time telling their people what to do are limiting the possibilities of what their group can do. By making all the decisions for them and enforcing your will on your employees you destroy morale and run the risk of making poor choices because you haven’t considered the opinions of the people who really know the job — your employees.

Deal with problems as they’re encountered.

(Craig)

We all prefer to ignore problems, especially people problems. As a manager I’ve had to deal with an incredible range of really nasty situations, from people using their business computers for “inappropriate Web browsing” to people I had to recommend for counseling. It would have been much easier to ignore these problems and hope that they went away. But doing so would only let the problem get worse.

A simple application of this principle is this: There should be no surprises at an employee’s annual performance review. An employee shouldn’t learn of significant deficiencies for the first time at his or her review. If it’s serious enough to merit mention in the review, then it must be important enough that you should have dealt with it when it happened.

Any eight hours will do. Any forty hours will do.

(Craig)

If at all possible, implement “flextime” within your organization. Flextime says that an employee can come in at anytime in the morning and leave at anytime in the afternoon as long as they’ve put in their eight hours. It permits an employee to take a half-hour lunch or a one-hour lunch. It should also permit occasional afternoons off if the time can be made up within a reasonable period of time.

This is especially important in engineering and creative disciplines. (It’s not very functional in sales or customer service organizations.) Flextime recognizes the employee’s ability to manage himself. It creates a very stimulating environment in which people will be free to leave the facilities even, if that’s what it takes to do their job. It’s not unusual in my group for a couple guys to head out to the software store to see what the competition is up to or to evaluate a new idea by looking at what’s already available.

Flextime also permits an employee to arrange his family time and work time in a way that meets his needs. Some employees like to spend time in the morning with their kids. Others prefer to get home right away so they can pick up kids from school or get a head start on the evening’s activities. By implementing flextime, you earn the respect and appreciation not only of the employee, but of his or her family.

Vacation time is a right, not a privilege.

(Neil Ennis)

Many employers make vacation time something you have to beg for. As long as you’re not in an organization that requires a certain staffing level each day (telemarketing, restaurants, etc.) you should always honor every vacation request. The employee has earned it.

Many managers fear employees will take time off right at the critical phase of a project. But no responsible employee will ask for vacation at a bad time. Even if they do it’s better to let them take it. Adding to the stress at work by adding stress at home isn’t going to get the project out the door any faster.

Promote employee ownership of the product.

(Dave Theilen)

Tell them everything we know about the competitor and the marketplace, let them make decisions about implementation, and believe their schedules. As a result, they turn out a better product and do it on time without forced overtime.

Let them work it out

Take the time to help an employee who is having difficulty with an assignment to get the resources he needs to accomplish the task. Let people make mistakes, then help them figure out what they did wrong and how to avoid the mistake in the future. You don’t need to give them the answers. They can figure it out if you give them the opportunity.

Don’t answer the phone when you’re in a meeting with an employee.

(DeMarco and Lister?)

There’s no better way to tell someone you don’t care than to take a phone call in the middle of a meeting with them. This goes for retail sales people who answer the phone while you’re checking out, too. Just ignore the phone or forward it to voice mail. If it’s important they’ll call back.

Project Management

Your employees know more than you do.

Let them do their jobs.

There’s no such thing as overtime.

(DeMarco and Lister)

Overtime hours are less productive. Employees make them up after the project is over through decreased enthusiasm and burnout. Overtime robs employees of their families and makes you the enemy.

Our programmers are our first customers.

(Craig)

Our programmers should be familiar enough with the application domain that they’re using our products to solve their own problems in that area. As a result, they know what users want because they are themselves users.

WDYR? (What do you recommend?)

(Gus Pagonis)

Don’t tell me about a problem unless you have a solution. Similarly, don’t tell your boss about a problem unless you can offer a solution.

Software Development

This program works.

(Craig)

Programs should be implemented incrementally. Each increment should be proven to be correct. At every stage, the program should work.

Debuggers don’t.

(Craig)

Debuggers give you a micro-view into your code. Most coding problems are logic problems which are macro-problems. If you think about your code while you’re implementing you don’t need a debugger.

There’s no such thing as too many comments.

(Craig)

The quality of internal documentation is the mark of a great programmer.

There’s no such thing as reusable software.

(Craig)

It is possible to create small utility functions that can be reused in many projects, even over a long period of time. I had a collection of BIOS display functions that I used for about six years when I was writing DOS programs. It was a very simple set of functions but it performed some very useful tasks and saved me a lot of time.

But when people refer to software reusability they usually mean creating large scale libraries of functions or classes which can be used on many projects. They seek to standardize on these common functions with the idea that once this code is written they’ll never need to do it again.

I’ve found that none of these efforts produce anything that’s usable for longer than a year. Technology changes, and the solutions that seemed right a year ago are useless now. Instead of trying to constantly position for the future, it’s best to follow the next axiom.

Implement today’s programs with today’s tools to today’s standards.

(Craig)

It seems there’s always some Great New Thing coming out in three to six months that’s going to revolutionize the way you write software. But three to six months from now there will be some other Great New Thing coming three to six months from then.

I’ve found that it’s best to use the most promising tools available today to solve today’s problems. Half-way through the project you’ll be tempted to change your implementation plan to take advantage of some new technology. It’s almost always better to continue with your original plan. Let someone else debug this new stuff while you get your product out the door. Then come back and take advantage of the new stuff on version 2.0.

Working with Other Companies

Ask for more than you need.

Buy yourself some negotiating room. You can always give some back. Applies to a lot of areas; similar to “under-promise and over-deliver”.

Use voice mail.

Leave detailed messages. Don’t just say “call me back.” If you leave a message it should convey new information.

Let 1000 flowers bloom.

(Guy Kawasaki)

The little guy you’re not interested in today could save your company tomorrow. Don’t burn your bridges. Leave your options open.

Customer Service

Under-promise and over-deliver.

(Guy Kawasaki)

Don’t make a promise you can’t keep. In fact, if you make a promise, keep it sooner and better than you promised.

Hiring

Interviews take at least four hours and often eight.

(Craig)

It takes about an hour to and hour and a half to get to know the candidate’s capabilities. It takes a half hour to an hour to tell about our company. The rest of the time is for the candidate to ask questions.

Hiring a new employee is a bigger decision for him or her than it is for you.

(Craig)

You’re asking the applicant to completely change his life. All you’re doing is choosing one person from a list of several potential candidates. As a result, give the candidate adequate time to become familiar with you, the job, the company and the city.

Let the candidate talk to his potential co-workers.

Involve other members of the team in the interview process. Then believe what they tell you about their impressions.

Life Principles

Think about it overnight.

(Bob Parsons)

Before sending a scathing e-mail or letter, let it sit overnight at least. The recipient will still be there tomorrow. I wish I could remember to do this more often.

Pray for your competitors.

(The Bible)

For several years I used a competitor’s mouse pad as a constant reminder to pray for them. I’ve never felt bad about steering a customer to a competitor’s product when they have something we don’t. I think in the long run it builds goodwill with customers and your industry peers.

Say you’re sorry.

(The Bible)

Admit your mistakes. It disarms people.

Send your wife flowers half way through a week-long trip.

(Craig)

I reserve this for really long trips but it really helps.

Always be reading a good book.

(Kurt Hansen)

It keeps your brain from decomposing.

Read about people whose lives you admire and want to emulate.

(Rush Limbaugh)

Have you noticed that squirrels seem to never learn from their friends’ experiences while crossing the road? Humans have the benefit of being able to learn from other peoples’ mistakes so they won’t have to make them themselves. They also learn from others’ successes. Don’t be a squirrel: Read a book.

Tip well.

(Craig)

Be loyal to businesses that treat you well. They’ll treat you better each time you come in.

Keep a to-do list.

Craig: Fill in this paragraph.

If you didn’t write it down, it didn’t happen.

(Cliff Stoll)

I’ve always wanted to keep a diary, but I’ve never managed to muster the discipline. But at work I try to keep a phone log and a brief diary. It makes it a lot easier to remember what happened when and to remind you of your accomplishments.

During the development of one of our software products we wanted to make use of some data, the copyright status of which was in question. I contacted the owner and was told that I didn’t need to ask their permission to use this data — my usage was not inflicting on their copyrights or trademarks. I made a note in my log of the date and time, along with the name of the person I talked to.

About four years later, the president of the company which owned the copyright on this data contacted me and wanted to collect back-royalties on our usage of the data. When I told him I had verbal permission from one of his employees, he didn’t believe me. But when I produced a copy of my dated phone log, there wasn’t much he could say. While he probably could have challenged us in court, he chose to honor his employee’s decision and let us off (he would have lost in court anyway).

If you have a legitimate complaint, mention it when you check out.

(Craig)

Mention one or two things you had trouble with every time you check out of a hotel. More often than not you’ll get a free night.

People don’t expect enough from hotels. Remember that the purpose of a hotel is to provide a comfortable place for people to sleep. Anything they do that undermines that purpose shows that they don’t understand the needs of their customers.

A classic mistake seems to be renting out large public areas for private events. We were staying in one of those large hotels with the big central atrium one time when they had scheduled a rock concert in the atrium. While it was great fun for those who attended, it wasn’t much fun for our family. On another occasion, we discovered the hotel rented its pool to a water aerobics group each evening during prime guest pool usage time. Needless to say, I mentioned both of these incidents to the respective managers and received credit for at least one night’s stay in each case.

Always leave the bathroom cleaner than when you entered it.

(Craig)

While the principle applies well at home, it’s also very suitable for public restrooms. Imagine if everyone just cleaned up after themselves in men’s rooms. The world would be a nicer place.

Make sure the slots in the screw heads line up in the same direction.

(Dad)

In other words, pay attention to the details. Or, “a job worth doing is worth doing well.”

A few years ago I was mounting an outlet cover plate on the wall after doing some wallpapering. I noticed that I subconsciously was making sure the slots in the screws lined up in the same direction (in this case, up and down — not sideways). I realized that I had picked this up from my dad years before. Then just a month ago I noticed that the electricians doing some remodeling for me did the same. I was pretty impressed there for a while… until I stepped back and realized they had mounted the outlet box at a slight angle.

I guess some people can learn principles but not quite fully apply them. It’s nice to have those screw heads straight, but I’d rather have the outlets square with the rest of the world.

Essential Reading

Certain books have been critical to shaping the way I think about management and product development. I consider these to be important to people managing groups of engineers or people involved in creative endeavors.

Zapp! The Lightning of Empowerment, Byham

Peopleware, DeMarco and Lister, Dorset House

The Bible, Various

The Macintosh Way, Kawasaki

“Contributors”

Dad — The best thing my dad ever did for me as far as preparing me for doing things myself was help me build a Soapbox Derby car. In the course of that project I learned a lot about doing a job and doing it right.

DeMarco, Tom and Lister, Tim — Met one of these guys at a Software Developers conference. Authors of Peopleware, one of the definitive works as it relates to my style of management.

Ennis, Neil — My supervisor at Rockwell. My first boss. An incredible role model and probably the source of more of this material than I realize.

Hansen, Kurt — My first close co-worker at Parsons. Rejuvenated my love of reading though he probably doesn’t realize it. Kurt once read through the first seven volumes of the encyclopedia. (OK, it would be more impressive if he had read the whole thing, but… seven volumes! That’s pretty good.)

Limbaugh, Rush — Radio host, author, consummate conservative.

Kawasaki, Guy — Author of The Macintosh Way and Selling the Dream. Offers a fascinating view of the computer industry and software development.

Novotny, Russ — Team leader on my first project at Rockwell.

Pagonis, Gus — Author of Moving Mountains. Managed logistics during the Gulf War.

Parsons, Bob — Founder of Parsons Technology. Madman and mentor. Probably also contributed to more of these aphorisms than I’ve acknowledged.

Stoll, Cliff — Author of Cuckoo’s Egg. Astrophysicist and techno-philosopher.

Theilen, Dave — Author of No Bugs. Saw him speak at a Software Developers conference. First software manager I heard who thought the same way I did about managing programmers. Again, many of the ideas I claim as my own are probably Dave’s, though I think I had many of my concepts nailed down before I first started reading his material.

Why iOS 7 is Objectively Bad

A discussion on Facebook with an Apple employee resulted in some comments that I thought would be better presented here. The response to my general complaint about iOS 7 was that it was new, and with anything new it just takes time to learn the differences. I disagree. iOS 7 is demonstrably and objectively wrong. Here are just a few observations.

My problem with iOS 7 isn’t “how do I remove an app from memory?” or “how do I do a search?”, but rather with the overall appearance (and therefore usability).

  1. There is less difference between the container and the content. Look at the Contacts app, where the screen is all white except for small blue labels and small black values. I just tapped a blue label (“home”) to change my daughter’s home phone number and it called her instead. It’s hard to tell whether something is touchable or editable. And what is editable (the captions in this case are, in fact, changeable) and what is fixed (like the navigation bar text at the top of the screen).
  2. There is inconsistent use of color. The Contacts app uses a blue “tint color” (which is what the SDK calls the color that is used for buttons, captions, etc. throughout an app). The Calendar app uses orange. The Notes app uses yellow except (and this is true of all apps) when a system-defined UI element pops up (like the confirmation dialog you get when you select the trash can), in which case you get blue as the accent color (except for the Delete Note button, which uses red, even though the trash can itself was yellow).

    What the system seems to be communicating is that color is irrelevant and that I shouldn’t count on color to tell me anything. But at the same time, red is consistently used for “danger” — like delete confirmations. And blue is always used for alert boxes. And the tap-and-hold menu is always white text on black (even if the text itself that you’re selecting is white on black, making the menu impossible to see). So is color important or not? iOS 7 would say “no” out of one side of its mouth and “yes” out of the other.

  3. Fonts and icons are thin, making them blend into the background. Fonts are sans serif, making them harder to read.
  4. There is a lot of gray-on-gray and white-on-white. Low contrast is hard to see. In an effort to de-accent the container and focus on the content, we’ve made the control elements (buttons and captions) harder to see and read.

There are not “how do I do this in iOS 7” observations. These are objective criticisms of the design of the user interface. I don’t need instructions on how to read a sans serif font or how to see low contrast text on a similarly colored background. You can’t educate your users past the unarguable flaws in the design of the operating system.

Ironically, it’s not “ugly”. It looks very clean. But even though white road signs with white lettering would look “clean”, we make road signs with high-contrast white-on-blue or black-on-yellow to make them easy to read. iOS 7 fails the readability and therefore usability test.

“Dad, When Did the Internet Start?”

Dillon and I were talking this morning about people who write checks and keep a running balance in the back of their checkbooks. I got thinking back and figured out I probably stopped keeping a paper check register in 1987 and stopped keeping an electronic one in the early 90’s. Nowadays, my bank keeps track of that for me and I can access it from my phone.

That led to the question, “When did the world wide of web begin?” And that question took me back…

I think my first experiences with any kind of online computing was during the BBS days of the 1980’s. I was a member of the “Hawkeye BBS” run by Ben Blackstock, a local attorney. For $15/year you could dial into Ben’s PC and access the various discussion lists and files that were kept there.

In about 1987 I started paying bills online with CheckFree. There was no Web and no dial-up access to the internet for most people at that time. Your computer called CheckFree directly and send payment requests. CheckFree wrote a physical check against your account and mailed it to the vendor for you. Or they would do an EFT transaction and write the check against their own account.

After I started working at Parsons Technology in 1988, Bob Parsons had me start using Quicken as a way to keep an eye on the competition. Quicken integrated with CheckFree, and MoneyCounts did too, eventually. Eventually Quicken had their own bill payment option and I think I used that for a while.

About that same time, I signed up for CompuServe. CompuServe was another dial-up service that was not unlike the BBS systems from ten years before. It was text-based — you got a menu of a dozen choices of things to do, entered a number to select an item, then you got another menu. All of this in the form of scrolling text — no graphics.

Parsons started doing tech support on CompuServe long before other companies, and we did beta testing there as well using a private forum. CompuServe had its own email service. When they eventually hooked up with the internet, my CompuServe email address may have been my first. As I recall it was [email protected]. Easy to remember.

Sometime in the early 90’s a friend of mine at church started going on and on about the cool things he was doing on the internet. He gave me a phone number to call and told me what to ask for to get a “PTP” account that would let me dial in and have access to the internet. I don’t recall if I was using a Web browser at that point or if it was all just FTP, USENET, Archie, Gopher, and other early protocols. I downloaded instructions to build a nuclear bomb, of course.

In about that same time period, America Online (AOL) came along. For you youngsters, AOL was like the Web in a box. You dialed into AOL and they served up graphical pages not unlike the Web. No Web addresses, though. Instead it was AOL “screen names” and “keywords”. So I was CRAIGR (screen name) and Parsons Technology was PARSONS (keyword). Even today you’ll sometimes see companies say to “enter the internet keyword ‘company name'” to find them on the Web. They’re still living in the AOL of the 1990’s.

Around 1994 or so, Microsoft started MSN, which was their answer to AOL and CompuServe. But the writing was on the wall and the World Wide Web was destined to be the online destination. Both AOL and CompuServe offered connections to the Web, and MSN kind of disappeared and Internet Explorer came along. It shipped with Windows 95. I tend to date most people’s awareness of the internet and the Web to Windows 95, which shipped in August 1995.

In the summer of 1996 I registered craigr.com and signed up with a company called SimpleNet for Web hosting. I created www.craigr.com. You can see a very early version of that site from December 1996 here. SimpleNet was eventually purchased by Yahoo, but not before I had a chance to visit them while on a business trip to California. The entire company was in a 3-bedroom condo with CAT5 cable running from room to room. It was pretty cool. They gave me a coffee mug and said I was the only customer who had ever visited them.

Objective-C Memory Management

Perhaps I’m showing my age, but I’m getting awful tired of language designers trying to improve on C/C++ memory management.

Just for review, here’s how memory management should work:

void foo()
  {
  // x is created on the stack. It is deallocated at the end of
  // the block/function and therefore its lifetime matches its
  // scope with no further effort. 

  int x;

  // pX is a pointer to an int that the programmer creates with
  // new. By using "new", the programmer is taking responsibility
  // for freeing the memory used by pX before it goes out of scope.

  int *pX = new int(0);

  // ... interesting code goes here ...

  // The obligatory delete before we exit the block/function.

  delete pX;

  }

Everything else in C/C++ is a variation on this. You can put pointers and variables in structures and classes/objects but they follow the same rules: If you allocate with new, you must free with delete before you lose track of the memory (i.e. the one and only (or last remaining) pointer goes out of scope).

When we started coding for iOS, we ran into “manual retain/release” which is a variation on the C/C++ technique (or rather, a manual method of the automatic garbage collection used in Mac OS):

@interface bar
  {
  // Like C++, when the pointer is a member (instance) variable, 
  // someone else is responsible for allocating memory for it.

  NSString * memberString;
  NSString * anotherString;
  }

// But if the instance variable is accessible from the outside
// world we can say it's a "property" and some of this is 
// managed for us. 

@property (retain) NSString * memberString;

// Unless we don't specify "retain". Now we're responsible for
// making sure the memory for anotherString is allocated and
// freed.

@property (assign) NSString * anotherString;

@end

@implementation bar

- (void)foo
  {
  // These are the same. They're on the stack and are automatically 
  // released when you exit the method/block.

  int x;

  // This is the equivalent of C/C++ "new", kind of. We can't just
  // do memory allocation without also initializing the object 
  // (handled by new and the constructor in C++, but that's the 
  // subject of a different article). The result is a pointer that
  // we're obligated to release before string goes out of scope.

  NSString * string = [[NSString alloc] init];

  // Another way of doing the same thing, but this time the 
  // resulting pointer is automatically released sometime in
  // the future that we don't care about.

  NSString * arString = [[[NSString alloc] init] autorelease];

  // Yet another way of doing the same thing, but the autorelease
  // is done for us. We can tell because the method name starts
  // with something that looks like the name of the class but
  // without the prefix. Intuitively obvious, right?

  NSString * autoString = [[NSString alloc] stringWithUTF8String:"Automatically released"];

  // Required release

  [string release];
  }

@end

And autorelease isn’t as automatic as you might think. You need to think about whether or not you need to create your own autorelease pool. This is important if you’re going to create a large number of autoreleased variables before returning to the run loop. You may want to manage your own autorelease pool in that case so you can free memory up at more convenient times.

If that’s not ridiculous enough, along comes Automatic Reference Counting (ARC) to “simplify” memory management.

@interface bar
  {
  // Like C++, when the pointer is a member (instance) variable, 
  // someone else is responsible for allocating memory for it.

  NSString * memberString;
  NSString * anotherString;
  }

// Instead of "retain", we create a "strong" reference. Memory
// is freed when this particular instance variable goes out
// of scope (is no longer accessible). 

@property (strong) NSString * memberString;

// We use "weak" instead of "assign" to mean that we understand
// someone else is in control of when this memory gets freed.

@property (weak) NSString * anotherString;

@end

@implementation bar

- (void)foo
  {
  // These are the same. They're on the stack and are automatically 
  // released when you exit the method/block. In reality, they're
  // qualified with __strong by default.

  int x = 10;
  NSString * string = [[NSString alloc] init]; // could add __strong for clarity

  // You can also create weak pointers for some reason:

  NSString * __weak weakString;

  // Unfortunately, that introduces a bug into these lines of code:

  weakString = [[NSString alloc] initWithFormat:@"x = %d", x];
  NSLog(@"weakString is '%@'", weakString);

  // In the code above, weakString is immediately deallocated after
  // it is created because there is no strong reference to it. See
  // how this is getting easier?

  // Not to mention:

  NSString * __autoreleasing arString;
  NSString * __unsafe_unretained uuString;

  // Now we don't have to do this:
  // [string release];
  // And that's really all we saved by introducing "Automatic Reference Counting".
  // At the same time, we created a new way to introduce a bug by failing
  // to have any strong pointers to an object from one line of code to
  // the next.
  }

@end

So we’ve gone from:

new / delete

to

retain / release (or autorelease with no release)

to

strong/__strong/weak/__weak/__autoreleasing/__unsafe_unretained

all in the interest of “simplification” and avoiding having to delete/release the memory we allocate. I frankly don’t see the benefits.

My Computer Bag

Tumi Expandable Leather Laptop BagI’ve been accused of having something of a luggage fetish, though more in the past than recently. Back in my Parsons Technology days I spent a fair amount of time on the road — nothing like my friend Dave, but more than most folks — maybe 3-5 days per month. It only took a couple of trips to figure out that the old suitcases in the closet weren’t up to the task, and what followed over the years was a series of suitcases and carry-ons as I tried to zero in on what worked best for me.

I’ve been traveling with a laptop since there were laptops. One of the first IBM-compatible PCs I used was a Compaq Portable. It weighed 25-30 lbs, but Rockwell had a padded case for it that made it look like a soft-side suitcase, and we literally checked it as luggage when we travelled with it. My first PC was a Compaq Portable II, but after traveling with and repairing Rockwell’s Compaq, I never traveled with it. In 1988 I bought a Toshiba T1200. Some of the early QuickVerse code was written while on the road with that laptop.

Throughout this period of heavy business travel, one constant companion was my Tumi leather laptop bag, which I purchased around 1989 for about $450. It was a crazy price to pay for a laptop bag, but this one had everything I was looking for and 25 years later I still carry it every day.

The front of the bag features a large and a small zippered pocket, each with a small zippered pocket on the front of it. Behind those pockets is a large, open compartment for cables and other bulky items. It has a small organizer sewn to one side that holds pens and business cards and gives you quick access to a calculator (back in the day), PDA (still back in the day), or a phone (there you go).

The second large compartment is divided into sections and opens up like a portfolio file. I find this side ideal not just for papers, notebooks, and other flat items, but also for my laptop. On the back of the bag is a large, flat, zippered pocket. On the back of that pocket, the straps from the handles form open loops that allow you to easily carry a newspaper (a what?) or an umbrella (ah, that’s better).

The bag has a leather handle sewn to each side. After 25 years of regular use, these handles are still firmly attached. There’s also a clip on shoulder strap that I leave permanently attached to the bag.

For short trips, I’ve found I can use the expansion feature to give me room to pack a change of clothes and shaving kit right in the bag. Just unzip the zipper that runs around the center section of the bag, and you gain 2-3 inches of space in the open compartment on the front of the bag.

Tumi still sells a version of this bag for $650, but they’ve removed the little organizer on the inside and replaced the umbrella straps with a feature that allows you to slide the pull-out handle of your wheelie through the pocket on the back so you can carry it with your suitcase. My Travelpro carry-on has a hook that I can use to carry the Tumi bag, so I don’t need this feature.

Even though Laridian started renting office space about two years ago, I still work one or two days per week at home or in a coffee shop. My MacBook lives in my Tumi bag, and my Tumi bag goes with me wherever I go. You can laugh at spending $450 for a computer bag, but if you divide by the number of years it’s lasted, you’re looking at $18/year and falling. That’s a great investment.