Grumpy Old Men, Opacity, and Optimizers

Today I’m channeling my inner grumpy old man. And these guys are helping. (I am not old enough to pull off such a face by myself, although life is rapidly helping me get there. ;-)

Grumpy old men.

The reason I’m feeling grumpy is that I’ve had another in a long, long line of conversations about how to write faster code.

It’s not that optimization experts are dumb. Far from it. They are invariably smart, and in general, they are better informed than I am about how pipeline burst cache and GPUs and RAM prefetch algorithms work. I generally learn a lot when I talk to guys like this.

I applaud their passion, even if I think they sometimes get carried away.

No. What’s making me grumpy is that after decades of hard work, we still have compilers that encourage a culture of black magic and superstition around this topic. I thought I signed up for computer science, not voodoo.

To show you what I mean, let’s talk about the humble inline keyword in C and C++. The amount of FUD and nonsense around it is really unfortunate. How many of the following have you heard?
Continue reading

Smart Geeks Think Like Cheerleaders

Technorati code: FMUS579NQBM8

Saturday I went to a high school half an hour north of our home, to watch my 16-year-old daughter compete in a cheerleading competition. And I learned something about software.

Photo credit: neys (Flickr)

I’m not sure how many teams were there–maybe a hundred. The competition started at 9 am and was scheduled to run through 5. Every team consisted of dozens of girls, all dressed in spangles and glitter, with identical ribbons in their hair. They’d march out onto the floor, drop their heads and arms to their sides, and wait for the first blast of music to initiate the routine. Then they’d tumble and dance their hearts out, finishing out of breath with a flourish.

Every hour or so, the performances suspended so judges could announce winners in a particular division that had just fielded its last competitor.

I noticed a pattern. Even though I have no knowledge of competitive cheer scoring, I could tell who had won. Continue reading

3 Commandments of Performance Optimization

In my experience, most programmer attitudes on speed fall into one of these categories:

laissez-faire

Programmers with this mindset think about performance on occasion, but it’s not a big focus. Occasionally they’re forced to tackle problems because a particular design is too slow, a customer is unhappy, or new scaling requirements materialize. In such cases, they experiment until behavior improves, and then go back to the work they really care about.

passionate

Programmers with this mindset have a hard time not thinking about performance. Every design they do reflects elaborate consideration of how to minimize footprint and/or how to complete a task in the shortest possible time. (Note that those two priorities often conflict.) Programmers who are passionate about performance often feel like their laissez-faire counterparts are derelict in their duty.

I don’t think either of these extremes is healthy in all cases. I have seen programmers who chronically think about performance too late,  creating large refactoring burdens and sabotaging their company’s success. Sometimes when you go from “make it work” to “make it fast” you find that all your original work is a waste, because a totally different design (even different tests, conceivably) is the only way forward; I wrote about this in “A Quibble with Martin’s ‘Optimize Later’ Notion“.

On the other hand, it is possible to be too passionate about performance; optimizing the performance of the dev team (by decreasing coding and testing time) is often a better business choice than optimizing execution speed in ways that make code more complex and harder to verify. I have encountered performance zealots disqualifying a perfectly good design on the grounds that it’s not performant enough in a use case that only 2 customers on the entire planet would ever care about. Not smart. As I’ve said many times, good code is balanced.

ThrustSSC — the first car to break the sound barrier. Sometimes speed is the ultimate criterion. However, most money is made on cars with more modest performance requirements. Photo credit: cmglee (Wikimedia Commons)

Let’s assume you buy my criticism of the extremes, and you’re willing to apply the “it depends” doctrine. Continue reading

Ken Ebert: Kill three birds.

(A post in my “Role Models” series…)

Killing birds is just a metaphor; who’d want to hurt something this cute? Photo credit: Valerian Gaudeau (Flickr).

Most people optimize for a single outcome.

Ken Ebert is made of smarter stuff.

When I began my career, I was like many engineers–keenly aware of issues like code quality and performance, but not so clued in to customer experience or business priorities. I’d go to team meetings, get new assignments, and head back to my cube to code away. If I was unsure how to accomplish my goals, I’d ask a senior engineer, and do my best to reflect the values they cared about. After all, they were the experts.

It gradually dawned on me that some of my engineer mentors (not many; geeks are better-rounded than popular stereotypes make them out to be…) suffered from a kind of myopia. They could build complicated and highly functional things, but they had little interest in how their constructions mapped into sales, revenue, and company success. I went through a revolution in my perspective, got religion about user experience, and spent a lot of time learning from product management.

In 2003, Symantec acquired several companies in rapid succession, and threw five sites together into a new business unit with marching orders to build a suite and conquer the world. I was tasked with architecture across the picture, and my perspective expanded again. Now it wasn’t just a single product’s success I was worrying about–I had to make or shepherd design decisions that enhanced the profitability of multiple independent products as well as the amalgam of all of them. Was it more important to make codebase X localizable, or to invest in a better install for codebase Y? If team A moved to a newer version of tomcat, would it break the integration story for our suite or impose undue burdens on team B? Resources were constrained (they always are!), time was short…

I began to sense that the way I made decisions needed to change, but it wasn’t until I worked intensely with Ken Ebert, years later, that I could put into words exactly how.

Making wise decisions about architecture, SOP on dev teams, product features, investment in R&D versus marketing–it’s like trying to solve an equation with multiple variables. Profit maximization requires that you consider more than one input at a time. This is partly what I had in mind when I blogged about the need for balance in good code, and when I blogged about optimization.

Many times I’ve heard Ken say something like this: “I think we should make feature N the centerpiece of our next release.” And my first response has been, “That’s doable, but kinda boring. Why not focus on M instead?”

When Ken nods sagely at my question, I know what’s coming.

N is glamorous, and low-risk, but it’s only useful to 3% of our customers. If we build M, we’ll address a sales inhibitor for half the funnel, plus we’ll be positioned to do features P and Q on our long-term roadmap, plus I’ll be able to get an analyst to write about it, plus …, plus …”

Ken doesn’t just kill two birds with one stone. He kills three, or five, or six.

I’m not sure how Ken manages to be so good at this, but here’s what I’ve done to try to approximate his success:

  • Evaluate in multiple time horizons.
  • Evaluate for the channel as well as direct sales.
  • Evaluate for support and professional services as well as dev.
  • Evaluate for marketing value.
  • Evaluate for opportunity cost.
  • Evaluate with an eye to domino effects.
  • Evaluate for morale and momentum.
  • Evaluate for technical debt.

Of course, nobody can do all of these, exhaustively, all the time. Don Kleinschnitz’s wisdom about putting a stake in the ground is an important counterbalance. But I find that I can think, at least briefly, about ramifications of a choice from multiple perspectives–and when I do, I often make better choices.

Thanks for the lesson, Ken.

Action Item

Look at the bulleted list of perspectives above; find one you’ve been neglecting. Pick a significant decision that’s on the horizon, and spend some time thinking seriously about that decision in the context of the neglected perspective. What did you learn?

A Quibble With Martin’s “Optimize Later” Notion

In Refactoring, Martin Fowler (a brilliant engineer whom I greatly admire) articulates an idea that I have heard from smart engineers for a long time: first make it work, then make it fast. He puts it this way:

“Until I profile I cannot tell how much time is needed for the loop to calculate or whether the loop is called often enough for it to affect the overall performance of the system. Don’t worry about this while refactoring. When you optimize you will have to worry about it, but you will then be in a much better position to do something about it, and you will have more options to optimize effectively.”

I mostly agree. Certainly, premature optimization can cause lots of problems (pollute an otherwise clean design, overvalue corner cases, dilute conceptual integrity), and profiler-driven optimization (science, not black magic!) is the way to get the best results. Donald Knuth famously observed that “premature optimization is the root of all evil” — a bit over the top, maybe, yet true often enough to give me fits.

But implicit in Fowler’s advice are the following problematic notions:

  • Optimization is a discrete activity from ordinary coding. Especially, it is discrete from refactoring.
  • Between the time that you code an original or refactored version, and the time you optimize, the existence of unoptimized code will have negligible effect on how the rest of the code’s ecosystem evolves.

The flaws in the first notion should be obvious; optimization often requires concommitant refactoring. I won’t beat that dead horse here. The second idea, however, deserves further comment.

Sometimes the only time to optimize is before decisions get made :-). Image credit: xkcd

Before you get around to optimizing, what happens if programmers go looking for an API that does X, find your works-correctly-but-suboptimally function, and wrinkle their nose. “Code smell!” they cry. And they write their own function that does a binary rather than linear search, etc. They don’t have time to investigate whether the original version was coded that way for a reason (and thus should simply be refactored); they just need something that works AND that is fast, and your function doesn’t cut it.

I have seen this happen over and over and over again. Late optimization, while smart in many cases, must be managed (communicated, commented, evangelized, trained, reinforced, audited, planned for) carefully or else it will provoke a lot of NIH and contempt from (ironically) less savvy programmers. Result: more guck that needs refactoring.

Action Item

Find a notoriously sub-optimized function in your code. Study how its existence in non-optimal form has influenced how other code has evolved.