Managerial Abuse.

One of the most interesting comments I ever read in any documentation was something I encountered years ago in Apple’s documentation. It was a technical note discussing using the Apple Macintosh Toolbox, and the key point was essentially that you should not just follow the rules, but you should go the extra step and follow the “gestalt” of the rules. A similar technical note observed that you should not abuse certain managers and use them for functionality they were not designed to handle. Ultimately it was about writing code that not only used the API according to the letter of the law, but also used the API in a way which observed the spirit (and the underlying design goals) of the API.

I have found this in general to be very sound advise, and it amuses me greatly (in a sick and perverted way) to watch programmers stretch the rules because they thought something should be done one way, and suddenly their stuff stops working because their changes went against the grain of the design rules of the platform they’re writing code on.

The latest example: I’m working on a program which at one point needs to access web pages on the iPhone and display them. The developer I’m working with has some very strong ideas as to how the HTTP protocol should work–and apparently his strong ideas have little to do with common HTTP practice. For example, the two common ways to pass parameters to an HTTP server is (a) ‘GET’ parameters, and (b) ‘POST’ parameters in the body of the request. So what does he want to do? Put the parameters in the HTTP header as ‘X-company-xxx’ extensions. And he wants the iPhone to always send these parameters, even from the UIWebView class within the iPhone.

So how did he want to accomplish this feat?

On the iPhone every web request through UIWebView triggers a callback to the -shouldStartLoadWithRequest: delegate method to the UIWebView delegate. The parameter passed is a NSURLRequest.

But it turns out this is actually a NSMutableURLRequest when the user clicks on a link. So, his solution was to cast the NSURLRequest (as advertised in the interface) to an NSMutableURLRequest, verify that it responds to the setValue:forHTTPHeaderField: callback, then populate the new values he wants to send back:

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)req navigationType:(UIWebViewNavigationType)navigationType
{
    NSMutableURLRequest *request = (NSMutableURLRequest *)req;

    if ([request respondsToSelector:@selector(setValue:forHTTPHeaderField:)]) {
        [request setValue:@"myValue" forHTTPHeaderField:@"X-Company-parameter"];
    }
    return YES;
}

Upon reading the above, if your reaction is “hey, that’s pretty clever”, please leave your name and address in the comments section of my blog so I can make sure I never work with you ever, in any professional capacity. However, if your reaction was “ick”, then your reaction was the same as mine. It took two people to convince me to let it go–with my ultimate reaction being “hey, it’s your code. Just as long as you deal with it when it bites you in the end, go for it.”

And guess what? It bites you in the end. By overriding this method and manipulating the request, for whatever reason, map URLs (that is, http://maps.google.com URLs which would otherwise bring up the Apple Google map application) break in this situation.

Managerial abuse bites you in the ass in the end because you start making assumptions about how the underlying system works. And if the system doesn’t work that way, then a future revision to the operating system will break your application hard, and sometimes in very hard to detect ways.

And in this case, this story abused two things: (1) It abused a channel normally reserved for low-level client/server interaction to send information in HTTP that should otherwise be sent in the traditional way with GET or POST parameters, or that should otherwise be handled with cookies. (This abuse puts additional requirements on how client code should behave when interacting with a web site, and these other requirements may effectively pre-empt porting the client to operating systems which don’t provide a mechanism to stuff HTTP header fields on web browser initiated clicks.) (2) It abused an existing API by coercing a non-mutable object through pointer casting into a mutable object, assuming the underlying object will always be mutable.

Thus, life is made unnecessarily complex, and for no better reason than the fact that a developer wants to invent an ad-hoc standard outside of the “gestalt” or design guidelines of the existing spec–only so he can show off just how clever he can be.

Leave a comment