24 March 2010

The Interface Matters

This post builds on previous work by Fortnow 07. When you are interviewing for a faculty position, you must be mindful of how you are dressed, which is your interface to the world. Here, I'll talk about the basic rules.

The Very Basics
Let's start with some things we should talk about. All of these may be obvious to some of you, but with an abundance of caution, I think they are worth repeating. These rules always hold in professional settings, even when not interviewing:
  1. Whenever your shirt is tucked in, wear a belt. It literally and visually "ties" your top half and bottom half together. (Without the belt, something will look "off" that you can't explain. Think back to 90's sitcoms.)
  2. Don't wear a belt with suspenders. (The engineer in you should appreciate that this would be redundant.)
  3. Make sure your belt matches your shoes. You can pick either brown or black. You can never go wrong with black. (With brown, be sure you match the shade of brown, too.)
  4. Make sure your socks match your pants. For example: navy socks? navy pants. If you are really desperate, you can be safe wearing darker socks. But...
  5. Never, ever wear white socks. Not unless you are doing athletics.
  6. Your socks must be pulled up all the way. The rule is that you should be able to cross one leg over the other while seated without exposing your skin.
  7. A tie with patterns on it will conceal accidental food stains better than a solid color tie. Also, solid color ties will make you look too uniform.
  8. Find a tie that makes you feel "on." (Avoid cute ties for the interview.)
  9. Trim your finger nails.
Interview Rules
There are more rules you must follow when doing the academic interview:
  1. Your shirt must be tucked in. (As a result, wear a belt, and follow all belt rules.)
  2. Wear a button-up, long sleeved shirt. You can never go wrong with a plain white shirt. (For one day of the interview, you can wear a light blue shirt, and a white one the next.)
  3. Wear a suit. Because you will be traveling and having a very long day (which can involve all three meals with members of the committee), wear dark colors. Dark colors conceal stains and hide creases. It's always safe to go with dark navy.
  4. Don't button your suit jacket's bottom button, even when getting measured for alterations. The bottom button is for decoration only.
  5. Speaking of which, get your suit altered. It will look odd if the sleeves or the pants are too long (or too short, if you buy the shorter one thinking the longer is "too long"!). When you get your suit altered, bring your dress shirt too, and also get that altered. In the end, you will be very, very comfortable.
  6. Wear nice shoes. As a good starting rule, find ones with thin laces, which are dressier. A Google image search for "mens dress shoes" turns up what I mean, but pick conservatively: A single color (and not in  crocodile design) with laces (not a buckle) is what you need.
The above rules are non-negotiable for your interview. The question to ask yourself is: Am I helping my case? If you show up looking like a graduate student, you might only re-enforce concerns faculty may have already had. Also, you need to show that you care enough to follow the rules.

Now, some of you may be thinking about counter-signals right now. If you are a real hotshot, for example, can you get away with looking like a hobo? Maybe you can get away with it. But could it help? You'll be compared to other candidates, who will be as equally outstanding as you. If they happened to be wearing a suit, and had a well-practiced talk, with no errors on the slides, and done their research about the school and courses? People will say they were polished. It is very, very hard to make that a negative.

Dressing Down
If you do feel over dressed you can always remove your tie and unbutton your top two buttons. It's as simple as that.

I recommend Target's Merona line of suits, because you have a grad student budget. They are sold as separates, so be sure you read the labels of the pants and jacket to be sure they match exactly (you don't want to be caught with charcoal pants and a black jacket).

For undershirts, Banana Republic has some great cottons that are breathable and can move with you. They can also help whisk away sweat.

For dress socks, try a department store like Macy's. You want some that can go long enough. (Banana Republic oddly only sells novelty socks, which don't go high enough.)

Extra Credit
Since we are talking about fashion, here are some bonus rules:
  • Unless you are over 50 years old, don't have cuffs on non-pleated pants.
  • Generally, the button-down collar isn't as fashionable, particularly after 5pm... But academia is the exception! Go nuts with the button down, because the dean you meet will probably be wearing one too.
  • Also, as an academic, you can wear loafers too.
  • Go for a two button suit. You can try three, and one might be too radical. But please have your jacket be single breasted, not double. Otherwise, people will ask you where the dock is or will want to give you their drink orders.
  • When seated, don't have your jacket buttoned.
  • When you are tying your tie, give it that little dimple (shown to the right). It will keep the tie from looking flat. No one will likely notice, but, you've come this far, so you might as well know.
  • When you get into the hotel, run a hot shower and then hang your suit in the steam. The steam will help get out the travel wrinkles (from either your suitcase or from wearing it).
  • If you have problems with perspiration, get an antiperspirant and put it on the night before your big day. When you shower in the morning, then you can put on a regular deodorant or a light antiperspirant. Antiperspirants are weird, powerful things and it is the process of your skin absorbing them overnight that makes them effective. This holds even if you wash your armpits with soap the next morning. As such, you probably don't want to use that stuff everyday!
The single best way to make a suit work? Get the skinny cut. Based on the suit you start with (and your body type), you might need to ask for the sleeves to be narrowed. The slim fit prevents you from feeling like you are swimming in your jacket (or your pants). The slim fit is narrow, but it is not tight. Be sure you get a tailor who knows style. Avoid the alterations done at dry cleaners... those are basic alterations that won't make you look as good as you can. Instead, look for alterations at places that do wedding dresses and other things. If they don't know what you mean by a skinny fit, run.

If you followed my Merona recommendation, you may find yourself spending as much for the alterations and dry cleaning as you did on the suit itself. It may not last you for years, but it will still look great and you'll be better served than what they try to sell you at certain overpriced men's suit stores.

After following these rules for a while, you'll start to notice how others dress and you can get more ideas. You can also watch TV and see what the non-eccentric, good guy characters are wearing. (Don't go by what late night talk show hosts wear, which are often funny looking because their job is comedy!) Also, you can never go wrong seeing what The President is wearing. And, yes, his ties have a dimple.

21 March 2010

Beware Approximate Models

Joel Spolsky has closed his blog Joel of Software, but the discussion he started continues. One persistent article is on The Law of Leaky Abstractions. While there are other critiques of the claims in the article, none have quite settled on what I found unsettling about it. We must properly use abstraction and beware of both its advantages and limitations. In particular, it is dangerous to use an abstraction with an oversimplification of how it works.

What Abstraction Is
is a mechanism to help take what is common among a set of related program fragments, remove their differences, and enable programmers to work directly with a construct representing that abstract concept. This new construct virtually always has parameterizations: a means to customize the use of the construct to fit your specific needs. For example, a List class can abstract away the details of a linked-list implementation-- where instead of thinking in terms of manipulating 'next' and 'previous' pointers, you can think on the level of adding or removing values to a sequence. Abstraction is an essential tool for creating useful, rich, and sometimes complex features out of a much smaller set of more primitive concepts.

Abstraction is related to encapsulation and modularity, and these concepts are often misunderstood.

In the List example, encapsulation can be used to hide the implementation details of a linked-list; in an object-oriented language, for instance, you can make the 'next' and 'prev' pointers private, where only the List implementation is allowed access to these fields.

Encapsulation is not enough for abstraction, because it does not necessarily imply you have a new or different conception of the constructs. If all a List class did was give you 'getNext'/'setNext' style accessor methods, it would encapsulate from you from the implementation details (e.g., did you name the field 'prev' or 'previous'? what was its static type?), but it would have a very low degree of abstraction.

Modularity is concerned with information hiding: Stable properties are specified in an interface, and a module implements that interface, keeping all implementation details within the module. Modularity helps programmers cope with change, because other modules depend only on the stable interface.

Information hiding is aided by encapsulation (so that your code does not depend on unstable implementation details), but encapsulation is not necessary for modularity. For example, you can implement a List structure in C, exposing the 'next' and 'prev' pointers to the world, but also provide an interface, containing initList(), addToList(), and removeFromList() functions. Provided that the rules of the interface are followed, you can make guarantees that certain properties will always hold, such as ensuring the data-structure is always in a valid state.

Although terms like abstract, modular, and encapsulated are used as positive design descriptions, it's important to realize that the presence of any of these qualities does not automatically give you good design:

  • If an n^3 algorithm is "nicely encapsulated" it will still perform worse than an improved n log n algorithm.
  • If an interface commits to a specific operating system, none of the benefits of a modular design will be realized when, say, a video game needs to be ported from Windows to the iPad.
  • If the abstraction created exposes too many inessential details, it will fail to create a new construct with its own operations: It will simply be another name for the same thing.

Joel's So-Called Law of Leaky Abstractions
Joel's law of leaky abstraction states: "All non-trivial abstractions, to some degree, are leaky."

We should first pause to examine the law itself-- like similar "laws," it is not falsifiable. Based on how you define what is trivial or not, or what is leaky or not, any claim of leakability can be made about any abstraction.

So, we should look at what Joel identifies as leaks. Joel's leaks fit the following patterns:

  • Accidental Limitations - E.g., there is no perfect String class in C++, because the language lacks certain abstraction features. Poorly designed APIs are also limitations that are purely accidental.
  • Layering Limitations - E.g., TCP is layered over IP, and so it shares the fundamental limitations of IP, even though it provides new functionality built on top of it. NFS is an example of a layering that creates a new interface to a service, but cannot provide the same availability characteristics expected of other file systems.
  • Performance Limitations - E.g., SQL queries are supposed to be fully declarative (as if writing in relational algebra directly), but when performance matters, you must have intimate knowledge of the database's execution.

Accidental Limitations are a problem when it comes to using real code, particularly when that code is part of an API you need to use. Claiming the entire concept of abstraction is "leaky" because people can write poor code isn't quite right: We could try to claim the same thing about any other useful technique or tool that may be misapplied.

As for Layering Limitations, these aren't really "leaks": We cannot expect abstraction to do what is physically or computationally impossible (wires in a network can get cut, and hence your music over TCP/IP won't play).

That leaves Performance Limitations, and is the strongest argument Joel makes. When the term separation of concerns was coined, one concern described was efficiency. To get the best performance, we need to understand things like memory hierarchies and database engines. You can reason about efficiency separately from other concerns: For example, one day I can look at my database queries and reason about their correctness; and on another day, I can look at the same queries and reason about their efficiency. The query abstractions help me reason about correctness-- and even efficiency, because many optimization cases I would otherwise need to worry about are handled for me.

Why can't the efficiency concern be properly isolated? Because efficiency is inherently a crosscutting concern. Any single weak-link in a chain of unbelievably fast code will drag the entire performance of the system down with it. Research in aspect-oriented programming, which is focused on isolating crosscutting concerns, has had limited or only domain-specific successes in isolating efficiency concerns. It is a hard problem, the philosophy of which would lead us to talk of artificial intelligence and computational complexity.

So, in examining Joel's argument, we find he wants us to believe the problems of efficiency are related to the problems of poor written APIs and also the problems of fundamental limitations. No wonder he is left to conclude that abstraction is "dragging us down." But we don't have to be so gloomy.

Leaks that Aren't
Because abstraction cannot do the impossible, and because isolating efficiency concerns is a long shot possibility, we have to be careful when using abstractions. In particular, we must be sure with the abstractions we use that we are modeling them correctly.

Donald Knuth has said that a computer scientist must have "the ability to work with multiple levels of abstraction simultaneously," from high-level to low-level.1 We cannot work with simpler models in our minds just because we are working with something that looks simpler.

Let's look at garbage collection as an example. Today, unless a language is meant for writing operating systems, virtual machines, embedded systems, or any other exceptions, it will have garbage collection. The basic idea is that you can allocate memory, but do not have to worry about deallocating it. However, that is the basic idea, and not the true abstraction! In reality, we don't have infinite memory. Here is the actual idea behind garbage collection:

Allocated memory that is no longer reachable from any of the program's threads can be safely deallocated by the garbage collector.

This idea is radically different from the infinite memory idea. For instance, we now have to know about the concept of reachability. How does this change the way we use garbage collection? Under the first, approximate model of GC, we will be lead to memory leaks under certain circumstances. In the second, correct model of GC, we will prevent memory leaks because now we know about WeakReferences.2

By thinking that the GC "is magic," we will be lead down the wrong path. For example, there are times when we know that an object "will no longer be used," but that is not the same as "is no longer reachable." Thus, if we have the right conception of the GC in mind, we find ourselves using WeakHashMaps more frequently.3 My rough estimate is that 20% of the HashMaps I use need to be WeakHashMaps; without the proper conception of GC, then a significant portion of my code would be wrong!4

Abstraction is about Design
Abstraction is not primarily about overcoming fundamental limitations of the machine or its environment. Abstraction is about organizing your code to match your conceptions of your design.

Although abstraction provides many benefits that simplify the task of programming, these simplifications are not strictly necessary. We can write our programs without so many abstractions. For example, whenever we need a Node structure that holds a value and pointers to two other Nodes, we can use a simple Node class, and use it for both a doubly linked-list and a binary tree. If we programmed like this, we could even save a few lines of code: The routine to get the right-most node of a binary tree could also be used to iterate through a doubly linked-list.

We should stop thinking of abstractions necessarily as higher or lower level than each other. Abstractions are relative to your design, and what looks like "the same" abstraction in one case can be too high level (leaving out too much), too low level (over specified and lacking flexibility), or just right.

Instead, think about abstractions as providing support for your design conceptions. If, in the process of creating your abstractions, you are lead to "leaks" then the problem is in your design.

1. Further quoted: "When you're working at one level, you try and ignore the details of what's happening at the lower levels. But when you're debugging a computer program and you get some mysterious error message, it could be a failure in any of the levels below you, so you can't afford to be too compartmentalized."

2. And SoftReferences, for when performance concerns are high.

3. Also see Google's MapMaker factory: new MapMaker().weakKeys().makeMap().

4. When thinking about memory, we also need to remember that Accidental Limitations do come up. For example, when using the substring method, you may need to wrap it around a call to new String().