Seven Things About ITunes That Are Just Plain Wrong

Yeah, there’s lots to love about ITunes. The overall architecture is excellent and if this is what Spotlight will become in the next OSX (as rumoured), that’s all good. However, there are also some things that are really bad in ITunes. It’s interesting that Apple still seems to be the best player out there despite these problems. It doesn’t say much for the competition. (The same can be said about a number of glaring problems with the IPod, especially its poor podcasting support, which the other players blissfully ignore while continuing to hope people will suddenly switch if they introduce better bubblegum colours, advertise, and slash prices. A separate post, maybe.)

<

ol>

  • Deleting. I like playlists, especially smart ones. So I spend precious little time looking at my entire Library. But if I hit clear in a playlist, it will only remove the songs from the playlist, whereas it would delete them in the Library. There is apparently no way to delete songs when you’re viewing them in a playlist. Weird. Violates the all-important HCI principle of consistency in favour of some minor robustness. (I could always undelete if there was a problem.) I have a nice Smart Playlist for all podcasts over one month old, but to delete them I can’t just delete all in the playlist. Instead, I’m forced to use an ugly workaround: Rate them all as 1-star, view in the library, sort by rating, and manually select and destroy all 1-star items.
  • Duplicate Songs. I wrote about this a year ago, and the problem remains; I still pity the fool who accidentally imports the same song more than once (which is pretty easy to do). Sure, there’s a Duplicate song finder, but it’s just about useless because you still have to manually go through and delete every single duplicate, even though it should be obvious to ITunes they are identical! Even if they both point to the same file, ITunes still won’t help you out!!! (It’s sort of beyond me why ITunes even lets you have two records pointing to the same file in the first place.)
  • The Music Store. It might pull in ninety-nine gazillion dollars a year, but I’d rather use Amazon any day. Logging in to the music store takes about 5-10 seconds, then every time I want to change my location within the store, another 5-10 seconds. It seems a lot longer than loading a web page, and I think that’s because it seems to load all images at the same time as the content. Overall, an Amazon page will probably load slower, but the content will load first, so I can easily go back if it’s not what I want or navigate somewhere. Furthermore, caching seems very limited, so if I go forward and back again, I have to wait once more. Furthermore, the ancient practice of Pre-Fetching seems to be non-existent.
  • Video. Handling of videos is just a little bit wrong. It sort of works okay if you’re happy to have Amanda’s talking head sitting in the tiny box in the corner, but switching in and out of full-screen, at least on the powerbook, causes all sorts of groaning that don’t actually occur with other apps. I also don’t get why, or under what circumstances, embedded links work, because AFAICT, they don’t.
  • Podcasting. Fair dinkum props to Apple for getting into podcasting fairly early on (certainly more than other companies who continue to miss the boat). But you know what? The actual implementation isn’t great, and I’m surprised so many of my podcast listeners come through ITunes when they could be getting so much more out of life by using PodNova or Odeo with any of the quality dedicated clients (like the open-source Juice). It’s poor because adding feeds relies on the same tedious Music Store interface, loading at the usual snail’s pace as you decide which podcasts to subscribe to. You can speed things up by using the Browse interface if you’re lucky enough to know about it, but even then, you’d probably want to look up the podcast’s previous shows, how recent they were, etc, before committing to it. Furthermore, there’s no concept of sharing, tagging, etc, which makes the online services so much more useful. The actual integration of subscribed podcasts seems quite nice, so I wish they got this aspect right as I’d like to use it. But, for now managing the list of feeds is too painful. If you subscribe to 3 or 4 feeds, ITunes is fine, but I subscribe to 100 feeds, which makes ITunes impossible. BTW, If 100 feeds sounds like a lot, keep in mind that some are mostly one-off like conference series, some publish infrequently, such as cough some of the Ajax feeds around the place, some are optional fillers like music or BBC newscasts, and some I’ll listen to if the topic is particularly interesting, otherwise throw away (even though some advertiser probably just paid for my “earballs” :-). All up, it amounts to about 30 hours a week, not too ridiculous.
  • Radio. I’m glad this feature is here, but it’s never been updated and quite frankly is wrong on so many levels. Streaming frequently fails due to bandwidth problems. Is that the fault of ITunes? Yes it is. If it observes that a station is frequently failing, it should wipe it off the list or warn me, not just clutter the interface with it. There are hundreds of stations, and I’m not going to remember how well each works. I could rate them myself in theory, but in practice I can’t because there’s no rating field! Really, I can’t do anything much about the directory at all – can’t set genres, can’t re-organise, etc. It’s true I can add my own feed, but trying to find radio station feeds on the net is not as easy as you’d think. In the case of some stations in the directory, they’ve been off for months, but they remain in the ITunes directory. The directory itself has a slightly odd organisation (a good case for tags instead of a hierarchy). It combines no less than 79 streams in one category, “International”, a flat structure containing J-POP, Salsa, and “Hawaiian Rainbow”, among many other cool things that would ideally be placed in their own little category. The use of “International” here implies it’s synonomous non-American, fair enough, but then what is “Reggae/Island” doing in a separate category. A better approach to radio stations would be something more like the music store (but well implemented).
  • Streaming. Okay, radio doesn’t really work too well, but I could easily take an RSS-powered feed from WebJay right? Nup. According to WebJay (now part of Yahoo!), “If you open a playlist in iTunes it will only play the first song and this will drive you crazy.” WebJay is only able to offer three very unappealing workarounds: Don’t use ITunes, Use a third-party utility, or download to your desktop and open manually. I’ve been using a third-party utility, but unfortunately ITunes adds a permanent entry to the URL for each song being played. Spend a few hours playing tracks and you have to go through and manually delete a hundred or so items!
  • Ballmer: Advertisers, Advertisers, Advertisers, Advertisers

    Ballmer gives it up for advertisers

    I was surprised to see this video of everyone’s favourite professional wrestlerCEO giving it up for “Advertisers, Advertisers, Advertisers!”. You might recall my post about my inclusion of the more famous “Developers” call-to-arms in a podcast (with good fortune, it was the Ajax podcast, the most downloaded podcast I’ve done). Including this new chant just wouldn’t be right unless I changed the name here to “Software As She’s Advertised”. But we all know quality software is about the design that goes into it, not the shiny package you slip it into at the end.

    Look out for the following jingles at a conference near you:

    • “XMLHttpRequest, XMLHttpRequest, XMLHttpRequest, XMLHttpRequest”
    • “Configuration Management, Configuration Management, Configuration Management, Configuration Management”
    • “Test-Driven Development, Test-Driven Development, Test-Driven Development, Test-Driven Development”

    “I…love…this…conference theme and the most common profession among those of you who are in the audience today, including but not limited to people who may be watching remotely over an HTTP stream….yeah!!!!!”

    Where’s that Sound Coming From?

    Stop the Noise. Don't really stop the noise, I usually like it, but nonetheless I like this photo too.

    Sound Thinking

    Where's that sound coming from?
    An app inside my box?
    Is it ITunes on the desktop
    Or YouTube in the 'Fox?
    
    A Skyper shouting at me?
    Or Pandora playing faves?
    Media Player come to life?
    Hmmm ... Real with recent saves?
    
    A podcast I'm preparing?
    A vidcast made for nerds?
    Nope, it seems to be this picture,
    It says a thousand words!
    

    Huh?

    I started writing the first four lines of this post when I realised I was writing a “poem”, so I just kept going even though I’m clearly no “poet”.

    Anyway, my point is:

    • People multitask, running ten or more browser and desktop apps at the same time.
    • Sound is arising a lot inside the browser these days, and I’m not talking about Axel F midis running in an off-colour GeoCities page. YouTube and wannabees, Flash telephony like JaJah, Podcasts being played by publishers as well as aggregators, Flash and Ajax games. Hopefully we’ll see more Ajax developers introduce Richer Plugins to include sound, because good sound effects make interaction more productive and more fun.
    • So I’d like to see an app that locates the visual source of the sound, which 95% of the time, can indeed be traced back to a particular window or browser tab. And if there is such an app, it should be baked into the OS. For instance, you could use an Alt-Tab-like sequence to isolate each sound as you rotate through the various sources. Nothing more annoying than having twenty browser tabs open and not knowing where the sound is coming from.

    Update Feb 26, 2012: And finally Chrome introduces it. Available now on Canary channel.

    Bitten By Rails Pluralization/Inflection

    If you’ve heard DHH or other Rails enthusiasts introducing Rails, they’ll often point to the neat inflection module, which maps back and forth between plurals and singular forms, among other things. Even if not the most killer thing about Rails, it’s an excellent introductory topic as it quickly conveys the humane nature of the Rails API as well as the principle of Convention Over Configuration.

    It’s also the kind of thing where you think “These exception cases probably won’t happen to me…how likely am I to be coding Octopi, Sheep, or Oxen” (unless you work in the underwater farm sector). Actually, it turns out exceptions do happen more than I at first expected and are generally handled in a clean way. But how about exceptions that can’t be handled?

    Where the inflector isn’t smart enough, I’ve seen the advice (e.g. in PragRails) to override ActiveRecord.set_table_name. e.g.

    1. class Sheep < ActiveRecord::Base
    2.    set_table_name "sheep"
    3. end

    But today I had a problem. My class, “Fave”, was leading to an error message about class “Fafe” not found, while loading the fixture. After some bemused grepping, I realised that it was due to this pluralisation issue. Seems that the fixture loader performs some singularization – here’s an extract from fixtures.rb:

    1. @class_name = class_name ||
    2.                   (ActiveRecord::Base.pluralize_table_names @table_name.singularize.camelize : @table_name.camelize)

    Overriding set_table_name doesn’t solve this problem. Which is surprising given the usual advice, so maybe I missed something!!! The solution that worked for me was to configure the Inflection module. I now have this in my config/environment.rb:

    1. Inflector.inflections do |inflection| inflection.irregular "fave", "faves"
    2. end

    Now that Rails’ notion of grammar has been redefined, the set_table_name can be removed as it’s redundant.

    Side note: Since people are often intrigued by the pluralization algorithm but probably not enough to hunt down the code, here it is – taken from active_support/inflections.rb (which confirms why “Faves” became “Fafe”):

    1. inflect.plural(/$/, 's')
    2.   inflect.plural(/s$/i, 's')
    3.   inflect.plural(/(ax|test)is$/i, '1es')
    4.   inflect.plural(/(octop|vir)us$/i, '1i')
    5.   inflect.plural(/(alias|status)$/i, '1es')
    6.   inflect.plural(/(bu)s$/i, '1ses')
    7.   inflect.plural(/(buffal|tomat)o$/i, '1oes')
    8.   inflect.plural(/([ti])um$/i, '1a')
    9.   inflect.plural(/sis$/i, 'ses')
    10.   inflect.plural(/(?:([^f])fe|([lr])f)$/i, '12ves')
    11.   inflect.plural(/(hive)$/i, '1s')
    12.   inflect.plural(/([^aeiouy]|qu)y$/i, '1ies')
    13.   inflect.plural(/([^aeiouy]|qu)ies$/i, '1y')
    14.   inflect.plural(/(x|ch|ss|sh)$/i, '1es')
    15.   inflect.plural(/(matr|vert|ind)ix|ex$/i, '1ices')
    16.   inflect.plural(/([m|l])ouse$/i, '1ice')
    17.   inflect.plural(/^(ox)$/i, '1en')
    18.   inflect.plural(/(quiz)$/i, '1zes')
    19.  
    20.   inflect.singular(/s$/i, '')
    21.   inflect.singular(/(n)ews$/i, '1ews')
    22.   inflect.singular(/([ti])a$/i, '1um')
    23.   inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, '12sis')
    24.   inflect.singular(/(^analy)ses$/i, '1sis')
    25.   inflect.singular(/([^f])ves$/i, '1fe')
    26.   inflect.singular(/(hive)s$/i, '1')
    27.   inflect.singular(/(tive)s$/i, '1')
    28.   inflect.singular(/([lr])ves$/i, '1f')
    29.   inflect.singular(/([^aeiouy]|qu)ies$/i, '1y')
    30.   inflect.singular(/(s)eries$/i, '1eries')
    31.   inflect.singular(/(m)ovies$/i, '1ovie')
    32.   inflect.singular(/(x|ch|ss|sh)es$/i, '1')
    33.   inflect.singular(/([m|l])ice$/i, '1ouse')
    34.   inflect.singular(/(bus)es$/i, '1')
    35.   inflect.singular(/(o)es$/i, '1')
    36.   inflect.singular(/(shoe)s$/i, '1')
    37.   inflect.singular(/(cris|ax|test)es$/i, '1is')
    38.   inflect.singular(/([octop|vir])i$/i, '1us')
    39.   inflect.singular(/(alias|status)es$/i, '1')
    40.   inflect.singular(/^(ox)en/i, '1')
    41.   inflect.singular(/(vert|ind)ices$/i, '1ex')
    42.   inflect.singular(/(matr)ices$/i, '1ix')
    43.   inflect.singular(/(quiz)zes$/i, '1')
    44.  
    45.   inflect.irregular('person', 'people')
    46.   inflect.irregular('man', 'men')
    47.   inflect.irregular('child', 'children')
    48.   inflect.irregular('sex', 'sexes')
    49.   inflect.irregular('move', 'moves')
    50.  
    51.   inflect.uncountable(%w(equipment information rice money species series fish sheep))

    Guard Clause Considered Helpful

    Apparently, PragDave recently questioned the conventional wisdom about GOTO considered harmful (does this mean all “X considered harmful” articles will be retrospectively struck off the record?). Ivan Moore’s given an example as to why the rule of “a single exit point” sucks, and I agree.

    Another reason for multiple exit points is guard clauses. Code units, like classes or functions, ought to look right at a high level. Just like with a piece of writing, it’s important that the overall structure gives you the big picture. Guard clauses help here. You can say, “Okay, let’s get the cruft out of the way – the trivial cases, the exception cases – and now we can focus on the main thing the function’s meant to do.”

    1. void foo() {
    2.   if (nothingToDo) { return; }
    3.   // Implement typical behaviour of foo()
    4. }

    is much more readable than:

    1. void foo() {
    2.   if (!nothingToDo()) { // Hold my breath until the end
    3.     // *ugh* The typical behaviour buried in an if-clause
    4.     // And adding insult, we're now indenting more than we need to
    5. }

    Steve Freeman points out, Ivan’s particular example could be refactored nicely into a single ternary operator statement. While they don’t scale to larger, more complex, functions, ternary operators are a very handy tool for the reason he explains.