⇥ Optimizing image display using a bin-packing algorithm – Part deux

September 30, 2010
No comments
 
⇥ Permalink

In the first blog post in this series, I introduced the concept of bin packing and showed how it can be used to optimize the arrangement of an arbitrary group of images so that they occupy the list amount of space possible.

The result, however, is—well, ugly, as those who had the guts to give my code a try will have found out. So, good concept, ugly output.

In this second post, I’m going to show you how to improve the quality of the image display and, in the process, we’re going to stretch the concept of bin packing a little in order to show that, despite its name, it’s not necessarily always about fitting boxes inside a bin.

Images are not boxes

There is a hidden assumption in the very basis of the bin-packing problem that I have not, so far discussed: the fact that all the objects that are to be packed are inflexible1.

This is perfectly normal if you’re trying to pack a container full of chairs; images, on the other hand, are not physical objects, and can, therefore, be stretched without any major damage, so long as we (a) don’t resample them to a bigger size than the original and (b) we do not change their aspect ratio

By taking advantage of this feature, we could now decide to, say, shrink an image when we cannot find a fit, thus giving our algorithm a better chance at filling the screen. Using such a naïve approach, however, will simply result in an even more grotesque display than the one that came out of the first attempt. This is because our bin-packing algorithm starts from the largest image, which is likely to occupy a large portion of the available real estate; by the time we get to an image that doesn’t fit without resizing, we’ll have to shrink an already small image, which won’t work well.

Stretching in one dimension

What we could do, instead, is to fix the maximum size of an image in such a way as to give them a uniform appearance. This can be easily accomplished by just deciding on a maximum height and then arranging all the images in a row, allowing our page to grow and stretch vertically as the rows get filled optimally.

This, incidentally, opens up a way to simplify our code. Since the height is now fixed, all we really need to do is pack the images horizontally, based exclusively on their width. Thus, we are still solving the bin-packing problem, except that, instead of dealing with two-dimensional objects, we now only have to worry about a single dimension—we are, for all intents and purposes, packing a line segment.

Dealing with a single dimension means that we need to track fewer pieces of data. In fact, as long as the images are packed along the line, we don’t really care about their position either—we’ll just add them to the horizontal row until it’s full, and then move on to a new row.

All in all, what used to be a complex bi-dimensional object whose position and area we were tracking has been reduced to a single, mono-dimensional line segment that is always anchored to a fixed point. This reduces our algorithm to simply tracking the width of each bin; effectively, every time we decide to place an image on a given row, we will just remove a segment from the corresponding bin equal to the image’s width.

It’s important to keep in mind that, despite the significant simplification to the process, we are still packing bins, which should result in a final arrangement of the images that is as close to optimal as possible (as opposed to, say, just shoving the images one next to the other)2. We have just created some additional constraints that have simplified our algorithm considerably.

Great power, and great separation

With this approach comes an additional consequence that is going to come in very handy in Part 3. The structure that we now use to track the space occupied by each image no longer has any real physical connection with the real estate it represents on the screen. We are tracking a row number and the width that hasn’t been used, but, on the screen, we will be drawing bi-dimensional objects that will, in addition to being placed inside some sort of container, have to be arranged so that they are equidistant and properly aligned.

In other words, we have separated the logical representation of a bin from its physical appearance. This means that, given the appropriate set of circumstances, we can now discard the physical representation of a row and reconstruct it without any loss of information from the logical data that we have saved. We are not quite there yet, because we are not quite tracking which images we are placing in a particular bin.

In Part 3, we will extend this concept (which separates the model from the view and is at the basis of a model-view-controller architecture) in such a way that we will be able to infinitely extend our real estate vertically while only ever loading as many images as necessary to fill our screen, thereby saving considerable amounts of memory and providing a fast and precise scrolling experience.

May the best fit win

We still haven’t solved the problem of dealing with more than eight images, which is the most we can extract from Google at any given time3. This is a bigger problem than it seems—a best-fit bin-packing algorithm only works when you can determine the tracking data (that is, the value that determines the best fit) ahead of time. This works while we’re dealing with eight images—but what if we wanted to load another eight?

There are two possible solutions here. The first is to perform a complete layout every time an image is added or removed from the list. This always gives us a best-fit optimization, but it has two significant drawbacks: it’s computationally intensive (especially once we have a lot of images to deal with) and it is likely to move existing images around to pack more efficiently, thus confusing the user, who will see things move without their input.

The second solution is to pack each group of images that are downloaded independently of the others, adding a new group to the previous one. This approach has the advantage of being computationally efficient and of avoiding to move images without the user’s intervention, but also the drawback of being only locally efficient—the end result will be a layout that will be less optimized than if we had had all the images from the very beginning. Alas, beggars can’t be choosers, but that’s a problem that we’ll deal with in Part 3.

The code, part deux

Finally, before moving on to the code, we still need to lay the images out properly, so that they will be spaced evenly across each row and so that they will be centered vertically. In Flex, we can do this by using an HBox, which automatically positions its children horizontally. To guarantee even spacing, we can use a Spacer between the images whose width we set to 100 percent; this will cause the Spacers to take up as much horizontal room as possible, thus spacing out the images evenly (we also add a Spacer at the beginning and end of each row to create a bit of margin).

protected var binContainer:Array = [];

protected function getBinContainerAtIndex(index:int):HBox {
while (index >= binContainer.length) {
var hbox:HBox = new HBox();

hbox.percentWidth = 100;
hbox.height = 150;
addChild(hbox);

hbox.addChild(safeSpacer());

binContainer.push(hbox);
}

return binContainer[index];
}

view raw gistfile1.as This Gist brought to you by GitHub.

As you can see above, we keep an array of row containers (which we don’t currently use, but will in Part 3), which are just properly-size and styled HBoxes. The getBinContainerAtIndex() method grows this array as needed—thus giving us the beginning of our bottomless page display.

Finally, our fitImagesInClientArea() method also has to change to reflect our new packing strategy:

protected function fitImagesInClientArea():void {

// Create the main bin

var bins:Array = [new Bin(width, 0)];

// Sort the images

boxes.sort(function(a:Box, b:Box):int {
if (a.width > b.width) {
return -1;
}

if (b.width > a.width) {
return 1;
}

return 0;
});

// Iterate through each image, finding the best possible
// bin for it based on its area.

for each (var box:Box in boxes) {
var bestFit:Bin = null;

for each (var bin:Bin in bins) {
if (bin.width >= box.width) {
// The box fits in the width of the bin. But is
// it a better fit?

if (!bestFit || (bestFit.width - box.width > bin.width - box.width)) {
bestFit = bin;
}
}
}

if (bestFit) {

// Position the box in the bin and add it to the screen

var hbox:HBox = getBinContainerAtIndex(bestFit.rowNumber);

hbox.addChild(box);
hbox.addChild(safeSpacer());

// Reclaim any unused space
bestFit.width -= box.width;
} else {
trace("Unable to fit box with width: " + box.width + " and height: " + box.height);
}
}

}

view raw gistfile1.as This Gist brought to you by GitHub.

Here, we have changed the Bin implementation to only track the row number and a width4, and the packing algorithm has become similarly simpler—in fact, the bin-splicing operation now only consists of removing the width of the new image from the overall width of the bin.

The results, compared to the Part 1 attempts, are dramatically better. You can try it for yourself, and take a look at the current code in the mono-packing tag of the GitHub repo for the project.

  1. In reality, we’re also assuming that they’re rectangles—but that’s fine for our purposes.
  2. This mono-dimensional approach, incidentally, is one way of defragmenting a hard drive: one first collects all the fragmented files so that they are contiguous, sorts them in descending order by some arbitrary value—for example, how often they are used—and then bin-packs them by another arbitrary best-fit value, such as how quickly the hard drive can read them into memory, thus optimizing the apparent speed of the filesystem.
  3. In my project, I get images from a different source—I switched to Google here just so that I could build a public demo. Therefore, it’s entirely possible that I am misreading the docs for Google’s API and it is possible to get more than eight results at a time. If that’s the case, I’d appreciate a comment from someone who knows better!
  4. If you remember, in Part 1 I mentioned that we would be using the Flex built-in Rectangle class, but, as it turns out, that’s unnecessary.

⇥ Optimized image display using a bin-packing algorithm – Part one

September 29, 2010
One comment
 
⇥ Permalink

I am currently working on a project that requires (among other things) the ability to display a series of images, whose size is unknown at design time, in such a way that as many of them are visible on the screen at any given time.

This is an interesting problem for a number of reasons: first, the solution can be applied to a number of different problems that have nothing to do with images; second, a little tweaking makes this problem a great gateway to building a cool image-display system; and third, it is a very simple—but very impressive—example of how math doesn’t have to be hard to be useful.

I’ve broken this post in three parts: in the first one, I will mostly focus on the problem and its solution; in the second, I will worry about making adjustments to guarantee the best possible solution; and in the third, I will make things look good.

The problem: packing bins

At its most basic, the problem is very simple: we receive a bunch of images in input, and we must arrange them in such a way that as many pictures fit in a given space as possible. In other words, we have a bunch of rectangles that need to be placed inside another rectangle in an optimal way.

This is not unlike the problem that one faces when packing a bag—the solution, in that case, is to start with the big, bulky items and then fit the smaller objects in the nooks and crannies until no more objects can be placed and you reach for a new piece of luggage over the loud complaints of your spouse. We have to do the same thing—only in two dimensions instead of three.

As it turns out, this is a very well research problem that is usually referred to as the “bin packing problem.” It applies to a large number of very practical scenarios that vary from the obvious (packing a container full of IKEA furniture so that as little unused space as possible is left on a ship or truck) from the esoteric, like defragmenting a hard disk.

Despite its simple premise, the optimal solution to this problem is impossible to find without essentially going through all the possible permutations and checking the individual efficiency of each one1. Therefore, we need to find an algorithm that is both efficient and practical.

Solutions

There are a number of solutions to the bin packing problem. The most obvious is to simply take each item as it comes along and shove it in the first available location that’s big enough to contain it. This approach (which is how I pack my bags) is called “first-fit” and it is, as you would expect, quite inefficient—in fact, Wolfram MathWorld says that first-fit algorithms can be as much as 70 percent less efficient than an optimal solution.

But let’s go back to the problem of packing a bag or a trunk: you start by putting all the objects in front of you, mentally separating the big ones from the small ones. Next, you pick the largest object and place it in bag in the best possible position (say, the top-left corner), continuing in this fashion until you either have no more objects to fit or no more space to fit them into.

Interestingly, this intuitive—or heuristic—solution (called best-fit) is very efficient: math proofs have demonstrated that it varies, at most, by 22 percent from an optimal arrangement, which other math proofs has shown is the maximum theoretical efficiency that can be guaranteed by a heuristic solution is… 22 percent2!

The problem of “best”

A big issue at play here is what “best” means in the context of a best-fit algorithm. The answer to this question is actually quite complex—given the simplicity of the algorithm itself, I’d say it’s probably the most difficult part of the puzzle we’re trying to solve.

The obvious answer is that a particular space is the “best fit” for a given object if, and only if:

  • Its area is at least the same, or bigger than the object
  • Its width and height are at least the same, or bigger than those of the object
  • The difference between its area and the area of the object is less than or equal than the difference between the object and any other available space in the bin
It’s interesting to note that the first two conditions are necessary in order for the fit to occur at all—if the object is bigger, longer or wider than the space we’re considering, it simply will not fit. Therefore, with only those two first conditions we have a first-fit algorithm.

It’s the third conditions that fulfills the best-fit requirement by imposing a requirement that is not necessary for a fit to occur. Luckily, the area is a good measure of efficiency if the relationship between the height and width of the bin is relatively close to one; in other cases, you will have to use different way of measuring the “best fit.” For example, if you are fitting into a bin that has one infinite dimension (say, the height of a page that can scroll indefinitely), then it’s much better to measure the efficiency of a fit based on the relationship between the width of an object and the width of the bin3.

The algorithm in practice

Now that we have the theory well sorted out, we can write out an initial algorithm:
  1. Sort out all the available images in descending order of area
  2. Let bins be an array of bins containing a bin whose width and height are the same as the client area to fill
  3. For each image:
    1. Let bestBin be null
    2. For each bin in bins:
      1. If the bin is the best fit for the image, let bestBin equal the current bin
    3. If bestBin is not null
      1. Position the image in the top-left corner of bestBin
      2. Create two new bins from the unused portions of bestBin and add them to bins
      3. Remove bestBin from bins
As you can see, this is very simple. The only concept we haven’t quite defined is how we “create” the two new bins out of the unused portion of the best-fit bin we use for any given image. Once again, the correct approach here depends on a number of variables strongly tied to the concept of “best fit.” For reasons that will become apparent in Part 3, here I choose to create two bins as illustrated in this picture:

Reclaiming unused space from a binAs you can see, for the purposes of our algorithm there is no difference between a “bin” and a “space inside a bin.” Any amount of available space is considered a bin and added to the bin array for reuse.

The algorithm in code

Implementing the algorithm is actually quite simple. In the sample project that I created to test the algorithm (written in Flex4), I start by pulling eight images from Google by searching for a user-provided query. These go into a class called Box, which, essentially, is just a container for an image that is also capable of calculating its own area.

The images are loaded into an object of the class Boxer (I know, I’m great at naming things), where they are then run through our packing algorithm:

protected function fitImagesInClientArea():void {

// Create the main bin

var bins:Array = [new Bin(0, 0, width, height)];

// Sort the images

boxes.sort(function(a:Box, b:Box):int {
if (a.area > b.area) {
return -1;
}

if (b.area > a.area) {
return 1;
}

return 0;
});

// Iterate through each image, finding the best possible
// bin for it based on its area.

for each (var box:Box in boxes) {
var bestFit:Bin = null;

for each (var bin:Bin in bins) {
if (bin.width > box.width && bin.height > box.height) {
// The box fits in the area of the bin. But is
// it a better fit?

if (!bestFit || (bestFit.area - box.area > bin.area - box.area)) {
bestFit = bin;
}
}
}

if (bestFit) {

// Position the box in the bin and add it to the screen

addChild(box);

box.left = bestFit.x;
box.top = bestFit.y;

// Split the bin to reclaim any unused space

bins.push(new Bin(bestFit.x + box.width, bestFit.y, bestFit.width - box.width, box.height));
bins.push(new Bin(bestFit.x, bestFit.y + box.height, bestFit.width, bestFit.height - box.height));

bins.splice(bins.indexOf(bestFit), 1);
} else {
trace("Unable to fit box with width: " + box.width + " and height: " + box.height);
}
}

}

view raw gistfile1.as This Gist brought to you by GitHub.

Note that the Bin class is little more than a rectangle (in fact, later on we will replace it with the built-in flash.geom.Rectangle). You can download the entire (working) project from GitHub (tag raw-fit for this version) and try it out yourself—or you can also give it a try online.

Problems that need solving

As you can see if you give it a try, this algorithm works—but the results look depressingly ugly. In particular, there are a number of issues to take care:

  • The images are all squished together, so that the unused space is not evenly distributed.
  • If an image can’t fit, it’s simply discarded. In practice, this is unacceptable.
  • The images are not presented in a visually enticing way
  • The code cannot deal with more than eight images (which is the maximum that Google will return at one time)
  • The code cannot deal with images as they are being loaded (in other words, it needs to know the dimensions of every image in order to apply the algorithm to them)
These, and several other improvements, will be the subject of Part 2 and Part 3. (You can subscribe to my feed to find out when they’re coming out).

  1. Interestingly, the efficiency of a given solution is easy to verify, which makes us stumble on one of the great unsolved problems of modern computational theory. efficient algorithms that come in handy when dealing with large, complex systems where even small improvements in efficiency can yield large gains. For our purposes, 22 percent wastage when fitting a few dozen images in a rectangle is acceptable—if you’re IKEA and you need to ship 100,000 boxes, an improvement of as little as 0.1 percent can result in significant shipping cost reductions.
  2. This may seem counterintuitive, but it actually makes a lot of sense once you consider that, if you can stretch indefinitely in one direction, the other becomes your constraint—the one you want to fill up as best as possible.
  3. The project I’m working on is in Flex, so that’s the language I’m using here. However, this code can be trivially ported into JavaScript, and the algorithm is so simple that it should be easy to implement in just about any other language.

⇥ Of paper and electrons

September 17, 2010
No comments
 
⇥ Permalink

On Twitter, Clay Loveless, who seems to be having a particularly bad day (or maybe he just plain doesn’t like me), has taken issue with the way we price our books. This seems like a good opportunity to explain how we do it, and why.

What is that you’re buying, anyway?

It seems to me that the first that needs to be clarified is what exactly it is that we’re talking about.

When you “buy” a book, my assumption has always been that you are interested in the contents of the book, rather than the form it comes in. Therefore, “buying a book” really means “licensing the content.” If the content comes on paper, then the paper is simply the medium on which the content is transferred.

When I price a book, therefore, I start by deciding how much we need to charge for the content. That is the money that I want to make from my license of the content to you.

The cost of knowledge

From that point on, the format in which customers buy the book is completely irrelevant to me. Therefore, I only charge them what it costs to produce the medium: free for an electronic download, and what the printer charges me (plus shipping) for a book.

It’s that simple. In fact, if a customer buys the print version of a book, I’m happy for them to download the electronic version as well, at no extra charge.

The sum of all things

Clay notes, correctly, that several other publishers have e-book prices that are far lower than their print counterparts, often as much as $10. To me, that seems absurd—printing a book doesn’t cost $10. By the same token, making customers pay extra if they want both an e-book and a print copy just seems wrong to me.

Now, you can say that our books are expensive. Perhaps they are. But at least I feel pretty good about the way we determine our pricing.

⇥ LLCs are a good idea, but you can still get sued

September 15, 2010
One comment
 
⇥ Permalink

On his blog, Joe Stump says that opening your own limited liability company (LLC) is a great way to protect yourself and your assets from unwanted legal attention when you segregate your side projects into it.

He is, of course, absolutely right. An LLC creates a separate legal person for third parties to enter into agreement with without all the complexities of owning and running a corporation. If one of those third parties decides to sue, they’ll have to initiate legal action against the LLC, protecting you and your assets.

If you do decide to open an LLC, however, there are a few things that you need to be aware of.

Note: I am not a lawyer, so take these notes as very high-level and not necessarily accurate. If you are a lawyer and spot inaccuracies, please comment so that I can take care of them.

1. The LLC is a separate person

If someone decides to sue your LLC, they will at least try to get to you personally. After all, the legal fiction of corporate personhood exists specifically to create a cushion between you and the LLC’s liabilities. The process of “getting to you” is called “piercing the corporate veil”—that is, getting a court to look beyond the fiction of corporate personhood to get to the person behind the curtain.

Piercing the corporate veil is a very difficult thing to do (as it should be), provided that you treat the LLC as a separate person.

In practice, this means that you must conduct the affairs of the LLC separately from yours, establishing that, when you are acting on behalf of the LLC, you do so in the LLC’s best interest as it is your fiduciary duty. This means taking care of a few formalities, like keeping your business license current, opening separate bank accounts and, especially, avoiding commingling your personal funds with the company’s. It also means that you cannot use the company as a shield to commit fraud, and so on, and so forth.

So, no treating the LLC as your personal piggy bank. Make sure you record all financial transactions, and always act in the best interest of the LLC, and not your own.

2. Get a lawyer

Lawyers are expensive. There is no way around that. However, unless you are a lawyer, it’s best if you leave the formation of your LLC to one, instead of using one of these rubber-stamp services that are available over the Internet.

There are a couple of reasons for this. First, unlike a service, the lawyer will be able to offer you some advice on whether an LLC is the right thing for you, as well as give you some basic guidance on how to ensure that you run the LLC properly. Second, should you ever get in front of a judge, it looks good if you show that you make it a practice to refer legal works to those who are expert in the field, rather than taking matters into your own hands, not to mention that, if the lawyer screws up, you can go after his or her insurance.

Oh, a final piece of advice: I often hear people complain about lawyers as if they were the scum of the Universe—they’re ignorant, lazy, stupid, greedy, evil… take your pick. That is, in my experience, the best way to ensure that the relationship with your lawyer will be unproductive and expensive.

Lawyers are experts in the law—a field that is often illogical and difficult to understand for the lay person. Which, incidentally, is exactly what non-techies say of programming. So, find a lawyer you can work with and make sure that your relationship is based on mutual respect.

3. Get an accountant

The LLC is a separate person, which means that it needs to file its own tax return. Even if you think you can file it yourself, it’s always best to get an accountant—once again, the reason is simple: what best way to act in the interest of the LLC than getting a third party to validate all the financial data?

That’s not to say that you need an audit, but it’s always good to get a CPA to double-check your calculations. And, once more, there’s another insurance that you can collect from if they screw up.

4. You can still get sued

The worst thing that anyone can tell you is that starting an LLC means that people can’t sue you. That’s no more true than saying that crossing over the zebras will prevent a car from running you over.

Nothing prevents any person from suing your LLC or you personally and, since the legal system works on default, you will have to spend the money to defend that lawsuit, no matter how frivolous.

What the LLC does is to provide you with protection from the results of a legal action. A determined party with deep pockets will still be able to take you to court in an attempt to pierce the corporate veil, make you spend considerable amounts of money and, generally speaking, eating a ridiculous amount of your time for a number of years. Having an LLC in place, provided you’ve behaved properly, will eventually protect you from the consequence of an action, but the process that gets you there will still be long, stressful and extremely expensive. That’s where having a good relationship with your lawyer will come in handy.

⇥ Apple has made pigs fly

September 9, 2010
One comment
 
⇥ Permalink

What started as a rather ordinary day has turned into a rather extraordinary one, at least for those of us who dip their feet in the world of Apple. The company’s announcement that it is relaxing a number of its App Store policies while publishing the very rules that it uses to decide whether an app can cut muster represents a massive shift in the way the Fruit folk interact with their developer ecosystem.

John Gruber and Jason Snell have already written excellent analyses on what the changes mean from many different perspectives, but I think there are a few more things that can be said.

The tone

Leaving the content of today’s material aside, its most interesting aspect was the tone with which it was presented. Much of the documentation is under NDApress release that announces them sounds like the corporatespeak people were kept right out of the loop. One cannot wonder whether, in a company like Apple, this minor miracle of human communication could only be pulled out by one man.

Flash

One of the big changes is, of course, in the way Apple deals with apps that are built using unofficial tools, which include Adobe’s Flash. Leaving Adobe aside for a moment, this is a massive concession on Apple’s behalf—both as a concession to companies that are building tools that speed up app development and (especially) as a boon to developers. The message is fairly clear: we don’t care how you build your apps, as long as they are great and compelling.

As far as Flash is concerned, celebration is premature until Adobe makes it move: remember that the company announced, back when the iPad was released, that it would simply let Apple do its thing and stop further support for iOS in future versions of AIR. Therefore, we must now hope that they will change their mind and decide to support Apple’s platform again. This is by no means a done deal, as resources in a company like Adobe don’t just get reassigned on a whim and, by now, the folks who were working on iOS support may well have moved on by now.

Rules

Several reasons have been advanced as to why Apple has decided to publish the rules it uses for App Store approval and instituted a review board to give rejections a second look: it’s afraid of frustrated developers moving to Android; it worries about regulation; it wants to be good towards its developers; it wants to get rid of the criticism that has surrounded rejections.

These are all valid points, to which I add one: it wants to increase investment in iOS apps. One of the long-running concerns that investors have had with the App Store is that the opaque approval process makes putting money into iOS-centric development riskier than it needs to be.

Until now, I don’t think this has been a major issue for Apple, as the iPhone and iPod touch are platforms that favour relatively simple and straightforward apps. However, the iPad commands a higher degree of complexity and sophistication, and I cannot help but think that there is more to an iOS-running Apple TV than Cupertino is letting on.

People who have only ever been exposed to development under the iOS program don’t seem to realize just how revolutionary Apple’s approach to third-party development on iOS is compared to the jungle of fees and bureaucracy that used to surround development under the iron-rule of the individual carriers.

If the same model were to be ported to the world of console gaming, Apple would make an absolute killing. Consider an Apple TV that, say, costs $200 and features the full iOS experience, including the ability to download and install games developed specifically for your TV set using the same approach that applies to the iPhone and iPad. On the surface, such a system would rival the customer-facing price of consoles like the Playstation 3 or XBOX 360.

From the point of view of a developer, however, the difference would be chasmic. Developing for any of the major consoles today is both expensive and complicated: most of the “majors” require investments in the tens of thousands to acquire “development versions” of their consoles and won’t even consider allowing a developer into their programs unless it has significant resources and a long history behind them. Once on the inside, the developer is at the end of a long chain of actors, each of which take a big bite out of the retail price: once the retailer, the distributor and the publisher have gone through it, the developers are left with a very very small slice of the overall pie.

Contrast them with a program that requires an investment of $100 for your entire team, has essentially no entry roadblocks whatsoever, and leaves 70 percent of the revenue in the hands of the developer, and it’s clear that Apple could destroy the business model that has worked so well for Sony, Microsoft and Nintendo in zero time flat.

To do this, however, Apple needs a clear program that can attract deep-pocketed players—hence today’s moves.

It’s interesting to note that the rules change nothing for Apple, because the rules are a “living document” that Apple can change at any time. In a sense, this is inevitable, because Apple cannot possibly anticipate all the possible circumstances surrounding an app’s submission—but the wording also gives the company an out should it decide to change one or more of its policies.

The review board

The announcement that Apple is instituting a review board to which developers can appeal rejection has struck me as really odd for three reasons.

First, I’m not sure that there is an actual need for a review board. The vast majority of apps are approved, and the review team has become much smarter at listening to developers who complain they have run afoul of arbitrary rules. Second, I doubt that Apple would set up a Review Board if it really needed one—if the number of rejections were really so high, being on the board would be a full-time job and either (a) rapidly become ineffective or (b) take up an inconsiderate amount of time out of the schedules of the high-level executives involved.

My guess is that the review board’s main function is to act as a honeypot for those developers who, upon having their app rejected, opt to go plead their case with the press, which is something that must really rile a lot of people at Apple, given that the company rarely, if ever, comments on such rejections2. With the Review Board in place, Apple now has one more chance to catch these problems before they become… problems.

And finally, the markets

By far the scariest part of the announcement is the effect that it has had on Adobe’s stock, which is up 12 percent today on news that only tangentially related to that company’s business.

This is bad both for Adobe and for Apple: the former’s fortunes have now somehow become entangled with a story that is relatively irrelevant to the long-term success of its chief product, and the latter’s every move is having a far too significant effect on the market, which is going to come back biting once Apple has the inevitable bad news to share.

  1. I do not intend on breaking the NDA, but there are plenty of places where you can find the documents.
  2. Remember, a lot of this stuff is under an NDA that a lot of people, but not Apple, has broken. Therefore, the company must feel that coverage on these rejections is quite one-sided.