Archive for March, 2011

A genius called Richard Feynman

I finally got around to reading “Surely you’re joking, Mr Feynman”, a book that has been on my TODO list for years. And it was everything I was expecting, and so much more.

The book is a set of stories written by Feynman himself. There is no plot, no overall story, no particular point. Written by anyone else, it would be mind-numbingly boring, but Feynman is such an amazing character that every single thing he writes turns into an adventure and a lesson about life. I kept smiling and nodding all the time throughout the book and I found the irresistible urge to take notes. Next thing I know, I had two entire pages of quotes and notes about my reaction to Feynman’s adventures.

So I thought I would share some of my reactions to these stories.

Feynman has always had an interesting relationship with the army. When the war started, he felt it was his duty to do something for his country so he went to see a recruiting officer and asked him how he could help. He was told that all he could do was join boot camp and then be assigned somewhere. Disappointed, he went walking in a park to think and he finally came to the following conclusion:

To hell with it! I’ll wait awhile. Maybe something will happen where they can use me more effectively

A few years later, Feynman joined the Manhattan Project, which led to the creation of the first atomic bomb. His work in Los Alamos ended up being instrumental in ending World War II, so his hope that he would be able to help his country in some other way than going through boot camp turned out to be quite prophetic, indeed.

I have always had an absolute fascination for the Manhattan Project, and if anything, I am sad that Feynman didn’t dedicate more time telling stories about his time there. He started as a pretty low grade physicist but he quickly got promoted and he ended up becoming a key scientist to the entire effort whose mastery of physics and powers of listening gained him a universal respect among his peers. When he joined, he reported to a physicist called Hans Bethe, and together, they came up with the Bethe-Feynman formula (obviously), which calculates the yield of a nuclear explosion.

I found this quite interesting and I tried to get a look at this equation, but I came up completely empty. Google, Wikipedia, Wolfram Alpha all seem to know a bit about the formula but they never show it. I had to pay close attention to an interview of Bethe to find out why: the formula is classified, and it continues to be today. Bethe has this to say about his invention with Feynman:

We extended Serber’s formula for the yield of a nuclear weapon, and there is the Bethe-Feynman formula, which I think is still secret and has worked very well.

I didn’t even think it was possible to have a fundamental scientific finding classified, but such is the case for this formula, which has probably been deemed too dangerous to be placed in everybody’s hands. I am guessing that all the countries that joined the US in the atomic club in the following years (Russia in 1949, the UK in 1952, France in 1960) have probably had to discover this formula on their own.

Feynman has another funny story about the secrecy that surrounded the Los Alamos camp and the project that was going to take place there. This happened in the early days, as he was planning his move from Princeton to New Mexico:

We were told to be very careful – not to buy our train ticket in Princeton, for example, because Princeton was a very small station, and if everybody bought train tickets to Albuquerque, New Mexico, in Princeton, there would be some suspicions that something was up. And so everybody bought their tickets somewhere else, except me, because I figured if everybody bought their tickets somewhere else…

So when I went to the train station and said,

“I want to go to Albuquerque, New Mexico”.

The man says:

“Oh, so all this stuff is for you!”

We had been shipping out crates full of counters for weeks and expecting that they didn’t notice the address was Albuquerque. So at least I explained why it was that we were shipping all those crates: I was going out to Albuquerque!

So much for secrecy…

Accomodations in Los Alamos were pretty sparse, but as the project started gaining momentum, they received increased amounts of machines, material, various devices, and even computers (this was in the early 1940′s). Feynman would later gain some interest into computers (he became fairly involved with a computer known as the Connection Machine) but even in these early days, he captured a very accurate truth about computers:

Well, Mr. Frankel, who started this program, began to suffer from the computer disease that anybody who works with computers now knows about. It’s a very serious disease and it interferes completely with your work. The trouble with computers is you play with them.

Surely, all the computer scientists of the world can relate to that…

Here is another paragraph that got a “Uh… what?!?” from me when I read it:

It looked as if something might happen at any minute, so I arranged ahead of time with a friend of mine in the dormitory to borrow his car in an emergency so I could get to Albuquerque quickly. His name was Klaus Fuchs. He was the spy, and he used his automobile to take the atomic secrets away from Los Alamos down to Santa Fe. But nobody knew that.

Yikes! There was a spy in Los Alamos. I never knew that, and I wish Feynman had expanded a bit more about his interaction with this person. As it turns out, Fuchs’ work helped create the atomic bomb but his later work was also used in the creation of the first hydrogen bomb. He confessed to being a spy in 1950 and he was subsequently arrested and charged with espionage.

The most riveting part of Feynman’s recollection of his time at Los Alamos is his account of the test of the bomb (the very first time an atomic bomb exploded on our planet):

They gave out dark glasses that you could watch it with. Dark glasses! Twenty miles away, you couldn’t see a damn thing through dark glasses. So I figured the only thing that could really hurt your eyes (bright light can never hurt your eyes) is ultraviolet light. I got behind a truck windshield, because the ultraviolet can’t go through glass, so that would be safe, and so I could see the damn thing.

Time comes, and this tremendous flash out there is so bright that I duck, and I see this purple splotch on the floor of the truck. I said, “That’s not it. That’s an after-image.” So I look back up, and I see this white light changing into yellow and then into orange. Clouds form and disappear again – from the compression and expansion of the shock wave.

Finally, a big ball of orange, the center that was so bright, becomes a ball of orange that starts to rise and billow a little bit and get a little black around the edges, and then you see it’s a big ball of smoke with flashes on the inside, with the heat of the fire going outwards.

All this took about one minute. It was a series from bright to dark, and I had seen it. I am about the only guy who actually looked at the damn thing – the first Trinity test. Everybody else had dark glasses, and the people at six miles couldn’t see it because they were all told to lie on the floor. I’m probably the only guy who saw it with the human eye.

Finally, after about a minute and a half, there’s suddenly a tremendous noise – BANG, and then a rumble, like thunder – and that’s what convinced me. Nobody had said a word during this whole thing. We were all just watching quietly. But this sound released everybody – released me particularly because the solidity of the sound at that distance meant that it had really worked.

The man standing next to me said, “What’s that?”

“That was the Bomb.”

This is just a tiny fraction of what Feynman has to say in this first account of his life (he wrote a few more story books, follow the Amazon link at the top for more details). One of the most amazing things to me while reading these stories was the tone that Feyman used. It’s filled with candor and sometimes even naïveté. For someone who is probably one of the most brilliant minds that ever lived, Feynman is consistently showing a remarkable lack of assurance and self confidence. He never thinks he’s good enough and he often turned down offers to speak or very highly compensated positions just because he thought he didn’t deserve these opportunities.

This is the testimony of a scientific mind in its rawest form, an intellect that doesn’t care much about influence, etiquette, politics or seeking favors. If it’s not scientifically accurate, it’s worthless, and this sheer honesty and absolute dedication to the scientific truth is what made Feynman one of the most brilliant minds of the century.

But it’s not just that: Feynman’s interest and curiosity for life knew no bounds and his forays into biology, drumming, painting and foreign languages (unsurprisingly, he became very good in all these areas) contribute to making his life an absolutely riveting read.

Hopefully, these excerpts whetted your appetite and you will want to find out more about this exceptional man.

Never get lost in Eclipse again!

Whether you are an Eclipse veteran or beginner, there will be times when you want to access a certain functionality but you can’t remember exactly where to find it.

This is where Control-3 (or ⌘-3 on Mac) comes in handy.

For example, if I want to modify the Java formatting options, I press this combination and then the first letters of “formatter:”

As you can see, every single functionality in Eclipse that contains the letters “formatt” is displayed, and the one I’m looking for is displayed at the bottom. I select it, and:

Remember this shortcut next time you get lost in Eclipse!

Announcing TestNG 6.0

I’m happy to announce the release of TestNG 6.0. A lot of changes have gone into this release, which have slowly accumulated in the 5.14 line over the past few months. I’ll go over the most important features and bug fixes in this entry and I’m including the full change log at the bottom of this post.

If I had to pick the most prominent features for TestNG 6.0, they would be:

  • YAML.
  • Guice.
  • Improvements to the Eclipse plug-in.

YAML

As most of you know, TestNG uses an XML file to capture the entire description of your test suite, and while I think the schema for this file has managed to remain fairly simple over the years, the XML aspect of it can sometimes get in the way of making quick changes. I considered supporting an additional format for a while and I ended up narrowing my choices down to JSON and YAML. In the end, YAML won on tiny details such as not requiring the constant use of double quotes and the fact that JSON seems to be more optimized for computer than human consumption. Here is a short TestNG YAML example:

name: SingleSuite
threadCount: 4
parameters: { n: 42 }

tests:
  - name: Regression2
    parameters: { count: 10 }
    excludedGroups: [ broken ]
    classes:
      - test.listeners.ResultEndMillisTest
      - test.listeners.TimeOutTest

Unfortunately, YAML and JSON don’t have as much tooling support as XML especially when it comes to editing and validation, but one thing that I liked in YAML is that it’s much more “copy/paste friendly” than XML. In XML, it’s rarely possible to just cut a line and paste it somewhere else in the file: you usually end up having to add surrounding tags or move closing tags. In YAML, you can usually just cut/paste lines right away. It’s also much easier to comment out regions than XML’s awkward “<!--” and “-->” delimiters.

I discussed my choice of YAML in this blog entry, and here is the official TestNG documentation.

Guice

From the very early days (around 2006), TestNG has made it possible for users to take control of the instantiation of their test classes thanks to the very useful IObjectFactory interface. Developers in need of creating the instances of their test classes themselves in order to prepopulate them could use this factory to perform whatever operations they needed and then return these instances back to TestNG, which would then use these to run the tests.

The release of Guice made this interface even more useful: instead of instantiating their test objects, users were now able to simply ask Guice to hand them a fully injected instance. This worked great but considering the number of discussions and requests that we received on the mailing-list on this topic, I started wondering if we couldn’t provide an even better way to support Guice directly with TestNG.

A few hours later, TestNG’s official Guice support was born:

@Guice(modules = GuiceExampleModule.class)
public class GuiceTest {

  @Inject
  ISingleton m_singleton;

  @Test
  public void singletonShouldWork() {
    m_singleton.doSomething();
  }

}

In this example, TestNG will use the GuiceExampleModule module to retrieve an instance of the GuiceTest class and then use that instance to run the tests.

You no longer need to use the object factory, you can now directly tell TestNG which Guice module(s) should be used to create the instance of a given test. Here is the original blog post that started the discussion (note that the syntax changed slightly since then) and the direct link to the documentation.

Improved Eclipse plug-in

I have been adding a lot of features to the Eclipse plug-ins over the past months, among which:

  • A summary tab that allows you to browse the results very easily (shown partially above).
  • A search functionality for whenever you need to look for the result of a specific test among hundreds.
  • Vastly improved automatic conversions from JUnit 3 and JUnit 4 to TestNG.
  • A revamped display view that matches the testng.xml format more closely.

Here is a quick rundown of the latest features and the full documentation.

Miscellaneous

These are the big items, here is the full change log, along with the contributors:

Core

  • Added: @Guice(moduleFactory) and IModuleFactory
  • Added: @Guice(module)
  • Added: timeOut for configuration methods
  • Added: -randomizesuites (Nalin Makar)
  • Added: IConfigurable
  • Fixed: @Test(priority) was not being honored in parallel mode
  • Fixed: @Test(timeOut) was causing threadPoolSize to be ignored
  • Fixed: TESTNG-468: Listeners defined in suite XML file are ignored (Michael Benz)
  • Fixed: TESTNG-465: Guice modules are bound individually to an injector meaning that multiple modules can’t be effectively used (Danny Thomas)
  • Fixed: Method selectors from suites were not properly initialized (toddq)
  • Fixed: Throw an error when two data providers have the same name
  • Fixed: Better handling of classes that don’t have any TestNG annotations
  • Fixed: XmlTest#toXml wasn’t displaying the thread-count attribute
  • Fixed: TESTNG-415: Regression in 5.14.1: JUnit Test Execution no longer working
  • Fixed: TESTNG-436: Deep Map comparison for assertEquals() (Nikolay Metchev)
  • Fixed: Skipped tests were not always counted.
  • Fixed: test listeners that throw were not reporting correctly (ansgarkonermann)
  • Fixed: wasn’t working.
  • Fixed: In parallel “methods” mode, method interceptors that remove methods would cause a lock up
  • Fixed: EmailableReporter now sorts methods chronologically
  • Fixed: TESTNG-411: Throw exception on mismatch of parameter values (via DP and/or Inject) and test parameters
  • Fixed: IDEA-59073: exceptions that don’t match don’t have stack trace printed in console (Anna Kozlova)
  • Fixed: IDEA’s plug-in was not honoring ITest (fixed in TestResultMessage)
  • Fixed: Methods depending on a group they belong were skipped instead of throwing a cycle exception
  • Fixed: TESTNG-401: ClassCastException when using a listener from Maven
  • Fixed: TESTNG-186: Rename IWorkerApadter to IWorkerAdapter (Tomás Pollak)
  • Fixed: TESTNG-415: Assert.assertEquals() for sets and maps fails with ‘null’ as arguments
  • Fixed: typo -testRunFactory
  • Fixed: NPE while printing results for an empty suite (Nalin Makar)
  • Fixed: Invoke IInvokedMethodListener.afterInvocation after fixing results for tests expecting exceptions (Nalin Makar)
  • Fixed: TESTNG-441: NPE in SuiteHTMLReporter#generateMethodsChronologically caused by a race condition (Slawomir Ginter)

Eclipse

  • Added: Convert to YAML
  • Added: New global preference: JVM args
  • Added: Eclipse can now monitor a test-output/ directory and update the view when a new result is created
  • Added: Right clicking on a class/package/project now offers a menu “TestNG/Convert to TestNG”
  • Added: Excluded methods are now listed in the Summary tab
  • Added: “Description” column in the excluded methods table
  • Added: Dialog box when the plug-in can’t contact RemoteTestNG
  • Added: Double clicking on an excluded method in the Summary tab will take you to its definition
  • Added: If you select a package before invoking the “New TestNG class” wizard, the source and package text boxes will be auto-filled
  • Added: When an item is selected in a tab, the same item will be selected when switching tabs
  • Added: A new “Summary” tab that allows the user to see a summary of the tests, sort them by time, name, etc…
  • Added: It’s now possible “Run/Debug As” with a right click from pretty much any element that makes sense in the tree.
  • Added: JUnit conversion: correctly replaces assertNull and assertNotNull
  • Added: JUnit conversion: removes super.setUp() and super.tearDown()
  • Added: JUnit conversion: removes @Override
  • Added: JUnit conversion: replaces @Test(timeout) with @Test(timeOut) (5.14.2.4)
  • Added: JUnit conversion: replaces @Test(expected) with @Test(expectedExceptions) (5.14.2.4)
  • Added: JUnit conversion: replaces fail() with AssertJUnit.fail() (5.14.2.2)
  • Added: JUnit conversion: replaces Assert with AssertJUnit (5.14.2.1)
  • Added: The progress bar is now orange if the suite contained skipped tests and no failures
  • Added: Skipped test and suite icons are now orange (previously: blue)
  • Added: New method shortcuts: “Alt+Shift+X N”, “Alt+Shift+D N” (Sven Johansson)
  • Added: “Create TestNG class” context menu
  • Added: When generating a new class, handle overridden methods by generating mangled test method names
  • Fixed: Green nodes could override red parent nodes back to green
  • Fixed: Was trying to load the classes found in the XML template file
  • Fixed: Stack traces of skipped tests were not showing in the Exception view
  • Fixed: XML files should be run in place and not copied.
  • Fixed: NPE when you select a passed test and click on the Compare Result icon (Mohamed Mansour)
  • Fixed: When the run is over, the plug-in will no longer force the focus back to the Console view
  • Fixed: The counter in the progress bar sometimes went over the total number of test methods (5.14.2.9)
  • Fixed: org.eclipse.ui.internal.ErrorViewPart cannot be cast to org.testng.eclipse.ui.TestRunnerViewPart (5.14.2.9)
  • Fixed: Workspace preferences now offer the “XML template” option as well as the project specific preferences (Asiel Brumfield)
  • Fixed: TESTNG-418: Only last suite-file in testng.xml run by Eclipse plugin

Documentation

  • Added: Section on Selenium (Felipe Knorr Kuhn)
  • Added: Link to an article on TestNG, Mockito and Emma in the Misc section

Upgrading to TestNG 6.0

Ant users can download TestNG 6.0 directly from the web site while Maven users only need to specify the following dependency:

    
      org.testng
      testng
      6.0
    

Don’t forget to update your Eclipse plug-in as well.

Rehabilitating the singleton pattern

“Design Patterns: Elements of Reusable Object-Oriented Software” came out in 1994 and it changed the software engineering landscape. What made this book unique is that it wasn’t really based on code (although it did contain a decent amount of it) but on terminology. It picked up general ideas and concepts, captured them in diagrams and, most importantly, gave them a name.

The power of names

Nobody had really thought about doing that before, and the idea was so good that even today, fifteen years later, most of these names are still in common use. You won’t come across a developer who has never heard about Singleton, a Visitor, a Factory or a Façade.

Of course, the science of software engineering has advanced quite a bit since 1994, and some of the concepts explained in the book came under attack. For example, we know a lot more about testing now, and this past decade has allowed us to identify techniques that make testing easier, and also anti-patterns that tend to get in the way of making our code testable.

Of all the design patterns from the book that have been criticized, none has taken as much of a beating as the Singleton. Not a day goes by without reading in blogs or irc that “Singletons are evil” and that you should avoid them at all costs. What’s surprising is that I read this coming from senior developers, and this statement tends to deeply puzzle more junior developers who suddenly find themselves having to rewrite a piece of code that they thought was quite natural and officially acknowledged as a good coding practice.

Here is the truth:

Singletons are fine as long as you don’t implement them with static

Scoping it out

Let’s take a closer look at this statement.

Singletons are very natural entities in a software engineering. Regardless of the kind of code you write (front end, back end, embedded in a browser, running in a container, etc…), you will most likely need to talk to certain services that only need to exist as a single instance. It’s also no surprise that popular dependency injection frameworks such as Guice and Spring explicitly support the Singleton pattern.

Don’t feel bad for feeling the need to implement a certain concept as a Singleton, it’s perfectly natural.

So what’s wrong with statics?

There is ample documentation on the problems that static variables and methods (but mostly variables) cause, but in nutshell, they make testing and concurrency more challenging, and as such, they should be avoided. The main problem is that static defines a scope that’s even bigger than the application itself. It’s a state that will only disappear once the class that contains it gets unloaded, so frameworks have very little room to control its life cycle. Another way to look at it is that the static scope is beyond the reach of Java programs and lives in the realm of the JVM.

This is really the only problem. If we can find ways to have singletons that are more narrowly scoped, then the concerns I mentioned above disappear.

The next smaller scope to the one that static provides is instance: the value will remain live as long as someone is holding on to a reference to the object, but once that is no longer the case, this value is gone.

One way to improve on the static scope would be to create all your singletons in your main method and then pass them down to your application. With this change alone, you have suddenly made your entire application much easier to test and easier to reason about from a concurrent stand point.

Once you start going down that path, you start wondering if this “main” scope isn’t too broad. If a singleton you create in your main method is not needed until way further down the stack frames, maybe there is no point in exposing that singleton to your entire application. Is there any way that you could either create (ideal case) or at least expose (second best case) that singleton only to the section of your code that needs it?

This code structure also rises another question: it’s not exactly convenient to create a bunch of singletons in your main method and then pass them “down”. How do you do that, anyway? Ideally, you pass them as parameters to the methods you are calling, but that is not going to scale very well, never mind the fact that your method signatures are going to start looking like monsters. Updating your entire call chain whenever you need access to a new singleton is an absolute disaster since you will have to add this parameter to the signature of each method.

One way to mitigate this problem is to group all your singletons in one class called, say, Configuration, and only pass that class around. If ever you need one more singleton down the road, you just add it to this class and you don’t need to change any method signature. That’s better.

We are still exposing a lot of code to all these singletons, though, and even that uber Configuration parameter looks like extra weight on these methods (most of which might just pass them around and not even use them).

Injecting for fun and profit

This is where the @Inject annotation comes in. Initially popularized by Guice, this annotation ended up being promoted to a standard by JSR 330: “Dependency injection for Java“. I’m not going to go into details on how to use this annotation (check out Guice’s excellent documentation), but I’ll just limit my comments to the topic of this post, which is how to implement singletons properly.

Using @Inject to gain access to your singletons solves the following problems:

  • No static.
  • The creation of the singleton is externalized. You don’t need to worry how or where that singleton is created, you just need to specify that you need it.
  • Finer scope. Only the class that you declare this injected field in will have access to that singleton. A side benefit of this is that you no longer need to pollute all your method signatures in order to pass this singleton all the way down the stack frames. It’s declared as a field and the dependency injection will automatically assign it at start up time.
  • Finer granularity. You no longer need to pass a monster Configuration object that contains all your singletons around: just specify which singletons you need exactly.

This post is getting a bit long already so I’ll stop for now. There is much more to cover on the subject of singletons and, more broadly, of dependency injection, which I’ll try to cover in a future post.

In the meantime, let’s all agree to acknowledge that when implemented and used properly, the Singleton is a very useful design pattern.

Rethinking scrollbars

The next version of GNOME will be removing the Minimize and Maximize buttons from their its window manager. Needless to say, this is a very controversial decision and the justifications for it look fairly weak to me.

Digging a little bit into this curious decision, Mark Derricutt pointed me to another upcoming UI change in Unity: a brand new style of scrollbars. This is explained in more details in this post on Mark Shuttleworth’s blog. Take a look at the short video for a quick overview of how they work (I noticed a bug at around 33 seconds: when the cursor scrolls the front window horizontally, the window in the back scrolls horizontally as well. What I find really interesting about this bug is that I have noticed Mac OS showing the same behavior sporadically, especially when I use the double finger gesture on my trackpad).


Side note: scrolling on Mac OS is one of the two UI functions that violate the “no click through” behavior. Do you know the other one? It’s the act of closing a window: you can close a background window by clicking on its red icon without needing to bring it to the front first.

Going back to the Unity video, I think this new design for scrollbars works well. I also notice that the hit box for the scrollbar is bigger than the thumb, which is a very good idea (one that I haven’t seen in any other OS). After all, when you click in the vicinity of the thumb in a scrollbar, what are the odds that you are not trying to grab the scrollbar?

The new design might be a bit confusing at first, but I think discoverability and learnability will be very good. Same observation for the arrows on each side of the thumb, which make more sense than having them at the ends of the container.

So the new scrollbars look good, but I predict that the removal of the Minimize and Maximize buttons will be a disaster, and that they might reverse this decision before GNOME 3 comes out, or maybe make it configurable.

And you know why I think that? Because the person doing the scrollbar video uses the Minimize widget all the time.

Maybe the GNOME UI team should take that as a hint.

Fantom and user defined generics

My post from last week generated some interesting discussions and reactions, but one in particularly grabbed my attention.

Both Stephen Haberman and Tom Davies made the following observation:

As far as Fantom is concerned, I doubt the successor of Java will lack user defined generics. That’s like going back to Java 1.4.

This got me to think. If I were to pick a different language than Java, would I be willing to give up user defined generics? Here is my answer:

That’s a fair point.

Personally, I wouldn’t mind trading user defined generics if I get in return type inference, closures, traits, properties, actors, .net support and Javascript generation.

And user defined generics are on Fantom’s road map, but I wouldn’t expect them for at least one or two years.

Switching to a new language always comes with compromises, no matter how superior you think that new language is. Even if it beats your current language on every point, you should expect to lose some productivity because of lacks in other areas, such as tools, support, documentation, community, compiler bugs, etc…

Fantom is no exception, and actually, due to the very design goals and Andy and Brian set for themselves when they created it, Fantom made some tough compromises in order to keep the language manageable. And user defined generics are one of the casualties.

Note that Fantom supports implicit casting, which contributes to cutting down the verbosity of the code when you are dealing with raw user types, but obviously, this doesn’t buy you any safety compared to user defined generics.

By the way, as the name implies, “user defined generics” means that Fantom does support some limited form of genericity: only List, Map and Func are generic. Therefore, your collections remain typed but you no longer have the option to create your own class Node<T>.

Is it a big deal?

I would miss them, because I do use them. A quick look at the TestNG code base shows about twenty generic classes out of nine hundred. That’s less than 2%, and TestNG is a framework that exposes a substantial API. But there is no question that these classes increase the robustness of the API and of the client code that uses it.

However, I feel that I would use the other features that I would gain from Fantom a lot more, especially properties and closures. I wouldn’t be surprised to find out that I could use at least one of these features in all the nine hundred classes. That’s a lot of benefit right there.

How about you? If you had to drop one feature from the following list:

  • User defined generics
  • Type inference
  • Closures
  • Traits
  • Properties
  • Actors
  • .net support
  • Javascript generation.

Which one would you do without?

Neat Windows 7 feature

This is what pops up when I hover (yes, hover) on the Windows Media Player icon in the task bar. I knew that applications could create jump lists with customized content, but I didn’t realize how far you can go with this feature, nor that these lists can appear on a hover. It’s really a great way to manipulate your player with the mouse. Let’s hope Mac OS learns something from it.

Sadly, it’s probably the only positive thing I can say about Windows Media Player, its non-standard user interface continues to bug me to no end and not a day goes by where I’m not wasting time trying to do something that should take just one click.