Taking Time Seriously Bryan O’Sullivan Twitter: @bos31337 Monday, June 18, 12
Let’s talk about mental effort Our attention is a fragile thing. Humans are easily distracted. Let’s illustrate. Try this, while I continue to talk: •Mentally compute the product 76 × 12 Monday, June 18, 12
Doing math in your head For most of us, multiplying multiple-digit numbers is an effortful task. Chances are: •If I asked you to perform that calculation while we were walking together, •You’d need to stop for a few moments to complete it. Monday, June 18, 12
That bit of mental arithmetic In case you couldn’t get there (due to my deliberate distractions): 76 × 12 = 912 Monday, June 18, 12
By the way... If you did the arithmetic exercise in your head... ...can you tell me what kind of creature was on the screen two slides ago? When you’re focused on one thing, it’s easy to miss something else that would normally be obvious. Monday, June 18, 12
The alternative to attention We know from experience that sustained concentration is draining. Your brain greatly prefers to operate in a less demanding mode, making rapid intuitive judgments. As designers and programmers, we need to keep this intuitive mode of thinking in mind. Monday, June 18, 12
Imperative programming I often hear traditional imperative programming described as “intuitive”. Let’s have the horizontal line represent its difficulty. Monday, June 18, 12
Functional programming I’m just as likely to hear experienced programmers call functional programming “ non -intuitive”. Again, the length of the horizontal line marks its difficulty. Monday, June 18, 12
Which horizontal line is longer? Monday, June 18, 12
They’re the same lengths! Many of you will already know the famous optical illusion on the previous screen. It’s called the Müller-Lyer illusion. This illusion sheds a little light on how easily our intuitive judgment can go wrong. Monday, June 18, 12
For what it’s worth... I divide my professional life between imperative programming (C, C++, Python) and functional programming (Haskell, Lisp). I’d be hard pressed to call either one inherently intuitive. (Or, for that matter, one more intuitive than the other.) Monday, June 18, 12
What has this to do with shipping code? As programmers, we of course work with our brains all the time. We’re often aware of when we switch between cognitive modes. Some examples of each mode: • Intuition mode: the code just comes flowing out • Attention mode: fixing a bug, designing a new algorithm Monday, June 18, 12
The perils of programming Intuition mode usually serves us well, which is why it’s our default. •As we’ve seen, it can lead us to efficiently make mistakes that we don’t notice. Attention mode is brought to bear when the going gets tough. •It’s slow going, often limited in power, and easily fatigued. Monday, June 18, 12
Intuitive-mode programming in MySQL typedef char my_bool; my_bool check_scramble(const char *scramble_arg, const char *message, const uint8 *hash_stage2) { uint8 hash_stage2_reassured[SHA1_HASH_SIZE]; /* ... uninteresting stuff ... */ return memcmp(hash_stage2, hash_stage2_reassured, SHA1_HASH_SIZE); } Monday, June 18, 12
That code looks... perfectly reasonable? And yet the line containing a call to memcmp is wrong. An attacker who can talk to a vulnerable MySQL server can authenticate as any user in ~256 attempts. Without knowing any passwords. How did this happen? Monday, June 18, 12
How did this come about? The FreeBSD / Mac OS X man page for memcmp : The memcmp() function returns zero if the two strings are identical, otherwise returns the difference between the first two differing bytes (treated as unsigned char values, so that '\200' is greater than '\0', for example). Clear as mud, right? (Linux, POSIX, and ISO word it better.) Monday, June 18, 12
My guess The author made an intuitive-mode assumption that the implicit cast from int to char would be safe. In all likelihood, they did not even know that they were making this assumption. Ever made this kind of programming mistake? I make them all the time, after 20 years of experience. Monday, June 18, 12
Air France 447 On May 31, 2009, this Airbus 330 was lost without trace or emergency call over the mid Atlantic. Not until 23 months later was the cockpit voice recorder recovered. The reconstruction of events on board the flight is haunting for what it tells us about decisions made under pressure. Monday, June 18, 12
Modern flight control systems The A330 is a heavily automated fly-by-wire aircraft. At the time its troubles began, 447 was on autopilot, flying into a tropical squall that most aircraft in the area were carefully avoiding. An autopilot depends on a device called a pitot tube to report the plane’s air speed. Pitot tubes are vulnerable to moisture and ice build-up, so passenger planes tend to fly with three, for redundancy. Monday, June 18, 12
The ice problem All three of 447’s pitot tubes iced over at more or less the same time. The autopilot disengaged due to loss of airspeed data. Minutes beforehand, the captain had left the flight deck for a nap, leaving his two second officers in charge. One of the second officers responded to the autopilot alarm by increasing thrust and pulling the plane’s nose up. Monday, June 18, 12
The last three minutes With the nose up at high altitude, the plane quickly lost airspeed, stalled, and entered a rapid descent, losing 10,000 feet per minute. One second officer seemed to be confused by the plane’s behaviour and kept the nose up, even though this was precisely the wrong thing to do. He failed to tell his colleagues what he was doing, and they did not ask. Monday, June 18, 12
What do these episodes have in common? Each was an elementary misjudgment, by an experienced individual, with severe consequences. We routinely make quick decisions in complex situations. Being under pressure magnifies the likelihood of snap misjudgments. Luckily, we often get to walk away from our mistakes more or less unscathed. Monday, June 18, 12
The startup environment As a startup founder, you’re routinely under pressure from investors and customers. You’re probably creating entirely new software that is quite unfamiliar. Your product has to ship yesterday, and impress right away. You can afford mistakes, but they’d better be few in number and cheap to rectify. Monday, June 18, 12
I built my startup’s software in Haskell This seemingly unconventional decision was driven by one major consideration. I wanted to ship reliable code quickly. At the time, this did feel like a slightly sketchy decision. •The Haskell ecosystem was exciting, but not so mature. In retrospect, it was a lot of work, but still a great idea. Monday, June 18, 12
The importance of a good type system For me, the most important “I need to ship stuff” aspect of Haskell is its type system. The type checker tells me about many (usually simple) logical errors in my code before I can even execute it. Monday, June 18, 12
Type safety and password checking As a trivial example, that MySQL password bug can’t happen in Haskell. Why not? Ordered comparisons return results of type Ordering •This is distinct from numeric types, unlike my_bool . There’s no automatic promotion (casting) of values. • We can’t implicitly convert from Ordering to Bool . Monday, June 18, 12
A more realistic example of types at work My company’s product consisted of client (C#) and server (Haskell) components. They needed to be able to communicate, so I wanted to go down the typical REST/JSON road. One problem with the Haskell ecosystem at the time was that I didn’t much like the existing JSON libraries. So I wrote one. Monday, June 18, 12
The anatomy of a typical JSON library The jansson library is a clean JSON library, written in C. It has a classic OO-in-C architecture. Its core public type is abstract: typedef struct { json_type type; size_t refcount; } json_t; Monday, June 18, 12
What’s json_type? The oft-seen “represent the type via an enum in a tag” pattern. typedef enum { JSON_OBJECT, JSON_ARRAY, JSON_STRING, JSON_INTEGER, JSON_REAL, JSON_TRUE, JSON_FALSE, JSON_NULL } json_type; Monday, June 18, 12
Inspection How does a user tell what kind of value inhabits a JSON structure? #define json_is_object(json) \ (json && \ json_typeof(json) == JSON_OBJECT) (Incidentally, can you spot a problem with this cpp macro?) Monday, June 18, 12
Construction What if I need to build a value? json_t *json_object(void); int json_object_set_new(json_t *object, const char *key, json_t *value); int json_object_del(json_t *object, const char *key); int json_object_clear(json_t *object); int json_object_update(json_t *object, json_t *other); This is only about a quarter of the API for just the JSON_OBJECT type. Monday, June 18, 12
Using jansson If I use this library, I’m responsible for a lot of stuff. •Be careful about which API entry points are CPP macros, and which are functions. •Manually check types of inputs, and results of functions. •Correctly follow the refcount rules. Par for the course for a C library, in other words. Monday, June 18, 12
Recommend
More recommend