In memoriam

20111006-094138.jpg

That was President Obama’s statement that I just read on my iPhone while vacationing in Europe. Today’s news is very sad news indeed and it seems the entire world is taking a moment to pause and reflect.

I got my first iPod in 2005, my first MacBook Pro in 2007, the iPhone in 2007, the MacBook Air in 2009, and the iPad also in 2009. I keep maintaining that I am not an Apple-only consumer, but it is more than coincidence that I continue to stay in the Apple ecosystem. Jobs and his team have created devices and software of beauty. Sure I complain about lots of things (stupid Finder, the iPad rotation lock became a mute switch briefly, MobileMe sync issues, etc.) but overall Apple products are the best tools for my job and my life.

Let me tell you a quick story. I am traveling in Barcelona right now and while at Antoni Gaudí’s famous Parc Guëll I ran into a couple of girls who needed help having their picture taken. I noticed that thy also had an iPhone, and it was set in Catalá language mode. But, I was able to navigate their phone and do more than press the shutter button: I was able to switch to HDR mode (“com HDR”) and show them how to fix their photo with Adobe’s Photoshop Express app.

What is significant about this is that even 1/3rd of a world away from home in another country in a language I don’t speak the user experience was consistent. Also because they could run the same apps we were to accomplish something together.

Jobs nurtured a culture of design that transcends barriers. Apple doesn’t quite compete on features or specs, they build solid user experiences in the hardware, software, and workflow. Perfect no, but far better than other companies. I keep reading about Android inconsistency issues, unpolished apps, wonky software integration. I don’t use an Android device regularly but I have used enough of them and often to know this tends to be true. Apple products work in an entire ecosystem in concert with each other. The computer and the smartphone and the cloud sync help move data around in ways to make it possible for me to do my job and my creative endeavors. And the Apple software has a high enough level of polish that it inspires other developers to do likewise.

I really think that is the true legacy that Steve Jobs will be leaving. He raised the bar on everything. He didn’t write the code or design the UI or create the TV ads, but like all great leaders he inspired people to do better. He wasn’t afraid to tell people “that’s shit”. He didn’t have time to be nice to everyone all of the time. He knew well of his limited mortality.

Other companies and leaders ought to consider this. Don’t just throw beta crap and half-polished products into the world. Try to really move the world forward somehow for the better. Don’t worry just about having bigger or better devices because that is what they told you to do in business school, ask the questions of social impact, environmental impact, and workflow impact. And perhaps most of all, truly find ways to surprise and delight people.

Comments

“Consider using bundle exec.”

I came across this error today when trying to run a simple rake routes:

You have already activated rake 0.9.2, but
your Gemfile requires rake 0.8.7. Consider using
bundle exec.

I had no idea what that really meant so I did a little searching and found that it is probably one of the most useful command combinations ever. From http://gembundler.com/man/bundle-exec.1.html:

Execute a command in the context of the bundle

Oh, so then running:

bundle exec rake routes

then produced the desired result. I was wondering if I was going to have to resort to RVM, which seems silly because isn’t the point of Bundler to lock an app’s gem versions rather than having to worry about which RubyGems you’ve installed at your system or user level?

Comments

join() is slower than the << shovel to join strings in Ruby

Turns out the Internet was right on this one: if you’re trying to create a big string from little ones it’s faster to << (less-than-less-than operator) on a String than to make an array of Strings and join its elements. Without diving into the Ruby code itself my guess is that strings are linked lists in memory and its end pointer is just moved, whereas making a bunch of array elements means new String objects for each and then having to walk all of the objects to form a new String in the end. (Granted, I’m using Ruby 1.8.7 still!)

Here’s the code:

require 'benchmark'
Benchmark.bm(20) do |x|
  x.report('join') do
    1_000.times do
      a = []
      1_000.times do
        a << 'This is some string stuff'
      end
      a.join
    end
  end
  x.report('<<') do
    1_000.times do
      a = ''
      1_000.times do
        a << 'This is some string stuff'
      end
      a
    end
  end
end

And the result:

          user     system      total      real
join  1.180000   0.390000   1.570000 (1.571057)
<<    1.090000   0.390000   1.480000 (1.491420)

Comments

Double-checking for nil and the Maybe Pattern

While listening to The Ruby Show episode #176 I heard about the ThoughtBot post about the Maybe Pattern as discussed in their “If you gaze into nil, nil gazes also into you” post.

It took me a minute to figure out what was going on. (Maybe I’m just getting slower in my old age.) Plagiarizing from their post, they included the code required to set up the Maybe Pattern and I’ll try to add my own comments in red so I feel like I’m adding something to this conversation:

This is modifying the base Object of which every Ruby object is
a child. Yes, that means even Nil gets an automatic maybe()
method stuck in it.

The idea is that if you think a method *might* return a value
then you ought to return your value with a .maybe() on it.
That accomplishes the "wrapping". You'll see that it takes
itself and returns an instance of Some with itself stuffed
into it. Thus at this point you really get a Some() object
back, not your original return value.
class Object
  def maybe
    Some.new(self)
  end
end

... Except for Nil. This one definitely is empty/blank/nothing
so we need to create an instance of Some that will throw
exceptions if you try to unwrap it.
class NilClass
  def maybe
    None.new
  end
end

And here is the Some object that wraps anything you give
it by storing it in its own @object attribute.
class Some
  def initialize(object)
    @object = object
  end

  This is how you "unwrap" an object. Pay close attention
that the None version of this will throw exceptions.
  def get
    @object
  end

  This is one way you can check to see if there might
be values.
  def present?
    true
  end

  And this is the other.
  def blank?
    false
  end
end

And back to some Magic Sauce. It creates a new error type,
Unwrapped, and will return it when you attempt to call get().
This is because as a consumer of the Some or None values
you ought to have checked present?() or blank?() first. That's
right, consumers need to be sure that they're not just going
to use a nil value.
class None
  class Unwrapped < StandardError; end

  def get
    raise Unwrapped
  end

  def present?
    false
  end

  def blank?
    true
  end
end

OK, great. So how do you use this in practice?

When you return a value that is absolutely true or false, then do so. If you think your return value might be null then wrap it by tacking on a .maybe() call.

The consumer of these return values should always check for present?() or blank?(). If something is not present or is blank then you should no longer need to access the return value because, well, you got your answer.

However, if you need to use the return value for something (e.g. it might be a single object, or might be an array, or a Hash, or ...) then you need to check if it's present?() and/or not blank?(). If that's true then you can call the object's .get() method to grab that value and continue with your logic. Like:

accounts = bank(me).accounts
# accounts might be nil ... check present?()
if accounts.present?
  account_list = accounts.get
  # Now account_list definitely has something which isn't nil!
end

The main thought I had in all of this is that this will create tons of wrapper objects that could just add bloat to your application. Plus there's the extra evaluation involved. In my own code I almost always just use the Rails .blank?() method to check if things are there. That seems to handle nil, empty strings, and empty arrays just fine!

Comments

You Don’t Know What You’ve Got Till It’s Gone

My 2010 MBA just started showing some unhappiness a few weeks ago. First there was the corrupt cursor, then there was the fact the fans didn’t seem to turn on even when the computer was under heavy load, and scrolling operations started going really really slowly—sometimes things would stutter, other times I could watch the screen repaint. So I just copied my work from the MBA to the old 2007 MacBook Pro. And my world has started to move at a snail’s pace.

The old MBP isn’t sluggish. No, it has a 2.33 GHz dual core Intel CPU and 3 GB of RAM. But it has that darned rusty spinning platter array…the HDD. 250 GB is nice, but after getting used to everything starting up after clicking its application icon or double-clicking a file, it’s painful. You don’t realize how fast the SSD is until you try to do everything you used to do and there are long pauses between clicking something to when something else happens. Even waking from sleep is slow.

The way of the future is clearly some kind of rapid storage mechanism like the SSDs or at least a hybrid approach to keep the most-used applications and documents in a quick-load cache.

Comments

Have your custom Paperclip Processors gone missing?

I’ve been converting a Rails 2.3.8 app into a Rails 3 app and one snafu was figuring out what happened to Paperclip. I use it to actually post-process audio files after upload, in this case slowing them down. I was getting this error:

uninitialized constant Paperclip::SlowerAudioFile:

Which is weird because I checked the readme and it still says to put them in the lib/paperclip_processors. I moved things around, I tried a bunch of little changes to the processor code, but nothing.

It seems the larger problem is just that the lib directory wasn’t being automatically loaded at all. (Turns out someone blogged this.) But by the time I had read that I had already taken the advice of a StackOverflow conversation and had just moved my processor to config/initializers/paperclip/slower_audio_file.rb, the beginning of the code looking like:

module Paperclip
  class SlowerAudioFile < Processor
    def initialize file, options = {}, attachment = nil
      ...
    end
    ...
  end
end

Comments

The CSS3 Spinning Ball of Awesome

I was playing around with CSS3 and came up with a pretty cool set of realtime transforming square DIVs warped onto a sphere. The result is a spinning ball of awesome.

See the live demo for yourself—please use Safari or Chrome.

Update 6/19:
It just got more awesome.

Comments

Deleting photos from an iPhone/iPad without importing

I’ve always been irked that iPhone photos can only seemingly be removed from the device by iTunes. The iPhone doesn’t show up like a normal camera device in Finder and you can’t get to it even through navigating with Terminal. Thanks to a post that came up during a little searching, it turns out the Image Capture app on Macs can do exactly that—I don’t know how to do this on a Win PC.

Yup, right in your Applications folder it turns out that there’s the Image Capture app:

If your iOS device is connected up you’ll see it on the left and then you can select any number of images and click the Delete button at the bottom of the window.

Comments

Life with an iPhone 4, all hail the Retina Display

I finally gave in. Yes I am fully aware that the white iPhone 4 launch is imminent (and Vodafone pictures are all over the Net right now) and that the iPhone 4S or 5 or whatever is launching soon, but I just couldn’t take it any longer.

My handy 3G that I have had since 2008 was barely doing anything useful. iOS 4 crippled the device so badly that even making calls was dicey. It got so bad that to use the Google Maps app it was actually faster to turn the phone off then on again to clear enough RAM and CPU to run it. After one frustrating evening of almost throwing my phone under a car tire I decided I would just drive over to an AT&T Store an pick up a new phone. That was probably 2 weeks ago.

Since then I have been using an iPhone 4 (black, 32 GB) and life has again returned to normal speed. I can use maps again. Apps don’t spontaneously crash. Phone calls actually work. The camera app works. Focusing is WONDERFUL. Finally I can rotation-lock the phone. And of course the Retina Dispaly is just amazing.

About that display: it’s not like I haven’t used friends’ iPhone 4s before. I would say that I know quite a number of people who did the upgrade or this was their first smartphone. Still, living with a display that has a high enough resolution that you can’t see pixels is pretty amazing. And now I can’t go back to any other phone.

There is just something about not being distracted by those tiny grid lines that makes using this device a pleasure. The type is so clear and easy to read that I subjectively feel that it is less effort to read text on it. Especially when it comes to small text, there is no blurring or antialiasing. That means a lot less strain all while packing a lot more readable information onto the screen. I am not distracted by the device because the computer pretty much becomes invisible.

All phone, tablet, and PC manufacturers ought to strive for a pixel density greater than 266 pixels/inch. I remember when I saw a Sony VIAO P with its 266ppi display. Windows was pretty much unusable because the UI didn’t scale its icons up, but oh man did the text look amazing when reading web pages. That same clarity is what I experience with the Retina Display. And now that we know it is totally possible to produce these super pixel-dense displays en masse, it’s just about time we can escape from pixels altogether. I am salivating for the day when we can use SVG or EPS as system-standard graphics formats that render amazing clarity for icons and UI elements at any screen size and resolution.

Comments

Great use of 3D transforms

I would have to say it is the subtle things that add the “wow” factor to web pages. I happened across Panic’s blog (the makers of Transmit, Coda, Unison) and in Safari the effect of mousing over the sticky notes is that they appear to lift off of the page as if you slid a finger under the note.

I’ve been playing with things like card flipping and rotation, and that is a great way to reveal/hide information. But sometimes it’s the simple that really gives something a little extra polish.

Comments

« Previous entries Next Page » Next Page »