Why Apple Annouced the Watch in Advance
It’s uncharacteristic of Apple to announce things so for in advance of their availability. Usually they wait till the hardware is going into production. I can think of only three times they have done this recently: the watch, the phone, and the x86 switchover.
I’m sure Apple would have preferred to release the watch fully formed and ready to go as a surprise in the spring of ’15. However, it would be impossible to make a product of the quality that Apple desires while keeping it a secret from most of the company. That’s why I believe the announcement was not directly for the public’s benefit. Instead, Apple announced the watch far in advance of availability mainly to inform their employees.
With the watch public knowledge, everyone at Apple can get excited about it and make all of Apple’s products work with the level of integration that their customers expect. It would be impossible to keep it a secret if everyone at the company was aware of it so Apple made a dramatic public announcement. That way they also get to control the message, kill competitors, and deny months worth of leaks to naughty reporters and rumor sites. Same deal with iPhone and x86. Achieving success as defined by Apple required a concerted effort by most of the company.
The downside: competitors get some extra time to try to copy it. That’s why Apple only does this for the really big changes.
Shellshock Not So Shocking
Shellshock is going around but there is not so much commentary about why it isn’t so shocking to people who have been around a while. Here’s some sage advice from a couple of legends in the security field. Simson Garfinkel and Gene Spafford wrote Practical UNIX and Internet Security 20 years ago. Even then, it was well known that shells and untrusted input were bad news. From the second edition (1996.) Emphasis is mine.
18.2.3.2 Testing is not enough!
Many programming languages, including C, ksh, sh, csh, and Perl, provide the means to spawn subprocesses. You should try to avoid using these features when writing CGI scripts. If you must spawn a subprocess, avoid passing through any strings that are provided by the user. If you must pass strings from the user to the subprocess, be sure that it does not pass shell meta characters including the `$|;>*<&> characters.
23.2 Tips on Avoiding Security-related Bugs
Check anything supplied by the user for shell meta characters if the user-supplied input is passed on to another program, written into a file, or used as a filename. In general, checking for good characters is safer than checking for a set of “bad characters” and is not that restrictive in most situations.
Shellshock is just as much an error by the developers of calling programs as it is a bug in the shell. Sure, the shell shouldn’t execute random stuff placed after a function definition in an environment variable but you probably don’t want random people on the internet defining functions in the shell you’re using to execute stuff, either.
Resolving the conflict between AFNetworking and SDWebImage
RestKit and SDWebImage are both very useful libraries but they conflict. The problem is that RestKit depends on AFNetworking, and both AFNetworking and SDWebImage add the same methods to UIImageView. Fortunately, there is a solution that doesn’t involve forking any repos. It’s still a hack, but it works.
First, go get the AFNetworking podspec for whatever version you are using and copy it into your repo. Now edit this podspec and add the following lines:
s.exclude_files = 'AFNetworking/UIImageView+AFNetworking.*'
s.dependency 'AFNetworking+Dummy', '~> 1.0'
exclude_files lets us leave out code we don’t want but other headers will still try to import it. So we make our own pod that contains empty headers with the same name and make AFNetworking depend on it.
To create our pod containing the dummy header file, make a directory called AFNetworking+Dummy and put a podspec file of the same name inside of it. It should have the following contents at a minimum:
Pod::Spec.new do |s|
s.name = 'AFNetworking+Dummy'
s.version = '1.0'
s.source_files = '*.h'
end
Now touch the file AFNetworking+Dummy/AFNetworking+UIImageView.h or otherwise create an empty file with that name.
Now you just need to update your Podfile so Cocoapods can find your dummy pod and your custom podspec.
pod 'AFNetworking+Dummy', :path => 'path_relative_to_podfile/AFNetworking+Dummy'
pod 'AFNetworking', :podspec => 'path_relative_to_podfile/AFNetworking.podspec'
Now you’re ready to use both RestKit and SDWebImage at the same time!
Crap Startups are Trying to Pull These Days
I’ve been looking for a new gig off and on for the past year. I’m pretty picky and I have a good nest egg. I also get a few contract gigs here and there that keep me from being desperate. I’m really only interested in startups and the companies I have interviewed at generally have between 5-50 employees. In this last year I’ve run across some serious BS I haven’t seen before in my 20+ years of working in this industry.
Lowballers – Even though the company employs dozens of software developers and certainly has defined both a narrow salary range that they are willing to pay for the position and a benefits/perquisites/equity package, they refuse to put together an offer unless you tell them how much you want/made first. I’ll politely say that I’ll consider any reasonable offer and that they have a better idea of what I’m worth to them than I do. An honest company will turn around and make an offer somewhere in the range they already had in mind. Lowballers just fade away. Hint: if they come out and actually say they don’t lowball then they almost certainly do.
Over Lawyering – Thanks to Business and Professionsl Code Section 16600, non-compete agreements aren’t legal in California except in a couple of well defined circumstances like being a partner in a company you just sold. Customer non-solicit agreements are also void and employee non-solicits are almost certainly not legal either. Still, as a condition of employment I’ve been asked to sign an agreement that contains both kinds of non-solicit provisions. What really got me was an attempt to get around non-compete agreements by requiring me to agree to allow this employer to contact any future employer or business associate so they can scare them about this agreement I’m supposed to sign. I’m sorry but no, I’m not agreeing to give you ten days notice of any business activity I plan to undertake for a year after leaving your company and I’m certainly not authorizing you to contact my future employers or business associates. The fact that the 1 year period reset after any breech made it clear that it was punishment.
Free Work – Tech companies have been trying to get out of paying any overtime for quite a while by bribing the legislature to change the definition of “exempt” employees. Even though exempt status is for managerial types who have the authority to assign work and set their schedule it’s used on software developers who don’t really have much choice. Still, I ran into a particularly egregious example recently with a startup. At the first couple of rounds of interviews the founder/CTO kept bringing up how it wasn’t a 9-5 job and they all work 60 hour weeks. I would too if I owned 40% of the company… Then after two rounds of interviews, including 6 hours of on-site interviews with plenty of whiteboard coding and problem solving, they wanted me to come in for a full day of hacking with them. That’s not completely unreasonable and at that point I was still interested in working with them. Well, the hacking project turned out to be some low priority project of theirs instead of something totally unrelated. It also wasn’t really something that could be done in a day by someone unfamiliar with the software involved. After a day I didn’t get very far (does anyone get much work done on their first day?) so they wanted me to come in again, because they still weren’t sure. After they offered to pay me to come in again to the tune of about $10 an hour (less than minimum wage in San Francisco) I knew they were bad news. I think they really wanted me so instead of breaking it off they said they wanted to “pause” the interview process. It’s not dead, just paused.
In case you are wondering, here are the signs of a good, well managed company:
- Has a well defined and rigorous interview process conducted by employees who really want to be sure they are only hiring good people.
- Is able to reach a hiring decision quickly, like within 24-48 hours of a full day on site interview.
- Knows how much they should be paying each position, aren’t afraid to make what they know to be a good offer to someone they want, and aren’t interested in seeing if they can get someone they are on the fence about for a really good price.
- Respects employees and understands that regularly working past the point of fatigue results in bugs and is therefore inefficient and unprofessional.
- Limits poaching by keeping employees and customers happy instead of attempting to use the force of law.
Socket.IO + TornadIO2 == happy hacking
I’m building a little appliance with a web interface so I needed to do some comet/websockets whatever. I wanted something that worked straight away with minimal pain. Surprisingly, several things I tried didn’t work.
WebSockets isn’t there yet. The WebSockets demos I tried didn’t work on FireFox, even after turning WS on in about:config. They also didn’t work on Mobile Safari. Most of them fell back on Flash which doesn’t work on Apple hardware.
What did work was Socket.IO. This consists of client side JS to handle all the details of WS/long-polling/whatever on what browser you’re on. The Socket.IO folks intend for you to use server side JS in the form of Node.js, but that was not too interesting to me. In general I’m not convinced that there is enough sharing of code between client and server to make being hobbled by JS on the server side worth it. Also, my server needs to use some C APIs and I already had a Python C module to do so.
For Socket.IO with Python I found a cool project called TornadIO2 which is a Socket.IO adapter for Tornado. TornadIO2 is well integrated with Tornado and worked for me on the first try so I’m going with it. Tornado has an asynchronous interface with callbacks, which is not ideal and another reason why I’m not keen on Node.js, but there is a coroutine library built in that is based on Python generators.
Tornado also has good ZeroMQ integration. ZeroMQ is another good piece of kit that probably deserves its own blog post.
TornadIO2 gets the thumbs up from me. If you want to make a real-time web application with a mature language like Python and without screwing around with what should be a completely solved problem, check it out.
Joel Test Fail
If you’re involved in software then you may have heard of the Joel Test. It’s a quick, unscientific way to get a ballpark estimate of how dysfunctional a software development organization may be. A company with a low score needs help and before joining you should seriously consider if you are going to be the person to help them. A high score is an indication that the organization is well managed.
The thing about the Joel Test is that not all of the questions are equal in how well they represent the health of the organization or the quality of its management. Likewise, some things are much easier to fix than others. For instance, some people haven’t experienced the benefits of continuous integration and/or may not be aware of new tools that greatly simplify the creation of virtual integration environments. Even without CI, for instance, it may be a good place to work and it shouldn’t be difficult for a good developer with some leadership skills to introduce better development practices.
One of the questions on the Joel Test is “Do programmers have quiet working conditions?” The answer at virtually all software companies is NO. Famous exceptions are Apple, Microsoft, and Fog Creek, of course. Without quiet working conditions it is more difficult and expensive to implement all of the other things in the test or the product itself. It’s harder to get good people. The people you have aren’t working at their full potential or they are sacrificing their lives to work early/late in order to avoid the distractions of their offices, which leads to burnout and turnover. If you’re at a place without quiet working conditions then it is almost certain that there is nothing you can do to change it. Management didn’t see it as a problem in the first place and is unlikely be persuaded by any argument. That’s why this question is actually the most important question on the test.
I was just looking at some jobs on Stack Overflow and noticed that employers may answer the questions in the Test and have their “score” featured in search results. The first ad I looked at that responded to the Test had a score of 11/12. It’s a startup in San Francisco called Grockit. The only question in the Test that they responded negatively to was “Do you do hallway usability testing.” If a company answers affirmatively to all of the other questions then it is probably a good place, because nobody is going to stop you from asking the next person that comes down the hallway to test out a new feature.
So I go to Grockit’s web site and click the “Jobs” link and what do I see? You guessed it, a picture of all their developers jammed in a single room. I have no doubts that there is a kitchen and dining area just out of the frame.

Bing vs. Google: Maps
I punch “28th and Sanchez” into Google. Google recognizes this as a possible address, searches its database nearby to wherever it thinks I am located, and shows a small map at the top of the search results. If I click on the map or enter the same query directly into Google Maps then it will go directly to a map of the intersection it thinks I want. It was correct and my desire was satisfied simply and easily.
Try the same thing with Bing (I actually tried Bing first.) Bing doesn’t recognize that it is an intersection and displays no map in the search results. No problem, I’ll click the “Maps” link at the top. Bing Maps doesn’t know what I’m talking about. On the left you can see that there are two query fields labeled “Business name or category (optional)” and “Location:” Can you guess which one was prefilled with my query from the search engine? A minor irritation, I think, I’ll just cut/paste the intersection into the location field. Nope, Bing Maps still doesn’t have any idea what I’m looking for. Add “, San Francisco CA” and it finally shows me the map I want.
If you try to enter a street address without a city or state Bing appears to return the first result it finds. So entering some addresses nearby to me here in San Francisco yielded results in Lubbock TX and Germany. Seriously, when I entered the address of the building I’m sitting in, Bing did not find any exact matches and a map of the Eastern hemisphere was displayed with pin indicating the location of what it thought was the best match, some place in Germany with a name that isn’t even close to my query.
Did it never occur to the Bing team that people searching the map without specifying a city/state want the match closest to their location? That I might want to enter an intersection like I would a simple street address? Did the product manager never try entering an address or intersection without specifying the city or did they think those results were acceptable?
Background OCR with ScanSnap / ABBYY FineReader on Mac
I got a Fujitsu ScanSnap 1500M in an attempt to take control of the paper in my life. The software it comes with is tolerable. However, the biggest annoyance is if you set it for automatic OCR, you have to wait for the OCR to finish before you can continue scanning. The scanner is much faster than the OCR, which only uses a single core even on a multi-page document.
It is easy to setup a Finder Folder Action to have the OCR happen automatically in the background so you can continue scanning. The downsides: you must setup a folder action for every folder and you can’t move the PDF until the OCR process is done. Also, the UI for setting up folder actions is crap.
Put the following AppleScript into a file called “OCR.scpt” and put it in “~/Library/Scripts/Folder Action Scripts.” Then right click a folder in the Finder and choose “Folder Actions Setup” and assign this script to any folder which you want incoming PDFs to get OCR’d.
BitTorrent InfoHash to Magnet URI Service on OSX
Some public torrent sites display on a torrent detail page an “infohash,” a SHA1 hash that uniquely identifies a Torrent, in hex format. An example would be “ffcbc1ea9ec0bc557f8fa42e673cdda0aea4d7e7.” Some sites provide a “magnet” URI that lets you download the torrent without a torrent file, possibly without a tracker. Magnet URIs for BitTorrent simply contain the infohash in a different encoding and look like this: “magnet:?xt=urn:btih:77F4D2U6YC6FK74PUQXGOPG5UCXKJV7H”
The cool thing about a magnet URI is it will let you download a torrent without using any trackers or conveniently send a torrent to someone else in a tweet or email. The client will go to the DHT and download the torrent file from other peers and not use a tracker. Some sites don’t publish the magnet URI but do show the infohash. For those you can convert the infohash to a magnet URI. It won’t work for “private” torrents because most clients won’t announce their contact information to the DHT for those.
If you’re on a Mac, it’s easy to use Automator to create a Service menu item that will take an infohash selected in any application, turn it into a magnet URI, and put it back on the pasteboard. Then you just have to go to your favorite BT client and open it. Some clients will automatically grab whats on the pasteboard for you.
- Open Automator and use the Service template.
- Add a “Run Shell Script” action from Library > Utilities
- Make sure “Shell: /bin/bash” and “Pass Input: to stdin” is set
- Paste in this code:
python -c "import sys;import base64;sys.stdout.write('magnet:?xt=urn:btih:%s' % base64.b32encode(sys.argv[1].decode('hex')))" $@ | pbcopy - Save as “To Magnet” or whatever
Now you can select an infohash in a browser or wherever (copy is not necessary,) go to the Services menu, and hit “To Magnet.” Then just paste your magnet URI into your torrent client or wherever necessary!