KISS in practice.

I was having a conversation with a co-worker, where I complained that the biggest problem with some of the code we’re working on is that it was over-engineered. I reminded him of Gall’s Law:

“A complex system that works is invariably found to have evolved from a simple system that worked. The inverse proposition also appears to be true: A complex system designed from scratch never works and cannot be made to work. You have to start over, beginning with a working simple system.”

He asked me a question about client-server interaction, and rather than shooting off a 140 character reply it seems to make sense to answer the question more fully here.

To summarize, we are building an application that communicates to a remote server using JSON over HTTP. The remote system is built on top of Drupal. (Honestly it’s not how I would have done it, because there seems to be too many moving parts already–but the folks who built the server assure me that Drupal is God, and who am I to complain?)

Now on an error there are several things that can go wrong. The remote server can return a 4xx or a 5xx HTTP error. It can return a JSON error. Or it could return an HTML formatted error (I guess they have some flag turned on which translates all remote errors into human-readable error messages.) The client is hardened against all of these return possibilities, of course, and is also hardened against a network failure or against a server being unresponsive.

So here’s the question: how should the client respond to these wide variety of errors?

On the server side, of course, there needs to be logging. We even do some device-level logging, and a mechanism is in place on our iPhone client to transmit that log in the background to the server if there is a problem. Because clearly from a developer’s perspective a 404 is not a 501 is not a 505 is not a “server is unresponsive” is not an “illegal character in the API” is not a “network down” error. So clearly we need to know what is going on so we can fix it.

But what does the end user need to know?

In my mind, handling this is very simple: what can the user affect?

In the case of a mobile device, the user can retry again later, or he can make sure he’s got good network reception. Period.

So in the event of a failure, the client’s behavior should be simple: if a connection fails, then test to see if the network is up. If the network is down, tell the user “I’m unable to talk to the remote server because your network is down.” And if the network is up, tell the user “Sorry, a problem occurred while talking to the server.”

And that’s it.

If the network is down, the user can try to turn it on: he can take the device out of airplane mode, or move to where he has reception, or turn on the WiFi. But it’s up to the user–we just have to tell him “Um, the network is down.” And let him decide how he wants to handle the problem–or even if he wants to handle the problem: it could be he clicked on our application while at 38,000 feet over the Atlantic.

If we can’t hit the server, but the network is up, then there is nothing the user can do about it. All we can do as software developers is make sure whomever is maintaining the servers that they should investigate the outage. All we can tell the user, however, is “sorry, no dice; try again later.”

And hope to hell our servers are reliable enough we don’t drive users away.

Making it more complex is silly. It doesn’t serve the user who may be stressed out by messages he can do nothing about anyway.

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.

Three Ways To Load A Nib. Only Two Work.

Someone I’m working with told me that you can load a NIB on the iPhone in the following way:

TestViewController *c = [[TestViewController alloc] initWithNibName:@"TestNib" bundle:[NSBundle mainBundle]];
[self presentModalViewController:c animated:YES];

However, this doesn’t appear to work. When chasing down the code, by the time TestViewController -(void)viewDidLoad gets called, self has changed; however, deep inside the lazy load of presentModalViewController the old pointer seems to be used because I get an exception indicating the view reference of the underlying UIViewController (that TestViewController descends from) was uninitialized.

There are two other ways to load the Nib.

First is using -(NSArray *)loadNibNamed:owner:options:

NSArray *a = [[NSBundle mainBundle] loadNibNamed:@"TestNib" owner:self options:nil];
TestViewController *c = [a objectAtIndex:0];
[self presentModalViewController:c animated:YES];

This seems to work, though the top level objects have been offset by one since v2.0 of the iPhone OS. (That is, this code will only work on v2.1 or later; if you build for v2.0 you must add one to the objectAtIndex index.)

The second way is the recommended way given in Apple’s documentation here:

// In my top level class
@interface TestRetainViewController : UIViewController 
{
    TestViewController *fController;
}
@property (nonatomic, retain) IBOutlet TestViewController *fController;
[[NSBundle mainBundle] loadNibNamed:@"TestNib" owner:self options:nil];
[self presentModalViewController:fController animated:YES];

This assumes there is a reference in the TestNib.xib file which points from the file owner object to the NIB.

One hitch about the second method, using an array: the array that is returned has a reference count of 1, but also has been set to autorelease. Thus you should either retain the array or the items in the array you want. The hitch about the third method, of course, is that because you’ve declared a property with retain semantics, you must also release the object on dealloc:

- (void)dealloc
{
    [fController release];
    [super dealloc];
}

You also can test to see if the NIB was already initialized in the call to loadNibNamed, however, in theory during NIB loading the reassignment to fController should release whatever was already loaded there before.

What tripped me up about the last project I worked on was that I was in such a rush to get very complicated NIBs built for an over-engineered UI, I created circular references and (more importantly) I wasn’t releasing any of the objects loaded via the NIB loading process. Turned out object connections on the iPhone are established using -setValue:forKey:, which does an automatic retain, and that means you need to release the reference in the -dealloc method.

What’s worse, if you don’t explicitly create the @property (or equivalent setXXX call according to the key/value rules, I believe simple assignment with retain is called–which means if you do multiple calls to loadNibNamed: above on TestNib but without the @property declaration, you’ll leak as each call simply overwrites the pointer.

Thoughts on project management.

Why don’t designers and developers have more power at many companies? The thought arises from the observation that newspapers could be saved if designers had more power.

I think the answer is fairly simple: there is (or rather, there should be) a clear difference between the functional requirements for a project, and the artistic and technological requirements to fulfill those requirements. For example, when designing a newspaper, the functional requirements may be to make the cover eye-catching for important news ‘above the fold’, to make the banner clear, and to make the contents easy to navigate. Technical functional requirements may also include information such as the number or placement of color pages, or the paper size itself, and business functional requirements may include the percentage of pages devoted to advertising.

Of course this should be obvious as hell. But in practice it is not, and I see two reasons why things fail.

First, they fail because the project manager or owner does not have a clear idea of the functional problems he is trying to solve, or doesn’t want to commit to a simple list of problems that he wants to solve. For example, a project manager managing a new software package who doesn’t know the target audience or understand the use cases for his software package is simply going to be unable to figure out what the functional requirements are–and a “swiss army knife” of functional requirements or (worse) a fluid and ever-changing list of core requirements spells disaster, because the manager or owner can never be made happy and the product will never ship.

Second, they fail because project managers or owners envision themselves as designers or developers or software architects, and rather than enumerate a list of core requirements and allow their people to do their jobs with some degree of flexibility, they micromanage the process. For example, I suspect most newspapers don’t allow designers to have power over the design of the newspaper because the newspaper owners think the page layout should be done a certain way or the newspaper should have a certain look. They don’t allow the designer any power, having decided that they (the owner) has more design experience than the designer.

Often, people who fall in the first category (they have no clue of the functional requirements) insert themselves into the process and fall into the second category (micromanaging the process, by second-guessing the hired professionals), simply because separating the functional from the design or development process requires experience. There is a difference between “make the newspapers headlines readable from a distance” and “use Helvetica 36 point type for the headline”–yet most inexperienced project managers are unable to separate the two.

My calculator project, again.

I just got back my 7 segment LED circuit boards from Pad2Pad, and hooked one up, and connected it to my HC08 for testing. The way this works is that the processor only needs to drive 4 lines: data, shift, load into display and reset. My test software program runs a 16-bit counter (of which we only see 12 bits), displaying the bottom three digits as hex as it counts upwards.

And here are the results:

Flawless! The circuit worked without any problems or needing any line cuts or jumpers. Hopefully I’ll have a chance to wire up three of these and hook it up to my calculator software soon…

Okay, Google: what were you thinking?!?

To my fuzzy little brain, the core of a ‘view’ object, be it an NSView, a JComponent, or a HWND object is simple: it’s a rectangular piece of screen real estate. It can draw into its piece of screen real estate. It gets called when it needs to be redrawn and when it is optionally clicked on. It gets called when its location inside the superview is changed. And it can have the ‘keyboard focus’ (whatever the hell you want to call that), so that keystrokes and menu commands are routed to it. And ideally it is embedded in a hierarchy of other views, and has a well designed event subsystem which allows unhandled events to be forwarded to the appropriate parent view or to other event handler abstractions in the system.

So to my fuzzy little brain, the Google Android OS should, when the aspect ratio of the screen is changed by opening the keyboard, send some sort of ‘size changed’ message. And perhaps as part of the message I can either just resize my children or, in a dramatic (but unlikely) case tear down and rebuild my contents–such as having a list view turn into a map view.

So when I read the following here:

Unless you specify otherwise, a configuration change (such as a change in screen orientation, language, input devices, etc) will cause your current activity to be destroyed, going through the normal activity lifecycle process of onPause(), onStop(), and onDestroy() as appropriate. If the activity had been in the foreground or visible to the user, once onDestroy() is called in that instance then a new instance of the activity will be created, with whatever savedInstanceState the previous instance had generated from onSaveInstanceState(Bundle).

This is done because any application resource, including layout files, can change based on any configuration value. Thus the only safe way to handle a configuration change is to re-retrieve all resources, including layouts, drawables, and strings. Because activities must already know how to save their state and re-create themselves from that state, this is a convenient way to have an activity restart itself with a new configuration.

(Emphasis mine.)

WT(bloody)F?!?

My calculator project

I figured a steampunk calculator would be made using a number of modules that are handcrafted from smaller components–so I just designed a circuit board which can drive 3 7-segment LEDs using a shift register circuit, and ordered 12 of the circuit boards from Pad2Pad. They’re 1.5 inches wide by 2.5 inches tall, and hold 3 LED segments; my calculator will then contain 3 of these for a 9 digit display: 6 digits to the left of the decimal point and 3 digits to the right, but with only 2 on by default. The beauty of the design is that I only need 4 control pins total: clear, shift, load and data, and I can drive the entire 9 digit display.

I also ordered a SP4T switch which I plan to use to switch between the four operators (+/-/×/÷), and a key switch to turn the calculator on and off. I also ordered C-cell holders for the 3v power supply. And a whole bunch of buttons for the calculator face.

Once I have the boards I can start testing the calculator code. In the meantime, when I have free time I intend to get the Java emulator of the HC08 working.

Calculators and 64-bit integer math.

Completed HC08 emulator in Java; will post as soon as I get a chance to validate the code. Also completed a basic 64-bit integer library for the HC08 that fits in about 1.2k. (Multiply and divide use shift/add rather than the HC08 mul and div instructions.) My goal: a basic floating point calculator written for the HC08.

Because who says a steampunk calculator should work like the el-cheapo four-banger calculators you get at the office supply store, but with brass inlay?