if ( document.comments_form.url ) { document.comments_form.url.value = getCookie("mtcmthome"); } Otaku, Cedric's weblog: November 2005 Archives

November 26, 2005

Would you like spyware with that?

I don't get irritated easily but I have observed a growing trend recently that is driving me absolutely nuts:  upgrade nags.

Well, to be precise:  upgrade nags without any possibility to turn them off.

You know, these dialog boxes that pop up whenever you launch the application and that let you know that a new version of the application is available.  The arrogance of the authors of these programs is absolutely baffling, and they should know by now that you don't get mindshare by forcing products down users' throats.

Here are the worst offenders as of today:

  • Yahoo Messenger.  It didn't used to be the case, but their recent "Yahoo Messenger with Voice" is obviously so important to them that they absolutely want you to install it, whether you have a microphone or not (or whether you want it or not).  Look, Yahoo, I like your client and you are welcome to let me know a new version is available, but how about a checkbox to allow me to pass on this great offer, uh?  Because right now, I am migrating away from Yahoo Messenger and urging my friends to do the same.
     
  • Acrobat Reader.  A veteran in the art of irritating users, and it's only getting worse as time goes by.  The most disturbing part is that the recent versions are actually worse than the previous ones:  longer start-up (do I really need all these plug-ins?  And why would I care about all these patents you filed?), pathetic scrolling and window management, miserably slow searching.  They must have seen that their users were reluctant upgrading, so they found the best way to make you:  a forced upgrade nag.  Keep up the good work, guys. 

  • iTunes.  Probably the worst offender.  Why?  Because it suffers from the same problems as Acrobat Reader plus the fact that every new version seems to restrict your rights on your own songs further.  When you upgrade iTunes, you can never really be sure that your iPod is not going to be wiped clean of songs or whether some of the songs you didn't buy through the iTunes store won't mysteriously stop playing.  Of course, it doesn't exactly help either that the Apple forums opted out of Google, so searching for answers to your iPod problems will typically not yield anything. And finally, here is the latest offense to date.

Any other?

Posted by cedric at 01:39 PM | Comments (24)

November 23, 2005

World of Warcraft Methadone

Ever since I started playing World of Warcraft some ten months ago, I have been hoping for the addiction to end.  It's a bit ironic to enjoy something so much that you actually want to get off it so you can return to a more balanced life, but it's really how I've been feeling these past weeks.  Not that my life hasn't been balanced:  I think I did pretty well, especially compared to some of my guild mates who routinely spend twelve hours in a row playing the game without any bios (warcraftese for "a break dictated by a biological necessity:  food, bathroom, etc...").

Well, I think that time has finally come.  I can proudly announce that "I am over World of Warcraft".

Let me explain how I got there.

I have to hand it off to Blizzard for creating a game that is equally fascinating "in the middle" (levels 1-59) as it is "at the end" (level 60).  Keeping level 60 characters interested is no small feat, and you need to find ways to keep them entertained even though they no longer get any experience.  World of Warcraft does this by providing dungeons of incredible difficulty that can only be defeated by groups of 10, 20 and even 40 (all group members need to be level 60, of course).  As you can imagine, finding groups to enter such "instances" (the technical term for these dungeons) is not easy and even if you might be lucky and find yourself invited to a random pick-up party for the Molten Core (one of the hardest instances in the game), you probably don't want to join anyway because you really need to play these dungeons with people you know and trust.

What is the appeal of these instances?  Loot.  Very rare and overly powerful gear that will greatly enhance your character.  It's really the only reason why players enter these instances, which is a bit baffling to me (and probably one of the reasons why I am finally quitting).

A high-end instance is an intense experience.  Very intense.  Here are a few points:

  • You need to commit for four to five hours in a row.  Don't even think of quitting unless you have a replacement ready and that the class of your replacement is similar to yours (or close enough).  Parties for high instances need a very precise balance of various classes (warriors, mages, priests, etc...) and tilting this balance, especially in the middle of the instance, can prevent the party from finishing.
     
  • You need to be on TeamSpeak.  TeamSpeak is a central server that allow groups of people to communicate with their microphones and headsets.  You don't really need a microphone if you're not a leader, but being able to listen to the directions from your leaders and to the talks during the fights is absolutely essential.  Regular chats are not fast enough and very easy to miss in the heat of combat.  I expected a lot of chaos on this channel, but all the players of my guild turned out to be very disciplined and they do not talk unless absolutely necessary.  It was my first experience of a video game leveraging audio and I was quite surprised by how well it worked out.
     
  • A high instance has several "bosses" (featured above is Ragnaros, the final boss of the Molten Core, and you're not even sure that you'll be able to summon him every time) and the preparation to fight each of them can take easily twenty to thirty minutes.  I'm not even talking about the fight itself, which can also be very long, but just the planning and the directions from your leader instructing various groups where to stand, where to go depending on how the fight turns, explaining various tactics, describing how the boss works and what attacks to expect from it, telling you which spells and moves to use which which ones to avoid, sharing "buffs" (protective spells that players cast on each other), etc...  By the time the fight is about to begin, your head is literally buzzing with the information overload, but now is certainly not the time to lose your focus because the real work is just about to begin.
     
  • Depending how well you do and how disciplined the party is, the boss will finally drop, possibly after a few "wipes" (the entire party decimated) followed by a long session of resurrections to bring everyone back.  When the boss is defeated, it's time to uncover the loot and decide who gets it.  That's right.  Each boss typically drops three or four items maximum, and since you have forty players, not everybody is guaranteed to get an item on a run.  So how do you decide who gets what?  There are various systems in place, the most popular one being DKP (Dungeon/Dragon Kill Points).  I won't go into detail on how this system works, but suffice to say it involves keeping track of who has gone to what raid, and what dropped during these raids.  It's a fair system that guarantees that the more raids you participate in, the more likely you become eligible for a rare item.  If you are curious, here is a typical DKP standings page.

With all that in mind, it should be no surprise to you that a high instance raid is an intense experience that will leave you sweating.  But boy!  What a rush!

I went on a few of those runs after finally deciding that the amount of involvement versus the feeling of reward was no longer high enough for me.  It was one of the most immersive experiences in a video game I have ever had (which is no small feat in a career of almost thirty years playing videogames), but the time has come for me to move on.

So I am now looking for my new addiction, and the winner is...

Ah...  Civilization...  my old Nemesis.

I've only been playing for a week so it's still a bit early to tell if Civilization 4 will deliver.  All I can say for now is that the ramp up is pretty tough, especially for a Civilization I veteran such as myself.  But I'm going to give it a fair chance, even if coming right after World of Warcraft is certainly a challenge.

So here's to a fond goodbye to World of Warcraft and the dawning of a new Golden Age (ah... already using Civilization lingo).

 

Posted by cedric at 11:21 AM | Comments (33)

November 20, 2005

The cost of fun

In a recent game review, PC Gamer mentioned that Quake IV, which was released recently, can be completed in about ten hours.  Ten hours.

This made me think.

I must have spent easily that much in my first week of World of Warcraft.  And probably just as much in all the weeks following, for a period of several months.  Which led me to wonder about the cost of entertainment, and how each type compares to each other.

Let's start with Quake IV.  Ten hours to complete it, maybe another ten hours to do it a second time (some people seem to do that) and maybe twenty hours playing on the multiplayer version, for a total of forty hours of fun.

World of Warcraft... well, it's actually fairly easy to quantify since the game keeps track of this for you.  Over a course of nine months, I built two character up to level 60 and each of them clocked in at over twenty days of playing.  That's twenty days of effective play -- 480 hours -- and let's add a few hours spent on a few other characters to round it up to about 1000 hours total.

Here is a quick breakdown:

Name Upfront cost Cost per hour Explanation
World of Warcraft $50 + $15 / month = $185 18.5 cents per hour $185 / 1000
Quake IV $50 $1.02 per hour $50 / 40 hours
TV Show $30 per month (basic cable subscription) $2.70 per hour $30 / 12, assuming you watch 3 series, each showing 4 episodes per month
Movie (rental) $5 $1.7 per hour $5 / 3 hours (movie + extras)
Movie (theater) $10 $5 per hour $10 / 2 hours

Of course, there are plenty of other activities we could add, such as sport (mostly free:  basket, volleyball, etc...  and not so free:  golf, scuba diving, horse riding. etc...) and other ways to pass the time (hiking, walking, running, reading, etc...).

Another factor that we should probably add is the "intensity" of these activities.  Not all of them will enrapture you and isolate you from the real world with the same intensity, and you could probably say that World of Warcraft would score very high on that scale while hiking would not.

But the general idea is this:  World of Warcraft, and massively online games in general, have often been chastised for not only the monthly fee they charge but also for charging for the game in the first place.  In light of these numbers, one might actually wonder why they don't charge more...

 

Posted by cedric at 09:29 AM | Comments (24)

November 17, 2005

Annotations and Behavior-Driven Testing

I have been a long-time fan of annotations, and my devotion started with EJBGen (which was using JavaDoc annotations in 2001, imagine that!), followed by my involvement in JSR 175 and now, with TestNG.

Annotations make a lot of sense for a testing framework, but once in a while, I still hear a few people wondering if they are appropriate for this particular domain.  Not only do I have a few reasons to believe this, but interestingly, the latest emergence of something called Behavior-Driven Testing is making this point further.  Here's why.

JUnit requires your test methods to start with the word "test".  When you do this, you are actually adding information to your method, attaching the "metadata" (extra information) that it's not just a Java method:  it's a Java test method.  This is the very definition of "metadata":  data on top of existing data.  But what are you really trying to achieve?  You are flagging your method so that it can be found by JUnit.  If you think a little bit about it, this goal doesn't have much to do with the name of your method.

Here is another way of looking at it:  what if you are using a framework that, says, automatically generates RMI stubs for any methods that start with "remote".  How do you combine this with JUnit?  It's easy to see that this approach doesn't scale very far.

Recently, a practice called Behavior-Driven Testing (BDT) has received some publicity.  The idea is to use a different terminology for your tests, not only for your test method names, but also in the way you perform your assertions.  Here is an example:

public void testAccountIsEmpty() {
  assertEquals(m_account.size(), 0);

Which can be rewritten as:

public void accountShouldBeEmpty() {
  m_account.shouldEqual(0);

I'll save the discussion on the pros and cons of BDT for a future posting and observe that the idea of baking the "test" attribute into the method name breaks down for this approach, proving the point that the name of the method and what this method means to a particular framework are completely orthogonal ideas.

Of course, the corollary of this observation is that TestNG already supports BDT :-)

 

Posted by cedric at 08:00 AM | Comments (3)

November 15, 2005

Hani is in da JCP!

Congratulations to Hani for his election to the JCP!

Hani, do us all a favor and be to the JCP what Schwarzenegger is to California.

Mmmh...  maybe it's not that much of a compliment, but you get the idea.

 

Posted by cedric at 11:13 AM | Comments (3)

November 14, 2005

Westminster Abbey and a mocha

Buckingham Palace Westminster Abbey

I was in Paris and London this past week, here are a few random thoughts...

  • I tamed jet lag.  I have traveled internationally so many times that by now, I have it down to an art. Here are a few simple rules:

    * Start shifting your time before leaving your country.  Stay up late (very late) and don't sleep in too much.  Note that the point is not really to make yourself tired so you will sleep on the plane (which doesn't help at all with jet lag) but just to start adjusting to your new time in your own environment.

    * On your first day in the new country, don't nap, don't sit (especially on comfortable couches), and don't go to bed before 10pm.

    Also, try not to abuse coffee:  the more you confuse your stomach with unusual quantities of drinks and meals taken at odd times, the harder it will be for your body to get used to your new schedule.  Ideally, you simply want your metabolism to believe that instead of a 24-hour day, you are just going through a 33-hour day and that your sleep pattern doesn't need to be altered to handle it.

    That's it.  Follow these simple instructions and even a nine hour time difference will have absolutely no effect on your body.
     
  • I flew on one of Virgin Atlantic's latest aircrafts on the way back, and it featured the best entertainment system I have seen on an international flight by far:  about fifty movies to choose from, entire seasons of TV series, news, games, etc...  It's all there.  You can also pause, rewind and fast forward everything at leisure.  Absolutely fantastic if you're not the reading type on planes.
     
  • Cell phone interoperability has come a long way and works close to perfectly now.  My trusted 6630 (which took the pictures above) worked beautifully and never lost GSM connectivity.  I actually travel with two phones and interestingly, they picked two different roaming carriers while in France (Orange and Bouygtel).  This is quite puzzling since both are Cingular, but it was a good opportunity to experiment.  No surprise there:  both phone calls and SMS worked seamlessly, the only glitch being that one of the two carriers refused to give me caller ID.  Not a big deal.

    I also experimented with sending SMS messages back to the US and between England and France, and everything worked fine.  Better:  even EDGE performed beautifully and allowed me to connect to the Internet through the Bluetooth modem while riding the Eurostar on my way to London (except in the tunnel, of course, but my phone quickly regained coverage when we came out and latched on O2 on the British territory).

Maybe we really live in a connected world after all.
 

Posted by cedric at 06:07 AM | Comments (4)

November 10, 2005

The future of source files

I just finished reading a very interesting article by Gregory Wilson that covers many issues that I feel strongly about.  In a nutshell:

  • UNIX shells are a wonderful, albeit aging, invention.
  • COM is a very powerful framework that has enabled a formidable ecosystem of innovative technologies on the Windows platform.
  • No matter how hard we try, we don't seem to be able to solve problems in only one language.
  • Even worse, we are increasingly mixing different languages in one source file.

My first observation is that this article fails to mention MSH, Microsoft's next generation shell, which expands on the first two points by providing a type-safe shell that formalizes the data that is exchanged through connecting processes.  No more arcane and non-standard command-line switches, or hacks using regular expressions to parse the output of all these tools.  MSH is a fascinating tool and I'll save its description to a future entry.

Gregory Wilson also makes the point that in the future, languages will be stored internally in a neutral format and be shown to developers using their own preferences.

A few weeks ago, I started working on an Eclipse plug-in that would allow me to have properties in my Java files.  The following code:

private String m_name;

public String getName() {
  return m_name;
}

public void setName(String name) {
  m_name = name;
}

would appear in my editor as:

+ property String Name; ...

This line would be folded by default and would be replaced with the full declaration above if expanded.

How does this relate to the article above?  Quite directly:  with this plug-in, I am transforming the Java syntax into my own.  I am using the Java source as an internal format and using an IDE to present it to me in a form that I find easier to read.

It doesn't have to stop there.  Maybe you don't like Java's semi-colons and braces and you prefer Pythons' significant spaces instead:

if (m_suiteConfigurationFailed)
  result = false
else
   for(Object targetInstance : instances)
     m_method = new InvokedMethod(targetInstance
   result = true

As for Wilson's basic point and the idea that all the programs in the world can be expressed in XML and shown in a user-defined way, I am still very skeptical.  It's not so much about the read-only view but more about the way people write programs.  New languages keep being created on a weekly basis, and some of them bring new concepts with them, which won't be adequately captured by this universal XML format without modifying its semantic, which brings us back to square one:  representations that are incompatible with each other and programs that can only be read or saved with a specific version of the representational language.

Another problem with Wilson's approach is that developers spend a lot of time reading other people's code, which mandates the existence of a language that everybody understands.  The tricks described above do not alter the Java source, and the physical file can not only still be parsed and compiled by javac, it can also be understood by any Java developer.

But I believe there is some hope and some promise, and in the meantime, nothing stops us from taking baby steps toward this destination, such as the Property plug-in I described above.

How about you:  how would you like to see your Java programs represented?

 

Posted by cedric at 11:03 AM | Comments (23)

November 08, 2005

Podcast

My podcast with the JavaPosse is now available.

 

Posted by cedric at 07:19 AM | Comments (2)

November 05, 2005

C# 3.0 Score Card

To make good on my threat, here are a few thoughts on the C# 3.0 features that I find interesting, along with a grade and a few thoughts:

Implicitly typed local variables:    A

I have been asking for this feature in Java for years.

Why do I need to write:

Account a = new Account();
Employee e = (Employee) employees.get("John")

Instead of

a = new Account();
Employee e = employees.get("John")

Can't the compiler figure this out for me?  Of course, it can.

Generics solve the second case, but they add more type inference envy than ever:

List<Map<String, Name> employess = new ArrayList<Map<String, Name>>();

Surely we can do a bit better than that, right?

Well, that's exactly what type inference will bring you.  Combine strong typing with a strict application of the DRY principle and you get the best of both worlds.

Extension methods:    C

This feature lets you add methods to a class outside the definition of that class.  The syntax is a bit peculiar:  you add this to the first parameter of your method:

public static int ToInt32(this string s) {
  return Int32.Parse(s);
}

I prefer Ruby's syntax for this:

def string.toInt32()
  ...
end

Note that this feature doesn't break encapsulation:  extension methods don't have access to private fields or methods of the class they extend. 

As for the feature itself, I have to admit it frightens me somewhat (both in Ruby and C# 3.0) because it becomes really hard to know exactly the contract that classes abide by, and also where the extra definitions are coming from.  I have to admit that over the years, I have grown quite fond of Java's rigid "one public class per file" rule and I'm afraid that extension methods might resurrect the C++ header nightmares that haunted C++ programmers for decades. 

On the other hand, this kind of extensibility opens the door for some very interesting tricks, such as the ones used by Ruby on Rails to exercise its magic (more on that in another post).

Time will tell.

Lambda Expressions:    B+

I have no doubt that functional programmers are screaming in frustration to hear the term "lambda expression" hijacked to mean "closure".  Let's put the intellectual debate aside and observe that closures are extremely useful.  C# already had a head start over Java with delegates and is now pulling further ahead with closures.  Let's hope Java will follow suit.  The C# syntax is fairly straightforward:

(int x) => x + 1

defines a lambda expression that accepts an integer parameter and returns that parameter incremented by one.  You can then pass this lambda expression around as real object.  I am quite looking forward to using this feature more.

Query Expressions:    C-

This feature is also referred to as LINQ for "Language Integrated Query".  The idea is to allow a certain subset of relational language inside C#:

customers.
  Where(c => c.City == "London").
  SelectMany(c =>
      c.Orders.
      Where(o => o.OrderDate.Year == 2005).
      Select(o => new { c.Name, o.OrderID, o.Total })
  )

If we have learned anything from Java's struggle with object-relational mappers, it's that embedding SQL in your code is usually a bad idea, so I'm having a hard time seeing the point in furthering the practice by making it a syntactic part of it.  I am predicting a very grim future for this feature.

Object Initializers:    B+

This feature helps reduce the clutter of your classes by waiving the declaration of simple constructors:

public class Point
{
  int x; int y;

  public int X { get { return x; } set { x = value; } }
  public int Y { get { return y; } set { y = value; } }
}

Point p = new Point { X = 0, Y = 1 };

In this example, Point declares two properties but does not include any constructor that accepts either of these properties  Yet it is possible to create a Point object and to initialize these properties in one statement.  Quite a relief from the verbosity of this.name = name that plagues Java.  Notice also how well this feature plays out with C# properties (another top priority on my Java wish list).

Conclusion

There are so many new features in C# 3.0 that statistically, you are guaranteed to hate at least half of them.  Interestingly, feature excess has certainly not dampened the popularity of C++, quite the contrary, so if Microsoft can guarantee that C# 3.0 will be completely backward compatible with C# 2.0, I am predicting that it will have a great future.   And a lot of detractors.

 

Posted by cedric at 03:25 PM | Comments (20)