nuthole.com "just a little bit more than the law will allow"
contact:email
subscribe:feed
compute
Powered by Blosxom
Get Firefox!
geourl
subgenius
spampoison hosting rails

the great iPhone swindle

posted by jack at 17:22 CET in / compute feed

Tech Sweden is abuzz with news of Telia's iPhone pricing plans having been released today. Unlike the AT&T contracts in the U.S., Telia's contracts for Sweden don't directly include unlimited data transfer. Also unlike the AT&T contracts, at first blush (and subsequent for that matter) the Telia contracts seem really pretty expensive, especially the iMaxi plan, which starts at about $150/month!

So, looking to maximize my bang for the buck, I worked up a little spreadsheet showing the monthly and total costs for the various phone models and plans.

  • The figures in bold are prices straight from Telia's site.
  • The figures in light blue are monthly recurring costs for the stated data amounts, and a second row for unlimited data amounts (arrived at by adding in the cost of Telia's 9kr/day "maxtaxa"; Note that this represents the maximum amount you'd pay in a month, assuming you blew past the free amount in the first day and kept using some amount of data transfer every single day of the month)
  • The pale green figures show the absolute smallest total cost for each of the two models, and the pale purple figures show the smallest total cost for each of the two assuming unlimited data. Note that these all wind up being for 18-month contracts, so for comparison's sake I've included extended calculations for the 18-month contracts, adding a row for what you'd pay if you continued with a normal Telia "fastpris" account at 199/month, and another row that adds in that plus the "maxtaxa" to arrive at the costs for unlimited data.
  • The dark green figures show the smallest total 24-month cost for each model, and the dark purple figures show the smallest total 24-month cost for each model assuming unlimited data.
  • I haven't calculated anything around extra minutes or extra SMS, since I (and probably many other iPhone users) assume that data usage will be a much more important factor, and in my case I'm sure that I'll seldom use more than 100 minutes or 100 SMS per month.

Some interesting points pop out when looking at this. For one thing, the more expensive plans really seem disastrously expensive, especially iMaxi. If you're not planning on calling for 16 hours a month or sending 1000 SMS/month (who does that?) then those really seem like a waste. Even if you were using that much, it seems like the standard tariffs, combined with the iMini plan, would still be much cheaper. Again, for my anticipated usage I really don't care, but maybe someone who really is a big voice or SMS user will calculate these things.

Another thing that strikes me is that there is an interesting pattern to these numbers. If you look at the dark purple and dark green figures, the cheapest totals (for minimum and unlimited data) for each model, they both are for a 24-month contract. Compared to building an equivalent usage period by combining an 18-month contract and a 6-month "fastpris", they are just barely cheaper; precisely 200kr in each case. And that's all assuming that Telia's "fastpris" and "maxtaxa" will remain at their current levels for the next 18 months. If they get even just a tiny bit cheaper, or if another operator has a better deal for iPhone users 18 months from now, then the 18-month contract will turn out to be a better deal in the long run.

So, it seems that financially, whichever of the two models you're looking to buy, the iMini 18-month plan seems like the way to go. Again, things may be different if you plan on doing lots of voice calls or SMS, but I'll leave that for someone else to figure out.

permalink | digg this | slashdot this | add to del.icio.us | 1 comment (add more!)

Twitter? Twucket.

posted by jack at 16:11 CET in / compute / programming feed

Just in time for WWDC '08, allow me to introduce you to Twucket.

Twucket is a new Twitter client for Mac OS X that I am releasing as freeware. I created Twucket because I wasn't happy with any of the available ways to view my Twitter page. The actual twitter website is a hugely-rendered page, and requires you to go to the browser now and then to see if anything has come in; The standalone clients I tried were either wasteful of screen real estate, or didn't fit in with the overall Mac GUI, or contained ads.

Twucket suffers from none of those problems. Its interface is minimalist and small, it behaves like a normal Mac application, and it doesn't insert ads into the display. What it does offer is a compact, simple Twitter interface with a few features that Twitter users will probably appreciate. It uses a relatively small amount of screen real estate per message, so you can leave a small window open in a corner of your screen that is still large enough to show the latest 4 or 5 messages you've received.

I do have additional plans for future versions of Twucket, but today is the day for 1.0.0. If you're a Twitter user, please give it a try and let me know what you think!

permalink | digg this | slashdot this | add to del.icio.us | 0 comments (why don't you write the first?)

Your New Favorite Podcasts

posted by jack at 17:09 CET in / compute feed

Podcasts. Either you're listening to them, or you're not. For me, living geographically removed from the American mediasphere, podcasts are a great way to keep up with American and other English-language professionally-produced audio content, not to mention all the stuff that people are putting out there on their own.

It's a bit like having your own radio station, just full of stuff you actually want to hear, that you can listen to whenever you want. I've usually got my iPod half-full with a variety of shows; I don't listen to each episode of each show, but I've got a pretty wide span so I can pick whatever I want at whatever moment I feel like listening.

I don't often see people writing about what podcasts they're listening to, and randomly browsing podcast sites looking for good shows takes time, so it's not always easy to find the good stuff that's out there. Just for the sake for sharing, here are a few of my favorites.

Le Show

Harry Shearer, the voice of many of the Simpsons characters, and one of the co-stars of the classic film Spinal Tap (in the role of Derek Smalls, the one with the incredible sideburns/mustasche combo) gives us this weekly glimpse into the news, focusing on politics and entertainment, rounded off with a bit of sketch comedy. Satirical, insightful, almost always funny.
This American Life

Each week, This American Life picks a topic, and presents a handful of segments about it using interviews, short-story readings, or other forms of audio journalism. No matter what the subject matter, it always feels like an hour well-spent. Chicago Public Radio produces this (mostly-)weekly show.
Undercover Songs

This is one of the very first podcasts I ever subscribed to. Nuno Nunes presents a handful of covers, songs performed by someone other than the original artists. This is huge fun! Although the frequency of updates has declined steadily—first weekly, then bi-weekly, now basically bi-annually—the content is great, and you will always hear something new and unexpected.
Savage Love

Many people have seen Dan Savage's Savage Love advice column in the alternative press; I read it for years in one of the Minneapolis/StPaul free papers before moving to Sweden. Fortunately Dan has embraced this new digital age, and now offers a phone number where people can call in and record their questions, and he offers them advice, sometimes calling them back to get more info. Though the vast majority of the callers have problems and concerns far from my own life, it's pretty interesting to hear the concerns of bisexual grammar fetishists living in poly relationships with jesus freaks. If this sounds vaguely Jerry Springer-esque, don't worry, it's not.
Well, that'll do for now. If anyone else feels like sharing, don't forget to use the comments, now less-broken than they've been in months!
permalink | digg this | slashdot this | add to del.icio.us | 0 comments (why don't you write the first?)

Defective C++

posted by jack at 11:12 CET in / compute / programming feed

At my previous job, I worked as a C++ programmer. The job, which started out primarily working with Objective-C and Objective-C++ to port a Windows application to Mac OS X, became progressively more a C++ job as time went on. I came to learn C++ fairly well, just enough to realize how much I dislike it. I haven't properly been able to summarize just why I dislike C++ so much, but fortunately someone else has: The Defective C++ page, part of the larger "C++ FQA", lays bare a number of problems inherent to the design of the C++ language.

In less than two years of C++ usage, I encountered nearly every one of these problems. Some of them can be dealt with by deciding upon and following "best practices" within the team, which we did (to give credit where credit is due, the more experienced C++ developers I was working with pretty much laid out the best practices for the rest of us to follow), but some of them are just things that you pretty much have to live with, and end up turning the development process into a real straightjacket.

(via Another Day in the Code Mines, which had picked it up from a discussion at Joel On Software; check out the comments in that discussion if you want to see some extremely blindered C++ apologists in action...)

permalink | digg this | slashdot this | add to del.icio.us | 0 comments (why don't you write the first?)

Ruby metaprogramming: Not scary at all

posted by jack at 13:17 CET in / compute / rails feed

There seems to be a sort of mystique around the concept of metaprogramming, but in Ruby it's really not mystical at all. It's all about leveraging a few existing methods in smart ways to let you eliminate boring code. This sort of thing is possible in my "native language" of Objective-C, but in Ruby it turns out to be even easier.

Today I'm going to talk about how to use the method_missing method to eliminate repetitive boilerplate code. method_missing is Ruby's fallback strategy for unresolvable method names encountered at runtime. If you try to call a non-existent method on any object, the Ruby runtime will instead call method_missing on that object; The default behavior of this method is to raise an exception, but we can override it to do smart things based on the method name.

The Badness

The Rails application I'm working on has a role-based permissions scheme, with a ManagementRole model that sits between User and Program models, allowing us to define roles that a User can have relative to a given Program, which in turn constrain what they're allowed to do with the application. These roles are expressed concretely as simple subclasses of ManagementRole, with names like RoleSearchMembers and RoleCreateMemberships. Up until recently, checking whether a User were allowed to perform certain tasks within a Program consisted of calling one of several nearly-identical class methods defined on ManagementRole, such as these:


  def self.allow_search_members?(user, program)
    return User.is_administrator?(user) ||
      self.program_role_exists?(user, program, "RoleSearchMembers")
  end
  
  def self.allow_create_memberships?(user, program)
    return User.is_administrator?(user) ||
      self.program_role_exists?(user, program, "RoleCreateMemberships")
  end

  # etc
  
  # the program_role_exists? method, not listed here, simply checks
  # for the existence of a matching ManagementRole object

As you can see, this is extremely repetitive, and adding new types of permissions means adding new, nearly-identical methods. As of now there are 18 methods like this, and that number will just go up in the future, leading to even more boilerplate code. Where will this madness end?

The Goodness

Providing a simple definition for method_missing in the same class lets me eliminate all those 18 methods, and will automatically deal with any new ManagementRole subclasses. It looks like this:


  # instead of a bunch of allow_xxx_xxx_xxx? methods that differ only slightly, 
  # we just catch all such calls here.
  def self.method_missing(method_id, *args)
    if match = /allow_([_a-zA-Z]\w*)\?/.match(method_id.to_s) and args.size==2
      return User.is_administrator?(args[0]) || 
        self.program_role_exists?(args[0], args[1], "Role#{match[1].camelize}")
    else
      super
    end
  end

The first thing this does is examine the method and the argument list, to determine if it looks like the kind of method we are trying to replace. If the method name looks anything like "allow_xxx_yyy_zzz?", and if there are exactly 2 arguments, then we'll do something interesting. Otherwise, we'll just call super and let the parent class deal with it.

In the "interesting" case, we simply perform the same checks we did before to determine whether we return true or false, but now we're using indexed values from the args array, and constructing the string naming the MangementRole subclass by using the result of the earlier regexp match. Voila!

The Even-Betterness

Of course, software development being what it is, any time you revisit an old design to try to improve it, the act of improving it can lead you to discover new, further improvements. While writing this, I realized something that would have avoided all this boilerplate code, and the metaprogramming it led to, in the first place: Instead of asking the ManagementRole class explicitly about each of these permissions, I'll be better off writing a single method called allow? in the ManagementRole class, which will do a lookup based on the recipient's class-name, e.g. RoleSearchMembers, RoleCreateMemberships. And then instead of calling ManagementRole.allow_search_members?(u,p) , I will call RoleSearchMembers.allow?(u,p). That will lead to even less code than the metaprogramming version, and less code is always better code. I haven't written it yet, but it'll probably look something like this:


  def self.allow?(user, program)
    return User.is_administrator?(user) ||
      self.find_by_user_and_program(user, program)
  end

So this problem, with its metaprogramming-to-the-rescue solution, turned out to be easily solvable with more traditional object-orientation, but that's OK! Hopefully this post will be helpful anyway, for someone else whose problem doesn't have the same easy solution that mine turned out to have...

permalink | digg this | slashdot this | add to del.icio.us | 0 comments (why don't you write the first?)



Looking for programming talent that doesn't make you say "WTF!"? Try the hidden network.