Vincent Gable’s Blog

December 16, 2008

isEmpty?

Checking if a Cocoa object is empty is a little harder then in other languages, say C++, (but easier in some ways). Because every object in Objective-C is actually a pointer to an object, there are two ways, obj, can be empty.

obj = {}

obj points to an object that is empty. Say an array with 0 items, or the string "", etc..

obj = nil

obj, the pointer obj, is NULL, nil, 0, or whatever you want to call it. You might argue that obj isn’t really an object, but it is empty, because there’s nothing in it.

Bug:

When I first started writing Objective-C, I made the mistake of writing code like: if([name isEqualToString:@""]){ ... }, to test for empty strings. And this code would work for a while until I used it in a situation where name was nil, and then, because sending any method called on nil “returns” NO, I would have mysterious errors. (Worse then a crash, because it’s harder to track down.)

Bug:

It’s tempting to avoid the previous bug, by explicitly testing for nil and {}. Say with code like:

if (email == nil || ![email isEqualTo:@""] )
   email = @"An email address is required";

But generally this is a bad idea. It means more code, which means more places for a bug. I know it’s only one trivial test, but I’m serious, when I say it’s asking for a bug — like the bug in the example above, which sets email to @"An email address is required", whenever it is not the empty string, rather then when it is empty. (Values have been changed tho protect the innocent but it’s a bug I’ve seen.)

Solutions:

Wil Shipley suggests using the global function:

static inline BOOL IsEmpty(id thing) {
    return thing == nil
        || ([thing respondsToSelector:@selector(length)]
        && [(NSData *)thing length] == 0)
        || ([thing respondsToSelector:@selector(count)]
        && [(NSArray *)thing count] == 0);
}

I’ve been using his IsEmpty() for about a year. I’ve had zero problems with it, while it’s made my code more readable and concise.

Another solution is to take advantage of what happens when you send a message to nil. (To over-simplify, you get back 0 or NO.) So you can just say “if ([obj count] == 0) then obj is empty.” This often means reversing your thinking, and testing “IsNotEmpty()” instead of “IsEmpty()”. I don’t think it’s as clear is IsEmpty() in general, but in cases where it is, there you have it.

December 8, 2008

Optimize CPU Usage of Your Website

Filed under: Programming,Quotes,Usability | , , , , ,
― Vincent Gable on December 8, 2008

The thing is, web developers should test their pages for CPU usage the same as app developers do. And anytime a page is idle, CPU usage should be at 0%. Same as with any other app.

Brent Simmons

Last quarter notebooks outsold desktops for the first time. Netbooks, and iPhones have been exploding in popularity as well. That means a significant number of your website’s visitors will be running off a battery, and since battery life decreases proportionally with CPU load, you really do owe it to your users to do this. The internet shouldn’t be something you have to be plugged into a power outlet to use.

December 4, 2008

Optimize People’s Time Not The Machine’s Time

Filed under: Quotes,Usability | , ,
― Vincent Gable on December 4, 2008

Bruce “Tog” Tognazzini gives the best example I’ve seen of optimizing a person’s time, not a machine’s time

People cost a lot more money than machines, and while it might appear that increasing machine productivity must result in increasing human productivity, the opposite is often true. In judging the efficiency of a system, look beyond just the efficiency of the machine.

For example, which of the following takes less time? Heating water in a microwave for one minute and ten seconds or heating it for one minute and eleven seconds?

From the standpoint of the microwave, one minute and ten seconds is the obviously correct answer. From the standpoint of the user of the microwave, one minute and eleven seconds is faster. Why? Because in the first case, the user must press the one key twice, then visually locate the zero key, move the finger into place over it, and press it once. In the second case, the user just presses the same key–the one key–three times. It typically takes more than one second to acquire the zero key. Hence, the water is heated faster when it is “cooked” longer.

Other factors beyond speed make the 111 solution more efficient. Seeking out a different key not only takes time, it requires a fairly high level of cognitive processing. While the processing is underway, the main task the user was involved with–cooking their meal–must be set aside. The longer it is set aside, the longer it will take to reacquire it.

You also need to consider actual performance vr perceived performance, when optimizing a user’s time.

Cocoa Coding Style Minutia: All Forward Declarations on One Line is the One True Way

This is a very petty point, but I believe there’s a right answer, and since it’s come up before I’m going to take the time to justify the best choice.

Forward Declare Classes on One Line, Not Many Lines

Right:
@class Foo, Bar, Baz...;

This is the style that Apple’s headers generally follow, look at NSDocument.h for example.

Wrong:
@class Foo;
@class Bar;
@class Baz;
...

Programming languages are to be read by people first, and interpreted by computers second. I really do hope anyone in software engineering can take that as an axiom!

Therefore, always favor brevity above all else with statements that are only for the compiler. They are by far the least important part of the code base. Keeping them terse minimizes distractions from code that can and should be read.

Naturally, it’s very hard to find a statement that’s only for the compiler. I can only think of one such statement in Objective-C, forward declarations of an object with @class.

What Does @class Do?

@class Foo; tells the compiler that Foo is an Objective-C class, so that it knows how much space to reserve in memory for things of type Foo. It does not tell the compiler what methods and ivars a Foo has, to do that you need to #import "Foo.h" (or have an @interface Foo... in your .m file.)

@class Foo; #import "Foo.h"
Foo is a black box. You can only use it as an argument. You can also send messages to Foo.

What is @class Good For?

Since #import "Foo.h" does everything @class Foo; does and more, why would you ever use @class? The short answer is less time wasted compiling.

Lets say you have a Controller class, and it has an ivar that’s a Foo. To get it to compile, you put #import "Foo.h" inside Controller.h. So far so good. The problem comes when Foo.h is changed. Now any file that has #import "Foo.h" in it must be recompiled. So Controller.h has to be recompiled. So any file that has #import "Controller.h" in it must also be recompiled, and so on. Many objects that don’t use Foo objects, but do talk to the Controller (or to something that talks to something that talks to the Controller!) have to be rebuilt as well. It’s likely that the entire project would end up being rebuilt. With even a moderately sized project, that means a lot of needless compile time!

One solution is to put a forward-declaration, @class Foo;, in Controller.h, and #import "Foo.h" in Controller.m, and the few files that actually do something to Foo objects. @class Foo; gives the compiler just enough information to build an object with a Foo* ivar, because it knows how much space that ivar will need in memory. And since only objects that need to talk to Foo objects directly have any dependency on Foo.h, changes to Foo can be tested quickly. The first time I tried this solution in one of my projects, compile times dropped from minutes to seconds.

Readers Need Less @class

Forward declarations add value to the development process, as does anything that saves programmers time. But @class tells a human reader nothing. Which is why I say you should use them in your code, but minimize the space they take up, by putting them all on one line.

@class Foo; tells a reader that “Foo is black-box that is a class.” That adds no useful information.

If the reader does not care about what a Foo is (they are treating it as a black box), then knowing that Foo is a class is useless information. Foo could be a struct, or a bit-field, or a function pointer, or anything else and they still would not need to know to understand the code.

Conversely, if they need to know what a Foo is to understand the code, then they need to know more then “it is a class”. They need to see Foo.h or documentation — @class just isn’t enough.

Exceptions

I want to again emphasize that this isn’t a big deal. I strongly feel that putting all forward declarations on one line is the right answer, but doing it wrong won’t perceptibly matter in the end.

So I don’t think there’s any reason to address exceptions to the rule. Do what you gotta do.

Best Practices

Use @class to speed up compile-times as much as you can, but use the keyword @class as little as possible, since it is for the compiler, not the person reading the code.

November 24, 2008

How To Space Your Code For Maximal Interoperability

Filed under: Design,Programming,Quotes,Usability | , , , , ,
― Vincent Gable on November 24, 2008

The new rule for indentation and alignment: use tabs for achieving an indentation level, spaces for character alignment within an indentation level.

Christopher Bowns (and independently Peter Hosey)

The arguments make total sense to me. Here’s hoping for better IDE support in the future. Unfortunately, (though interestingly), according to Steve Yegge, indentation is very hard:

I would have been publishing this article at least a month ago if it weren’t for indentation. No, six weeks, mininum.

See, I thought that since I had gone to all the thousands of lines of effort to produce a strongly-typed AST (abstract syntax tree) for JavaScript, it should therefore be really easy to do indentation. The AST tells me exactly what the syntax is at any given point in the buffer, so how hard could it be?

It turns out to be, oh, about fifty times harder than incremental parsing. Surprise!

Here’s a forward-looking (somewhat contrary) opinion,

Soft-wrapped code (leaving a long line long, and letting the IDE handle the spacing) also appears to be the direction that Apple are heading and they tend to drag a lot of Mac programmers along in their wake.

Matt Gallagher

November 3, 2008

Voting Done Right: Wait For It

Filed under: Design,Security,Usability | , , , , , ,
― Vincent Gable on November 3, 2008

Everyone wants to know the results of an election as soon as possible, including me. I will be spending tomorrow evening with friends, watching election results on live TV. I’ll be unhappy if a battle-ground state is slow to report, and I expect to know who the next president will be before I go to bed. But quick reporting of election results is in no way necessary, and in fact undermines our electoral system. We should put trustworthiness ahead of entertainment, and count votes deliberately.

According to the project triangle, you can do something quickly, you can do something cheaply, and you can do something well, but you can only do two out of three.

I propose that official tallies should not be released for 72 hours after polls close, by law. This gives us time to do voting right, and affordably.

A Hard Problem

Engineering a good voting system is a much harder problem then most people realize.

The system must be resistant to fraud by voters, and election officials, and the politicians on the ballot.

Voters must vote only once. But nobody can tie a particular vote to someone (that would allow voter intimidation and buying). But their vote must still be counted for the right candidate.

Tallies must be auditable (in case of a dispute a third party can re-count the votes). The whole system must be perceived as trustworthy and transparent by everyone.

Oh, and it has to scale to use by hundreds of millions of people on election day.

And all of this has to be built, and maintained, with very limited public funds.

This is a very hard problem already. Adding the extra requirement, “and final results must be ready two hours after polls close (so results can make prime-time TV)” would, in my opinion, make it an impossibly hard problem. Unfortunately, that is the direction we are moving.

No Need to Rush

Our electoral system was designed in an era when, cliché as it sounds, the pony express was the fastest way to communicate intra-nationally. Officials do not take office for several weeks after they have been voted-in. Delaying the certification of a successor until Friday would not incapacitate government. It’s always clear who the current officials are until new ones take office.

Of course, today we live in a faster, more connected, world. It could be argued that this means we have a modern need for instant results. Fortunately, this does not appear to be the case. The fallout of the Bush v Gore election in 2000 proved that society and government can function just fine for several weeks without knowing who won an election.

The Fear

Confidence in modern voting machines is rightly low. For the first time in nearly three decades, there will be a decline in the number of people casting their ballots electronically. Nobody (lobbyists aside) seems to really think that these voting machines are a working out for us, except that they do give “tallies” faster.

Personally, I am terrified of an all-electronic election. The reason is simple: it can’t be audited. Digital forensics just aren’t real enough. If someone stuffs a ballot box, they leave a trail of clues, down to the chemical composition of the paper. But there’s no record when bits are flipped to a crooked candidate. Any digital footprint can be faked. “Recounting” an electronic election would be pointless — asking the same program to run the same calculation, with the same data.

Of course, there are exotic solutions. It might be possible to develop a digital storage media that can only be written to once, and would record forensic information, like the time of each write. Unfortunately, none of these ideas sound remotely cost-effective. Which leaves….

Good old physical paper ballots. Slow, but sure, they are a proven technology that has earned our trust.

… then the Opposite of Progress is…

So why not simply mandate that paper ballots must be used for an election? Personally, I think that would give us a better election system then we have today. And it’s probably got a much better chance of happening then my idea of sitting on election results for three days.

But I don’t think it’s the best long-term solution. Historically, laws just don’t keep up with technology. And we have every indication that the pace of technological change is increasing. A little over seventy years ago, the Social Security Number was born. Today, we are stuck with them. I’m not convinced that paper will be the best medium for recording votes in 70 years.

Rather then dictating anachronistic implementations, it seems better to codify the right trade offs to make when designing a voting system. Then we can organically reap the benefits of advances in voting-technology, as we have historically.

The real problem is that we, as a voting public, are favoring quick results over reliable ones. This is a social problem, it is not a technological problem. It is best to directly address the social expectations, not the technological details.

But honestly… it will never happen. We like our prime-time TV and instant gratification too much. Withholding election results, even temporarily, feels too dictatorial. We can expect to get our votes counted faster every year. I just hope it’s not at the expense of counting them correctly.

October 26, 2008

Early Voting Machines

Filed under: Security,Usability | ,
― Vincent Gable on October 26, 2008

A fascinating article from 1936 on voting machines. They are not some new invention,

Inventors of the voting machine undertook to eliminate (improperly marked ballots). First man to give the problem attention appears to have been Jan Josef Baranowski in Paris, France, in 1849. He suggested that adding machine principles be applied to voting and that a closet be provided in which the voter could make his choice by turning handles or pushing buttons opposite the names of candidates. De Brettes in that year and Werner von Siemens in 1859 in Germany constructed primitive legislative voting machines, operated mechanically to cast either white or black balls. Thomas Edison patented a crude machine in 1869. At about the same time, Vassie, Chamberlain, Sydserff and Davy produced devices in England.

The exuberant article really puts the utter failure that is modern “electronic voting machines” in stark perspective. As security guru Bruce Schneier points out, “Complexity is the worst enemy of security; as systems become more complex, they get less secure.”

October 6, 2008

Returning Linux

Filed under: Quotes,Usability | ,
― Vincent Gable on October 6, 2008

Our internal research has shown that the return of netbooks is higher than regular notebooks, but the main cause of that is Linux. People would love to pay $299 or $399 but they don’t know what they get until they open the box. They start playing around with Linux and start realizing that it’s not what they are used to. They don’t want to spend time to learn it so they bring it back to the store. The return rate is at least four times higher for Linux netbooks than Windows XP netbooks.

MSI’s Director of U.S. Sales Andy Tung

October 3, 2008

Release When Ready

Filed under: Design,Programming,Usability | ,
― Vincent Gable on October 3, 2008

There are lots of people who strongly suggest that you should do your development in public. It is part of the “release early and often” concept. But I also believe that this concept is not effective in developing great ideas because it is limiting. The minute that you get real customers involved, their needs become much more pedestrian. They will yell loudly about things that may be important to their use of the product, but they will rarely yell about some new game-changing concept. In fact they will resist radical change and rethinking because it messes with their now committed workflow. And now you are comitted to supporting them. So as I see it you should strongly consider whether you have enough meat on your conceptual bone before you decide to release publicly. Because when you get users involved, it is the equivalent of putting the saw and the screwdriver down and grabbing the sand paper. There will likely be few additional big ideas after that point.

Hank Williams

September 27, 2008

Apple Has Learned The Importance of Play. We Should Too

Filed under: Design,Quotes,Usability | , ,
― Vincent Gable on September 27, 2008

…joyful playful exploration is critical to learning. Rote learning and memorization is less effective.

I believe that a big part of the reason that Apple has been successful is that they figured out long ago that their products had to have the elements of joyful exploration that are the hallmarks of great toys

Hank Williams

The short article is worth reading.

« Newer PostsOlder Posts »

Powered by WordPress