Build Numbers in Xcode (Revisited)

So after the suggestions given in the comments section the build script I’m using now uses PlistBuddy (which I wanted to use before but didn’t know the correct path), and increments only if we’re building the release build. (It was an interesting exercise to see my project’s build number go up into the thousands–but a build number that looks like a zip code isn’t really useful.)

Here is the current script which I’m using.

# Auto increment version number from build common file

use strict;

die "$0: Must be run from Xcode" unless $ENV{"BUILT_PRODUCTS_DIR"};

# Get the current revision number and use it to set the CFBundleVersion value
open FH, "build.count" or die;
my $version = join("",);
close(FH);

if ($ENV{CONFIGURATION} eq "Release") {
	++$version;

	open FH, ">build.count" or die;
	print FH $version;
	close(FH);
}

$version = "1.1 ($version)";
print "Build $versionn"; 

# Update info.plist in build product. Use defaults command
	
my $INFO = "$ENV{BUILT_PRODUCTS_DIR}/$ENV{WRAPPER_NAME}/Info.plist";
my @cmd = ( '/usr/libexec/PlistBuddy', '-c', "Set :CFBundleVersion $version", $INFO );
exec @cmd;

Note that this is Perl, which means you need to set the Shell to “/usr/bin/perl -w” when you set this as the run script phase.

This works on my iPhone software. For Macintosh builds you need to change the third-to-last line to:

my $INFO = "$ENV{BUILT_PRODUCTS_DIR}/$ENV{WRAPPER_NAME}/Contents/Info.plist";

And don’t forget to create a build.count file in the same directory as your project file and set the text file to the starting build count.

Why I hate custom protocols over HTTP.

One recent trend is to use HTTP in order to send data between a client and server. Between protocols built on top of SOAP and XML/RPC (and yes, I’ve built code on top of XML/RPC, and have a Java XML/RPC library), it’s not all that uncommon to send text commands over HTTP.

And it makes sense: HTTP generally is not blocked by various internet providers while other ports are firewalled, and it is well supported across the ‘net.

As a rule, however, I’m generally opposed to overriding an existing protocol for private use. My instincts are if it is possible for me to open a port from a client to the server that is not in use by an existing protocol, then use that port instead.

With HTTP, there are a number of downsides. HTTP is essentially a polling protocol: ask a question, wait for an answer, get an answer. There is a lot of plumbing that has gone into HTTP in order to work around the performance issues revolving around HTTP–but because it is essentially a polling protocol, there is little you can do to bypass a resource that takes a long time to download besides opening up a second connection. (Protocols like LDAP allow multiple logical connections over the same physical TCP socket.)

HTTP has also become somewhat more complicated over the years, with things like optional keep-alive settings and an array of possible return codes. All of this makes sense if you’re building a web browser (though some of it is a bit over-engineered: I don’t know if 418: “I’m a teapot” is a joke or a sarcastic response to things like 449: “Retry With”), but for a simple RPC protocol, we really don’t need more than “success”/”failure”/”exception.”

And today I learned another thing that just confirms my “don’t override someone else’s protocol; just build your own” instinct.

As designed the client I’m working on initialized a connection by requesting information on static resources that may have changed. So I’d do an “init” call, and wait for a response. As part of the request call, the server team specified that I should send “if-modified-since” with the date of the last response, so I can tell if I should update the cached response. (This was modified from the original idea, which was to simply use an integer version.) This client runs on Android both over WiFi and over the cell network.

You can guess what happened next.

Yes, T-Mobile rolled out a new proxy server to reduce 3G network traffic by automatically detecting and caching server responses, and sending ‘304’ errors on the init call. Well, if you send ‘if-modified-since’, you better process 304 errors, right?

My client didn’t.

And so it means the 130,000 people running our client software–died. Hard.

The first time you run the application it would sync up just fine. But the next time you’d hook up, T-Mobile would detect that your request hadn’t changed, and would send a 304 response–which the client would not understand, and eventually shut down claiming the client could not connect to the server.

And we never tested this. Of course we never tested this. Our server never sent the 304 exception, and so we never had a way to test this. In retrospect, of course “everyone knows” that if you send an if-modified-since, you should process the 304 exception.

The fix was simple, as all such things tend to be once they are discovered and understood.

But it would never happened if we had never overridden an HTTP protocol, where there are layers we don’t fully understand (until they break) running on a network which can insert any ol’ proxy (some with bugs we may never understand) between the client and the server.

ColorPicker

So the designer I work with gives me colors to use in our application as a web hex color specification, and I need to put it into my iPhone application as RGB values in the range [0,1]. Or I need to pick some color, and I pick an H=210° color, but I need to plug in the color into my application as integer RGB values. Or I need to type in [UIColor colorWithRed:xxx green:yyy blue:zzz alpha:1.0], and I’ve got r=110, g=250, b=155.

So out goes the calculator, and a lot of “155 [Enter] 255 [div]” and typing in the first three digits past the decimal place.

I’m a programmer. I can create tools.

So I built ColorPicker, a Macintosh-only program which allows you to set and adjust colors, and copy them in four different ways, so they can be quickly pasted into Mac, Windows or Java code.

Redistribute as you please, hopefully it will be useful to folks.

The Maker’s Dilemma

So here’s the problem if you’re a maker and someone is looking at you to be a manager.

On the one hand, a manager can accomplish far more than a maker, in the aggregate: look at Steve Jobs. One could almost look at Apple as an expression of Steve Job’s will; he has assembled some of the brightest minds to accomplish some really fantastic things–all in accord to his sensibilities.

On the other hand, being a manager is, for a died in the wool maker, a really shallow and annoying job.

And there is an additional penalty as one makes the transition from maker to manager. The difference between a really experienced software developer and a mediocre developer is, according to The Mythical Man Month, something like a factor of 25 in productivity. Further, when you start managing people, you find yourself spending time in meetings–meaning you can kiss about half of your day goodbye unless you adhere to a very strict scheduling regime. And even then, at best you can save four days out of five.

So this means that your first employee–being inexperienced at the product being worked on–will cause you to lose at least a factor of 5 in productivity in order to gain 1.

There is, in other words, a depression–a chasm–which forms between your best productive days as a maker, and as a manager leading a large team. The least optimal environment to be in is as a maker at the top of your game managing 2 or 3 makers who are just getting started.

In the end, if you continue and persevere, you can be even more productive–eventually–than you ever were as a maker. Maybe.

It becomes worse when the transition takes place when there is a need: in essence you’re doubling or tripling the salary burn rate while reducing overall productivity at a time when you can ill afford the lost in productivity.

And of course don’t forget you’re moving into that dreaded position: middle management, a position which, during the current recession, has proven to be expendable.

Words of Scheduling Wisdom.

Maker’s Schedule, Manager’s Schedule

One reason programmers dislike meetings so much is that they’re on a different type of schedule from other people. Meetings cost them more.

There are two types of schedule, which I’ll call the manager’s schedule and the maker’s schedule. The manager’s schedule is for bosses. It’s embodied in the traditional appointment book, with each day cut into one hour intervals. You can block off several hours for a single task if you need to, but by default you change what you’re doing every hour.

When you use time that way, it’s merely a practical problem to meet with someone. Find an open slot in your schedule, book them, and you’re done.

Most powerful people are on the manager’s schedule. It’s the schedule of command. But there’s another way of using time that’s common among people who make things, like programmers and writers. They generally prefer to use time in units of half a day at least. You can’t write or program well in units of an hour. That’s barely enough time to get started.

When you’re operating on the maker’s schedule, meetings are a disaster. A single meeting can blow a whole afternoon, by breaking it into two pieces each too small to do anything hard in. Plus you have to remember to go to the meeting. That’s no problem for someone on the manager’s schedule. There’s always something coming on the next hour; the only question is what. But when someone on the maker’s schedule has a meeting, they have to think about it.

For someone on the maker’s schedule, having a meeting is like throwing an exception. It doesn’t merely cause you to switch from one task to another; it changes the mode in which you work.

If you are a manager, please read the whole thing.

And if you used to be a maker and are now a manager, and you forgot the lessons in this article, then I only have one pleading question: why???

Automatic build numbers in Xcode

This one is a relatively simple mechanism for automatic build numbers. This increments the build number every time a successful build is made in Xcode.

Step 1: Create a new Run Script

In the target setting, add a new Run Script after the Link Binary With Libraries. Change the shell to /usr/bin/perl -w and paste the following script:

# Auto increment version number from build common file

use strict;

die "$0: Must be run from Xcode" unless $ENV{"BUILT_PRODUCTS_DIR"};

# Get the current revision number and use it to set the CFBundleVersion value
open FH, "build.count" or die;
my $version = join("",);
close(FH);

++$version;
print "Build $versionn"; 

open FH, ">build.count" or die;
print FH $version;
close(FH);

$version = "1.0 ($version)";

# Update info.plist in build product. Use defaults command

my $INFO = "$ENV{BUILT_PRODUCTS_DIR}/$ENV{WRAPPER_NAME}/Info";
my @defaults = ( 'defaults', 'write', $INFO, 'CFBundleVersion', "'$version'" );
exec @defaults;

Note: If this is for a MacOS X application instead of an iPhone application, then the third to last line should be:

my $INFO = "$ENV{BUILT_PRODUCTS_DIR}/$ENV{WRAPPER_NAME}/Contents/Info";

Step 2: Create the Build Count file.

Note that this Perl script pulls the version number from a file “build.count” which is at the same directory level as the project file. You should create a file containing the single character “0”.

Step 3: Build

Now you can test to make sure that the CFBundleVersion setting in the Info file is updated to “1.0 (1)”, “1.0 (2)”, etc. (The “1.0 ” part is set by the build script; change there to update the major/minor build numbers, or prefix the build with anything you want.)

This works by incrementing the build number in the build.count file, then using the defaults command-line tool (‘man defaults’ for more) to update the info.plist file after it is copied into the executable bundle.

The original concept came from Red Sweater Blog: Automatic Build Sub-Versioning in Xcode. However, in my case I wanted to do the build version count between check-ins, and we are currently using GIT. (But that’s another horror story.)

I will never understand social networking.

I will admit I will never understand the current craze of social networking. I don’t understand Twitter. I don’t get Facebook. (Actually I think Facebook is the spawn of Satan, but that’s a different post.) I don’t get MySpace. The idea of a software program on my cell phone broadcasting my current location to my friends is something I simply don’t grok: the idea that I should sacrifice that degree of privacy for some degree of notoriety seems strange to me.

In my day, the idea that the Government would be able to plant microchips in our minds in order to track our movements was a sure sign of madness–today we volunteer to carry around electronic devices we pay for (and pay the networking usage of) so we can install software that allows Corporations to track our every movement. (And if you suggested we would do this twenty years ago, my friends and I would have thought you were completely out of your mind certifiably insane.)

But I have to remember something: the 20-somethings I currently work with were 10, 11 and 12 when the World Wide Web was invented. For me, I still remember bang paths. It was how we routed mail before the invention of DNS. And I was in college at that time. I still remember when there was an informal injunction against ads on Usenet Network News because many of us were getting our Arpanet connections via a DoD contract, which prohibited advertising.

So the idea that we would use all of this to communicate with other people socially–or the idea that we would volunteer as much personal, private information to corporations who then promise to resell that information for advertising purposes–still strikes me as extremely strange.

When PR meets Blogging.

On our corporate blog I posted a somewhat irritated little screed, which was originally triggered by an e-mail message sent to me by a service provider who said that a pirated copy of our software, which was leaked by a member of the press, was using a test account for obtaining its location–and the test account was daily hitting its limit. That caused our pirated version of the software to stop updating its location–and the failure of the pirated copy to update its location was resulting in negative public reviews.

And PR rewrote the article.

Now I’m not irritated at the rewrite. The reality is that for a public facing corporate blog, the blog is owned by the corporation. If someone at PR decides they want to review all posts before they go out or if they decide to edit or rewrite all blog posts, that’s their prerogative: I’m not one of those fools who believes the First Amendment also applies to private citizens and corporations.

But I am irritated, from an intellectual standpoint, that my name is still associated with the post. I know, it’s counter-intuitive: most people would be glad to get credit on what is, in the end, a much better article than the one I originally posted. (It’s less obnoxious, for example.) But it’s the the guy who attended Caltech asserting himself: intellectual honesty demands that if someone rewrites my article, that person deserves the credit, not I.

Update: The request was acknowledged, and the post is now no longer in my name.

It could be that I will never be a successful CEO of my own corporation of a thousand person corporation: I don’t like giving credit where it is not deserved and I don’t like taking credit where it is not due. And from what I’ve seen over the past few years, corporation building seems to involve a lot of people taking credit where it is not due, and giving credit where it is not deserved. (I’m partially irritated because at one point in one conversation I had someone come up to me while I was standing in front of an investor ask me if we had a “great client development team,” and I replied “yes, we do.” Um, what team? Me, myself and I? But I had to play the game. Feh.)

The sad thing is I’m not even irritated that this is the world works. I may as well also be irritated by the fact that gravity makes me heavy, hot things burn, and occasionally into everyone’s life a little rain must fall.

The reason is simple, by the way: investors, customers, and the general public like to believe in a company, a product, an image. Our preconceived notions often make it difficult for us to believe that one person is responsible for a thing, or they want a single individual to root for. To violate this image–to suggest, for example, that Steve Jobs is not the center of the Apple Universe, or that some anonymous programmer drove the complete rewrite of iMovie’s new user interface–is to run against this public perception. And it causes people to lose confidence in what it is you’re trying to sell, when you show them what’s behind the curtain and it’s not what they think it should be.

The play’s the thing–even if the “play” is serving a customer at a restaurant, or providing them QA feedback, or downloading a cool free app from the Android Marketplace or the Apple iTunes App Store.

On a related note, it’s why I believe when there is a public facing corporate blog, individual bloggers should also have their own blog, separate from the PR feed. That way, individual posts from individual bloggers can be separated out from the main PR message.

We all have our own voices. It’s intellectually dishonest to run all of our voices through the PR speak filter–though I’m fine with PR asking for a post to be taken down because it violates a contractual requirement or doesn’t represent the public voice the company wants to project. I would never write the following sentence in a million years: “Although this was not an official release, we were thrilled to hear the overwhelmingly positive response to the application, and to see people really talking it up around the various social networks.” That’s because I don’t follow social networks. I’m a coder, I have better things to do than waste my time on Facebook. Marketing follows uptake; that’s their job. Mine is to produce great code within the platform, time, corporate and political constraints presented me.

Assessing how long it will take to write or fix code.

Like all developers, I hate giving estimates as to how long it will take to write some code or fix it. The real problem is that you can’t really honestly know how long it will take something until you’ve solved all the known-unknown and (worse) unknown-unknown problems. And by that time, well–you’re done.

There are, however, rules of thumb we can apply to estimate how long it will take to write some code: a feel for the size of the problem, a vague sketch of the architecture in your head, the mental checklist on the APIs you’ll need to access–and experience allows you to give a rough estimate on how long it will take to write new code.

For me, estimating new code is relatively easy: I have a rough feel for it. But estimating fixing bugs–that’s a whole different animal, because it consists of two sorta-known unknowns:

(1) How do I reproduce the problem? You can’t fix it until you can reproduce it, and sometimes it’s hard to figure out how to reproduce a problem.

(That’s why a good QA or QAE is so damned hard to find, but so invaluable to the development process: a good QA or QAE can give you specific steps to reliably reproduce a problem. It’s also why a well-written bug report must include specific steps which reliably reproduce a problem.)

(2) Is the problem a simple fix? Or am I going to have to rewrite something? Sometimes a bug is as simple as “oops, forgot to set up a variable before calling a routine”–and with good reproduction steps it could take just a few minutes to test, debug, validate, and push out to QA for verification.

Sometimes the problem requires a massive rewrite.

And you can’t know until you know what the problem is.

For me, I estimate these defects based on if the steps to reproduce are simple or if the problem is a vague “it crashes when I wave it through the air,” and if the area in the code sounds (and the nature of the bug) sounds like it’s a “hmmm, I wonder if I skipped an important step” or a “oh, God; do I need to rewrite that module?” And while you can get a feel for it, it’s not an exact science since you’re estimating the time to resolve two sorta-known unknowns (that is, I know they’re unknown, but I don’t know how unknown my unknowns are)–well…

To give a concrete example I got a bug report that said “sometimes it crashes when I start up the application.” Someone asked me for an estimate. I told them “I think it’s a simple crash, but I don’t know how to reproduce it. Maybe two days?”

Then QA privately e-mailed me with specific steps.

And two days became 15 minutes.