Wednesday, March 25, 2009

Safari Flash Fail

This happens to me a lot:

Take a look at the stack trace that gets sent to Apple:

So I think this is being caused because I set the storage allowed by the Flash player to 0 KB. The default is 100 KB. Why do I have it set at 0 KB? It's not because I am some privacy fanatic, just the opposite in fact. It was because I was debugging some PayPal code a few months back that required that Flash local storage be unavailable. Most sites then ask to set it back to the default 100 KB. However, if the SWF in question is too small to show the settings dialog, then it can't show the dialog to ask the user to set the amount of local storage for the site. You can right-click any SWF to bring this setting up, well any SWF that is biggest enough to display the settings manager. This is on a per site basis, but you can set things globally as well. Dealing with the error that is thrown when setting data fails is what I helped PayPal with. Obviously there are a lot of sites that do not deal with this error, and that seems to bubble up in Safari and cause it to crash.

Friday, March 20, 2009

iPhone OS/SDK 3.0: Remote Notifications

If you are an iPhone developer, you were probably excited about Apple revealing a beta of OS 3.0 and the corresponding beta of SDK 3.0. There was a lot of excitement and speculation over what new features would be available in 3.0. One of the most anticipated ones was Push Notifications. Everyone thought that Apple would release this since they had promised it in the past, and they were right. So how do you use it? That was the question I asked myself, and here is what I have been able to figure out so far from the documentation.

The first thing you need to do is have your application call the new API registerForRemoteNotifications. This a new API on UIApplication. So when you create your app's delegate (i.e. the class that conforms to the UIApplicationDelegate protocol) you will probably want to invoke registerForRemoteNotifications in your applicationDidFinishLaunching: method (or in the application:didFinishLaunchingWithOptions: method, more on that later.) This will cause the UIApplication to send a request to the Apple Push Service (APS) and it will respond with a token.

When the UIApplication receives that token, it will invoke your app delegate's application:didRegisterForRemoteNotificationsWithDeviceToken:. As the name implies, you get a token as one of the parameters to this method. Your application needs to send this token to your servers. When your server then determines that a notification needs to be sent to a particular device, it will send a request to APS using this token. That is how APS knows where to send the notification to, and also what application the notification is being sent to. It looks like you are pretty limited in what you send to APS, i.e. you do not send (much) application data to APS. You just send it a message saying "hey tell this device that I've got something waiting for it." APS will send this to the user's device.

So the notification arrives, and now there are two possibilities. First, the user is still using your application. In that case, your app delegate is once again invoked, this time it's application:didReceiveRemoteNotification: method is invoked. This lets your app know that you need to phone home to your server and go get the new yummy data.

If your application was no longer active, i.e. that pesky user quit it so they could do something else, then the user will receive a pop-up asking them if they want to launch your application because a notification has been sent to it. If they choose to do so, then when you application launches the app delegate's application:didFinishLaunchingWithOptions: method will be invoked.

In both cases, the delegate will receive an NSDictionary representing the notification as the last parameter passed in. Again, it appears that what can be in this dictionary is pretty limited as its max size is 256 bytes. You can put some custom stuff, like maybe some enum value to represent what kind of notification it is, or an ID to use as a request to get more information.

That is pretty much it! It is fairly straightforward, pretty close to how many people imagined this would work.

Monday, March 16, 2009

Karma's Bitch: The Denver Broncos

Twenty-five years ago, football fans were eagerly awaiting the NFL draft. There wasn't the ESPN/Mel Kiper hype that we have today, but none was needed that year. John Elway headed up the greatest quarterback class the NFL has ever seen. To say that Elway was highly regarded is an understatement. He had ideal size for an NFL quarterback with mythic arm strength. He was a fantastic overall athlete who also happened to be incredibly smart (earned a degree in economics while at Stanford.) The Baltimore Colts had the #1 pick in the draft and needed a quarterback. One problem: Elway refused to play for Baltimore. He threatened to play baseball instead if Baltimore drafted him. So Denver stepped in and traded for the rights to Elway. A year later, Mayflower trucks swooped in during the middle of the night moved the Colts from Baltimore to Indianapolis. Elway's selfish power play did not directly cause the Colts to move, the city of Baltimore had more to do with that, but nonetheless: Elway brought some bad, bad karma with him to Denver.

Elway's success in Denver is misunderstood today. People forget that there was a time when people talked about Elway's failures more than his successes. After 14 years in the league, he had plenty of individual accolades, but three horrible losses (and individual performances) in the Super Bowl. It was almost the perfect kind of karmic retribution. Sure you make the deal with the devil to get the great prize (Elway), but it can't bring you happiness (championship.) Then a karma curveball was thrown.

Mike Shananhan became the head coach of Denver. He had been mightily wronged by Raiders owner Al Davis, and now he was head coach in the same division as the Raiders. This virtually guaranteed success for Denver, and they went on to win back-to-back Super Bowls in Elway's last two seasons.

Denver continued to have success after Elway retired. However, after last season they abruptly Shanahan for no good reason. It was time for karma to finish off Denver for the sins it committed years before. Enter Josh McDaniel, hot shot new coach for Denver. Not satisfied with a young, Pro Bowl quarterback (Jay Cutler) that "the other guy" had drafted, McDaniel tries to trade that QB for a QB (Matt Cassel) that he coached last year as offensive coordinator for the New England Patriots. Here is where karma starts stepping in. The trade falls through, and instead the Patriots trade Cassel for way less than most thought he would command. Cutler finds out. First the Broncos deny everything. Then after meeting with Cutler over the phone and in person, they tell him to his face that they would be willing to trade. Now Cutler is demanding to be traded. It's almost too good to be true.

Sunday, March 15, 2009

Hiring Developers

I had a fun exchange on Twitter recently with @jamesiry and @codemonkeyism about how to hire developers. I think my thoughts on hiring are a lot different than most folks. So I thought it would be a good topic to expand upon.

First off, I must admit a lot of influence from Steve Yegge on this topic. For me, that was one of those times when you read something and you find yourself constantly thinking "yes exactly, I know what you mean." In other words, it was very consistent with my own experiences and opinions, but better articulated than I had ever been on the topic.

Otherwise my opinions on this matter are partially from my experiences plus a healthy dose of my flavor of logic. I am a big believer in being skeptical when people make statements based on their experiences. This is a common mistake, maybe the most common logical error that people make. Talking about and learning from your experiences is a good thing, but if you want to make a generalization, then you better have a lot of experiences to draw from. That is not even good enough, as your experiences need to be quite varied. Small sample sizes and skewed samples both lead to flawed conclusions.

Ok with all of that out of the way, I think the best approach to hiring developers is to take a very engineering-centric approach. There are things that a (software) engineer does that a scientist does not worry about. An engineer never assumes they will get the best solution on their first try. Instead they plan for mistakes. They plan for ways to measure these mistakes, so they can make adjustments and know if their adjustments are effective. Engineers also plan for failures.

So how does this translate to hiring? First off, you have to realize that a non-trivial fraction of the people you hire will be mistakes. You will get it wrong. In my experience, you get it wrong around 25-50% of the time. That's just my experience, so you should be skeptical about that number. However, it is not the exact number that matters. What matters is that if you think you will rarely get it wrong, that a bad hire is an exceptional event, then you will wind up with a lot of bad developers and it will cripple you.

This assumption can be hard to swallow. A lot of people will just say that this is wrong. However, once you get over this point, then everything else is downhill. If you know that you will make bad hires, then you will instrument your system (in this case your development organization) to check for these events and react to them. You quickly realize that it is key to make this assessment quickly. Do it in three months if you can, six months at worst. Assign a mentor to new hires, carefully pick their first project, whatever. Remember that a new hire is worthless for several months anyways, so the only important thing they can do during that time is prove they are a good hire, not a bad one. If you hire somebody because of an immediate need, you are running your organization poorly -- bring in a hired gun (contractor.) Anyways, it is also very important to make sure the new hire knows that this assessment is going on and that possible results include being laid off or a different position.

So all of this is the end goal, if you will. It is all after the hire. What interest most people is the before the hire process. Again with all of the above in mind, hiring is straightforward.

1.) Attract talent. This is hard. You have to get people to want to work for you. Maybe you hire recruiters. Maybe you use word of mouth. Hopefully you will try to create a good environment and culture for developers. As much as he annoys me, I would still recommend reading Joel Spolsky's ideas on this topic. I think Joel is totally wrong when it comes to the hiring process (actually on most things), but that he gets a lot right when it comes to creating a good environment for developers.
2.) Filter. This is easy. Resumes are the standard result of attracting talent. You can do dumb filtering, like insist on some type of degree, some number of years of experience, some knowledge of a particular technology. Or you can do something more subjective, like look for people who went to certain schools, worked for certain companies, or in certain environments like startups, consulting, enterprise software, whatever. Filtering can get more elaborate. Maybe you have a phone interview and ask some easy questions that you are sure any decent developer will know. Or you send them a similarly easy test of some sort. I am not saying that these are all good ways of filtering, just that they are options.
2a.) But what about traditional interviews? I am not a believer in the traditional, technical interview. It is a huge waste of time. Most people like to give candidates some tough programming or logic problem. Or maybe they go for the open ended design question or puzzle. Here is where I most concur with Stevey Y. All these typical interview techniques do is identify people who think like you. If you are really smart, then maybe this is good, but there is a good chance that you are not really smart. We all think we are smart, it is impossible to be objective about this. Microsoft and Google are both famous for their tough interview questions, but it is ridiculous to think that they are unique in the type of questions they ask of candidates. It is just the opposite. Every software company asks the same kind of questions and they still make a lot of bad hires.
3.) Personality Litmus Test. This is also easy. The one thing you can usually accurately ascertain from an interview is "will I be able to get along with this person?" and "will my team get along with this person?" If the answer is no, then do not hire them. You might think "but it is ok to hire a really smart person, even if they are hard to get along with" but then you are forgetting that you are not very good at determining if a person is smart or not. So just take that out of the equation. Remember the bad apple studies. If you think there is even a shot that somebody is a bad apple, cut the interview short and send them home. Note: I am assuming here that you are not a bad apple, hence that you would not get along with one of these types.

And that's it! If the candidate passes your filters and you think you can work with him/her, then make an offer. Remember that there is a good chance you are getting this wrong, and plan accordingly.

Monday, March 09, 2009

Covariance, Contravariants, Invariants, Help!

The other day, I made a really dumb Tweet about Java collections. I tried to come up with an excuse for it, but there really was none. This was, um, inspired by a proposal to simplify bounded wildcard syntax in Java. Perhaps my mistake is proof that such a simplification is needed, but probably not. To make amends for my mistake, and in the hope that others will be wiser than I, here is another way of looking at this issue.

Collections in Java are invariant, by default. That means that if you define a method to take a List of X, then you have to provide a List of X. List of Y, where Y is a subclass of X, will not work. Here is an example:



public static void invariance(List<Number> nums){
nums.add(1.1D);
for (Number n : nums){
System.out.println(n.doubleValue());
}
}

Invariance implies implies problems with the following code:

List<Integer> ints = Arrays.asList(1,2,3);
invariance(objs); // won't compile
List<Object> objs = new ArrayList<Object>(ints);
invariance(ints); // won't compile

You have go to match things exactly if you want to call an invariant method. Sometimes this is too restrictive, but not in this case. In the example above, you both read and write from the collection. If we could pass in the List of Integers, then adding a double to it would be invalid. If we could pass in a List of Objects, then calling the doubleValue method would be invalid. The only option here is invariance.
If you only need to read from the collection, then you can have covariance:

public static void covariance(List<? extends Number> nums){
for (Number n : nums){
System.out.println(n.doubleValue());
}
}

Now you can pass in anything that adheres to the API of Number, i.e. anything that is a subclass of Number.

List<Integer> ints = Arrays.asList(1,2,3);
covariance(ints); // compiles!
List<Object> objs = new ArrayList<Object>(ints);
covariance(objs); // won't compile

Not that you still cannot pass in the List of Objects. They don't have a doubleValue method, so it would be trouble if the compiler let them in. Now in the covariant method, if you tried to add a double to the list, the compile will not let you. You might protest and say "a Double is a subclass of Number, so I should be able to add it to a collection of objects that are a subclass of Number." This is shortsighted. You don't know exactly what kind of collection was passed in, just that everything in the collection should implement a particular interface. It could be a List of Integer or a List of Double or a List of Byte. So you cannot just add to the collection. For covariance, you want methods that do not mutate the state of the collection. Now technically, you could remove objects from the collection and the compiler will let you get away with it. Still it might helpful to think of covariance as read-only.

What if you want to add things to the collection? That is where contravariance comes in. Here is an example:

public static void contravariance(List<? super Number> nums){
nums.add(1.1D);
}

Here I say that want anything that is a superclass of Number. In other words, I am willing to say that I cannot be anymore specific about the elements in the collection than they are Numbers.

List<Object> objs = new ArrayList<Object>(ints);
contravariance(objs); // compiles!
List<Integer> ints = Arrays.asList(1,2,3);
contravariance(ints); // won't compile

Now I can send in a List of Objects, and since Object is a superclass of Number, the compiler is happy. If I send in a List of Integer, the compiler will stop me. I could try a List of Double too, and it will still stop me. My collection needs to very permissive, so that my contravariant method can add to it.

Neal Gafter's proposal to simplify some of this, looks like:

public static void covariance(List<out Number> nums){
for (Number n : nums){
System.out.println(n.doubleValue());
}
}

public static void contravariance(List<in Number> nums){
nums.add(1.1D);
}


I think this is intuitive. If I only want to take things out, I want covariance. If I want to put things in, I want contravariance. One of the things that made me re-think (and maybe confuse me) this subject was how things work in Scala. There you use + and - for covariance and contravariance, respectively. By default, a List in Scala is covariant. However, Lists are immutable. Adding to a Scala List produces a new List, it does not mutate the original List. The mutable cousin of List, like ArrayBuffer, is invariant, just like a List in Java.

Sunday, March 08, 2009

Day of Infamy

Last week I wrote about a day of infamy, but did not get around to talking about this. I was too happy about President Obama following through on his pledge to get our military forces out of Iraq. On that same day, the government did something that was not so good. The Fed essentially took control of Citibank.

But wait, we've heard Secretary Geithner and Chairman Bernake both say that they oppose nationalization of our banks, and assure us that what we are doing at Citibank is not nationalization. This is a classic case of mincing words. The Fed has not only assumed a commanding position of ownership, but they have already begun dictating the company's policies. They have remade the board of directors and mandated policies on employee compensation and lending standards. This is de facto control. It's like in The Sopranos when Uncle Junior was the nominal leader of the Jersey mafia, but everybody knew that Tony was calling the shots. This is what has happened with the US and Citibank. The US is Tony and Citibank is the Jersey mafia. The actual executives might as well be old, senile, and in jail.

Now the government has taken control of banks before, most notably in the S&L runs back in the 80's. This was always done to liquidate the assets of the bank. Maybe that is what is going on with Citibank, and the government is misleading the public because ... well who knows.

I do not think so. The government wants banks to loan money. They want businesses to borrow and hire workers. They want consumers to borrow and spend. This is not happening, for many very good reasons. If you are a bank, you need to clean up your balance sheet by increasing your cash and reducing your risky investments. If you are a consumer, you need to increase your savings and reduce your debt. But if the government has control over large banks, they can make the bank forget about increasing cash and reducing risk. They can offer up loan to any and everybody. They can make it really hard on consumers to resist the temptation of free money. Imagine getting a letter in the mail everyday saying that you have been pre-approved for a new credit card with a 0% interest rate and a $100,000 limit! It's the modern day version of the chicken in every pot.

And so it is that I think February 27 will be a day of infamy in American history. It may be the beginning of an era where the government is an essential part of all economic activity in America. Want to buy a house? Ask the government. Want to buy a car? Ask the government. Want to send your kids to college? Oh wait, nevermind on that one. Want to plan for retirement? Umm ...