It’s been interesting to observe the visceral reactions people have had to the overhauled Maps app in iOS 6. Everyone, from tech pundits to average users, seems to have an opinion on how awful the new app is. It’s even spawned a mocking Tumblr.

Yes, for a company that touts product perfection as one of its core tenets, the new Maps app is about as imperfect as they come and a rare misstep for the world’s most valuable company.

So I suppose I shouldn’t be that surprised to see articles predicting the end of Apple as we know it. But most articles or posts of this type seem to be of the link bait, lazy journalism variety. So let’s take a look at some of the more prominent doom-and-gloom assertions regarding Apple’s future and take stock of reality.

  1. Steve Jobs would never have let this happen.

    This is the type of argument I have seen the most over the last couple of days. And, while it may be true that Jobs may have stopped the app from shipping, without the man making the call himself, we’ll simply never know whether that’s the case or not. However, the substance of the argument is essentially positing that Steve Jobs would never have shipped an imperfect product - people making this argument seem to have a rather limited memory span.

    In fact, I can think of two very high-profile duds that Apple shipped under Jobs’s direction - MobileMe and the original iPhone 4 with its flawed antenna. In both cases, Apple was able learn and iterate upon each product in a way that ultimately paid off for them. Apple ended up fixing the issues with the iPhone 4 antenna, offered a free case to early adopters, and sold tens of millions of units of the phone. MobileMe ultimately became iCloud and now has over 150 million paying subscribers.

    Even Jobs wasn’t immune from shipping duds. But he was ultimately able to learn from those mistakes and direct Apple to develop better products. The barometer for Apple’s continued success isn’t in whether they release a flawed product every now and then, but rather how they react to and iterate upon those releases.

  2. Apple’s management is reckless and/or incompetent for releasing such an unpolished product.

    As I noted, even under Jobs, Apple was no stranger to botched product launches. But whereas those launches may have been the result of some unknown internal dynamic, there may be a simpler business decision at play here.

    As has been widely reported, Apple’s contract with Google for Google services on iOS expires this year. Now, it’s not known what the inside story is, but I suspect that Apple was simply content to let their contract with Google expire in order to push their own version of Maps to better control the end-to-end experience with consumers. John Gruber posits two additional theories:

    It’s possible Apple tried to renew for another year or two and Google either refused (unlikely, I’d say) or offered to do so under terms Apple found unacceptable (possible, I’d say).

    In the first case, it would seem clear that the expiration of their contract with Google presented a good opportunity for Apple to jump ship from the entire Google platform, even if it meant some growing pains for themselves and their users. In the case of either of Gruber’s theories, it’s possible that Google simply gave Apple no choice and they had to push out what they knew was an incomplete product. Whatever the case, it’s probably safe to assume that Apple wanted to stop supplying their primary competitor with absurd amounts of money for its services.

  3. Apple can’t compete with Google in this space.

    Well, not at the moment. Google is the 800 pound gorilla in the mapping space - creating a product anywhere near as effective or polished as theirs wasn’t going to happen overnight.

    See, building a mapping application is hard. Like, really hard. It requires an enormous amount of human and technical capital, a lot of expertise in geospatial analysis, and a ridiculously large dataset to get anywhere close to where Google’s risen in this space. In retrospect, it’s not really surprising that Apple fell short when we compare their app to the Google Maps of old.

    Apple is increasingly dabbling in areas that require strong dataset management and utilization skills - skills that weren’t necessarily required for most of the products in their portfolio previously. But as Apple bets more of its future on cloud computing, these skillsets are going to become more important and Apple is going to have to rapidly develop strong data gathering, data management, and machine learning capabilities in order to make services like Siri and their new Maps app successful.

    But that’s not to say that Apple’s not capable of competing on Google’s level. In fact, if there’s any company out there that can give Google a run for its money in this space, despite it not being one of their core competencies, I’d say it’s Apple. But it will take time to get to that level and that will be frustrating for a lot of iOS users. And if Google is indeed readying a new, standalone maps app for iOS (and I don’t see any reason why they wouldn’t be), the onus is going to be on Apple to get to that level of sophistication sooner rather than later.

Apple hasn’t peaked, isn’t doomed, and isn’t going anywhere. The hubbub surrounding the Maps launch is certainly well-deserved and something I’m sure Apple will make strides to correct, but the doomsday predictions are nothing more than hyperbole and sensationalist journalism. Like their missteps of yesteryear, Apple will recover from and adapt to this to produce even higher quality products.

So I started a new job on Monday and have been interested in getting up and running with optical character recognition (OCR) libraries as a little side-project related to my new duties. Tesseract seems to be the de facto “go-to” software for OCR and I wanted to get up and running with it and some Python bindings. As I found out, this is actually easier said than done and requires a very minor hack that I haven’t found documented anywhere on the web.

Before we begin, note that I installed Tesseract and its dependencies with Homebrew. These instructions may work for MacPorts installs, but I haven’t tested that - your mileage may vary.

Installing Tesseract (and its dependencies) was as simple as cracking open terminal and running brew install tesseract. You’ll also want to make sure you have Swig installed - if you don’t, run brew install swig. Next I had to get a python-tesseract tarball to build. I’m a big fan of virtualenv and I use it for basically every little thing I do with Python - I set up a new one with virtualenv tesseract_test. I ran source bin/activate in my new virtualenv and then untarred the python-tesseract archive. Then I ran, as suggested by the build docs, python setup.py clean followed by python setup.py build and was greeted with this piece of wonderful news:

include path=/opt/local/include
Current Version : 0.7
running build
running build_py
file tesseract.py (for module tesseract) not found
file tesseract.py (for module tesseract) not found
running build_ext
building '_tesseract' extension
swigging tesseract.i to tesseract_wrap.cpp
swig -python -c++ -I/opt/local/include/tesseract -I/opt/local/include -I/opt/local/include/leptonica -o tesseract_wrap.cpp tesseract.i
tesseract.i:11: Error: Unable to find 'publictypes.h'
tesseract.i:12: Error: Unable to find 'thresholder.h'
tesseract.i:13: Error: Unable to find 'baseapi.h'
error: command 'swig' failed with exit status 1

I’m not the only person who has run into this problem (which was the primary factor that motivated me to pen this). The build is failing because Swig can’t find the right files - not because they don’t exist, but because the setup script is looking in the wrong place. The fix for this is extremely simple - open setup.py in your favorite editor and, on line 10, change

prefix="/opt/local"

to

prefix="/usr/local"

Save and exit. Homebrew, by default, symlinks software it installs into /usr/local - the setup script was looking for them in /opt/local instead. Changing this will correct that issue. Try running python setup.py build again. It should complete successfully this time and you can then run python setup.py install - you now have a working Python binding for Tesseract installed!

I hope this helps someone avoid the headscratching I endured for a little while trying to figure this out.

I’m frustrated this morning.

Over at TechCrunch, Peter Ha has penned a post nitpicking Google’s Project Glass - a product best described as a prototype. For anyone who hasn’t read the post, let me get you up to speed.

Sebastian Thrun, the founder of Google’s skunkworks X laboratory was on Charlie Rose last night to discuss, among other things, Project Glass. It’s actually a pretty great interview in and of itself - Thrun and Rose discuss Glass and Google’s autonomous cars (also a Google X project), Thrun ducks some broader questions about Google X, and they talk about Udacity (Thrun’s online university experiment).

But, I suspect for most geeks like me, the most exciting part of the interview is when Thrun actually demos the Project Glass glasses he’s wearing and takes a picture of Rose with them. They actually work! This isn’t just a public display of a funky-looking headpiece or a dead-end, Microsoft-esque vision of the future video. Thrun proved last night that these things are the real deal - and that excites me a lot.

Ha, meanwhile, seems only to want to poke holes in this very public, very brief demo. He compares the quality of (remember, still a prototype) Glass’s camera to that of the iPhone 4S (a well-polished Apple device with a best-in-class camera system). He bemoans the fact that the debut video showed the user controlling Project Glass with their voice and that, in his demo, Thrun had to press a button and use gestures to take the photo and upload it to Google+.

Is he for real? No one is doing anything like this. I find his entire piece to be an exercise in absurdity. If the Glass unit Thrun was showing off had been a final version that was ready for review it would be one thing (and I’d even agree with Ha), but it’s merely a prototype. There is clearly a lot of work left to do, but the progress shown so far is still extrememely exciting and promising.

Ha wraps up by saying: > Be excellent again, Google. That’s all we ask.

I agree - let’s give them a chance, shall we?

Last week, I was inspired by a blog post to roll my resume into its own API. The challenge, as described in one of SEOmoz’s GitHub repos, was to build an API for your resume in Ruby. Having only very little experience with Ruby (and having meant to dive into it for a long time), I took the opportunity to teach myself something new.

Enter RESTume (see what I did there?).

This was a project (the core of it, at least) that took me no time at all to throw together while I waited to hop on a plane last week. I fleshed out the rest of it (unit tests, Bundler support, deployment on one of my VPSs) over the course of this past weekend when I had downtime during the Long Beach Grand Prix.

Needless to say, I’ll be attaching a link to RESTume with any new job application I submit. If nothing else, it’s an easy way to demonstrate ability and present yourself in a possibly unexpected way.

I recently made the decision to migrate off of Tumblr and start hosting my own blog. Initially, I was going to write my own and host it on one of my VPSs, but my limited time and other coding endeavors made that a project I was unlikely to finish anytime soon. So, instead, I opted for Jekyll and GitHub Pages - this gave me the freedom of rolling a blog that still felt like my own while removing 75% of the development work I would have had to endure otherwise.

And it’s awesome - I’m really enjoying it.

But, there’s a little bit of boilerplate that has to go into every post - not to where it becomes a massive undertaking to draft one, but enough that it gets a little tedious. A glance at various Jekyll implementations revealed that many users are using a Rakefile to handle the monotonous task of creating new content and generating the associated boilerplate. Well, given that Python is my language of choice at the moment, I thought this would be a good opportunity to teach myself something new (and avoid the temptation of being lazy and cloning someone’s Rakefile).

Enter Shovel. I first became aware of Shovel a few weeks ago when a weekly Python digest I receive made mention of it. Billed as “Rake for Python,” I became intrigued and poked through the repo for a few minutes before filing it away in my mind and went back to work. When the inspiration for writing a task automator for Jekyll struck me, I decided I’d use this library instead of Rake.

To get started, I simply invoked pip install shovel (in a virtualenv, of course). You could also clone it from GitHub and then install it (note that, at minimum, you’ll need argparse installed):

git clone https://github.com/seomoz/shovel.git
cd shovel
python setup.py install

Once I had it installed, I got to work. Shovel will automatically execute a specified task in any file called shovel.py when shovel <taskname> is called in the same directory. Alternatively, you can “modularize” (this isn’t strict Python modularization - see the docs for a more thorough explanation) your tasks by creating a shovel directory and creating Python files and/or subdirectories within it. For instance, if you had a task called cure in a file named cancer.py within a directory named diseases, you’d invoke it from the directory containing the shovel directory with shovel diseases.cancer.cure.

To start hacking with Shovel, you only need to import one class:

from shovel import task

task is actually a decorator class - to use it, simply decorate a method with @task and it instantly becomes a task you can execute with Shovel (provided it’s in a Shovel file or directory). So you can basically take any method you’ve written, wrap it with @task, and invoke it from the command line. Shovel will also look for arguments in the command to use as args or kwargs and uses comment blocks within the method as help dialogue (accessed, conveniently enough, with shovel help). These features make Shovel extremely easy and useful to use.

With this knowledge in hand, I set out to create a Shovel file that would handle my Jekyll dirty work. Beyond those two additional lines of code, there’s nothing extra you need to add to get Shovel to work with your code (besides maybe making errors exit to the command line gracefully). From there it was a bunch of string and date manipulation to get the results I desired - what follows is one of my Shovel tasks for creating a blog post (a link to the full source is below that) - CONFIG references a list instantiated outside the method:

@task
def post(title='new-blog-post', date=None):
	'''Creates a new blog post.

	Usage: shovel post --title "New Post" [--date "2012-4-3"]'''
	if not os.path.exists(CONFIG['posts']):
		sys.exit('shovel failed: ' + CONFIG['posts'] + ' is not a valid directory.')

	slug = re.sub(r'[^\w-]', '', title.lower().strip().replace(' ', '-'))
	if date and not re.match('^[0-9]{4}-[0-9]{2}-[0-9]{2}$', date):
		sys.exit('shovel failed: date must be in YYYY-MM-DD format. Please try again.')
	elif not date:
		date = datetime.datetime.now().strftime('%Y-%m-%d')
	filename = ''.join([CONFIG['posts'], '/', date, '-', slug, '.', CONFIG['post_ext']])
	if os.path.exists(filename):
		sys.exit('shovel failed: ' + filename + ' already exists. Please try again.')

	print 'Creating new post: ' + title
	with open(filename, 'w') as f:
		f.write('---\n')
		f.write('layout: post\n')
		f.write('title: ' + title + '\n')
		f.write('published: false\n')
		f.write('category: \n')
		f.write('tags: []\n')
		f.write('---')

The full source is available as a gist (for easy cloning) or in the repo that hosts this blog.

Shovel has some other interesting functionality that I won’t go into here - I highly suggest you go check out the Shovel repo, read the documentation, and get started with it if you find it useful - it couldn’t be easier to use.