VendAsta Technology is an All You Can Eat Buffet.
This week marked my first week on a new project at VendAsta. For the past 7 years I’ve spent my professional life awash a sea of .NET technologies. Web? ASP.NET. Desktop? Win32 & WPF. SOA? SOAP & WCF. And so on and so forth. That all came to an end this past Monday when I transitioned away from our .NET project and started work (or training, rather) on our own spin up application.
Excited? Indeed. But that overhwelming sense of “oh man, what have I gotten myself into” has been red-lining for 5 days. Reason? I have literally a dozen technologies that I need to learn… and they’re adding all the time. Currently, this is the list of technologies I need to learn:
- Google App Engine
- BigTable (or is it DataStore now?)
- Django
- jQuery
- Python
- YUI (Yahoo! User Interface)
- FBML (Facebook Markup Language)
- Facebook API
- CSS (Yea, it’s been years and I can’t remember jack)
- OpenID
- OpenSocial
- FriendConnect
These are all technologies we are currently planning on using in our new application. The list may (and likely will) change during as the requirements change, but so far this is it. As I said, I’m pumped… but man… can I do it? Can I manage this curve? You know it. Can you? Would you like to find out?
You and all your mashups… like I’m afraid of you, Web 2.0!
The Fall of Rome: The Microsoft Way
Recently Guy Kelsey of VendAsta fame and fortune posted a brief, but thought provoking article about how our company is going through an iPhone Epidemic. At least I found it to be fairly thought provoking considering I’m one of the people that shelled out the cashola to buy one. I’ve always been a fan of smart phones, and for the most part I’ve been a Microsoft faithful (there was that brief moment back around 2000 though when I bought a HandSpring). I was loyal to Microsoft’s form factor because those devices supported Microsoft’s Compact Framework (a mobile version of their full-on .NET Framework) which allowed me to have programmatic fun-time if I ever wanted, in an environment that I was already familiar with.
However, there are 2 things that have changed for me over the past couple years.
- As I grow as a software developer I am becoming more and more interested in non-MS technologies, especially open source technologies. .NET isn’t satisfying me anymore and I want to grow, and as I grow I want to be challenged to apply the software engineering techniques that I’ve learned.
- It has become unbearably obvious that Microsoft couldn’t innovate itself out of a wet paper bag.
At the risk of sounding cliche, it was Apple that woke me up and gave me the motivation to try out some new things.
In 2003 I purchased my first Apple product – an iPod. It was the 3rd generation, 30GB, and I was smitten. It was beautiful. It felt like I had picked it off a tree. It reaked of techno-hipster, and it glowed when I touched it. The iPod quickly became an integral part of my life. I was a walking iPod commercial, never leaving the house without the 2 long, white plugs in my ears denoting that I was part of the exclusive club (with about a billion other people), and I frequently played air drums while iPodding.
About a year later my computer was hit 3 times with some pretty severe worms (the first time because I was unprotected, the subsequent two times occured immediately after the first post-install boot of my computer, while Windows was downloading the latest service packs). In a string for 4 letter words I vowed I would never boot XP again, and within 24 hours I had dropped 1,600$ on an Apple iBook G4. Again, I was smitten. The sleak design, the ease of use, the physical sense of touch. Again, the whole thing felt organic, it felt natural, it felt like an extension of my life. And it integrated seamlessly with my first love, the iPod. After that I went on a multi-year binge that consisted of me selling off old iPods, buying the new ones, purchasing the smaller iPods so I could exercise with something light weight, etc.
I upgraded my iBook G4′s Panther OS to Tiger, and was again falling in love with what Apple was doing. Spotlight, Dashboard, Automator. Awesome tools that improved how users interact with the file system on their computer. Tools which extended the computer’s processing from localized files and information to a fully internet-integrated device on which you could quickly and easily look up words in a dictionary, check the weather in any city you wanted, check movie times, etc. – all without opening a browser.
During this time Microsoft was busy busy busy, designing and developing their new operating system Windows Vista. Vista promised to have a lot of interesting features, including a new 3D rendered user interface (which ended up being horrible to use), something called “WinFS” (essentially a database layered overtop of NTFS technology that’s going on 1,000 years old and was eventually stripped), PC-to-PC Synchronization (also stripped before release) and more security (which was implemented by constantly nagging you to deny or confirm any action that happens on your computer, ever – unfortunately not stripped). 6 years later, when it was finally released, so many of Vista’s “killer” features had been stripped that Vista was essentially just a new user interface that took serious hardware to run… and it cost 500$ for the full version. 500$. For an operating system. Seriously. I’m not even making this up.
In 2007, when Microsoft finally crapped out Vista upon the masses (with a feature set still years behind what Tiger included in 2005), Apple rolled out another OS called Leopard. Leopard sported a lot of cool innovative (and usable) new features, including easy data backup with Time Machine, and the ability to easily install Windows on your Mac (along side Leopard), and 300 other new features. And it cost 129$. A quarter of what Microsoft wanted for its new flagship. Let me repeat that – better features, built on a better foundation, for a quarter of the price.
Now I don’t mean to ridicule Microsoft here, and dishing on them is not the intention of this article. What I wanted to outline, however, was that while other companies were actually innovating, Microsoft just put a bunch of new lipstick on an old pig and called it Vista. There was no innovation, and what little innovation that did exist within Vista was innovation that your average user could care less about.
Now this is nothing new. Micorosoft hasn’t been known for top notch innovation – for the most part they’ve bought out some other software company, re-packaged their products and sold them as a new MS product. This is fine from a business perspective, and it’s okay when you don’t have a whole lot of competition, but that strategy will no longer work for a number of reasons.
- Love’em or hate’em, Apple is pumping out innovative products that are sleak, sexy, easy to use, and that people want. The iPhone, Apple’s first shot at the “smartphone” market, is a shining example of something that absolutely destroys anything Microsoft has tried to do even with their most recent line of Pocket PC form factor and Windows Mobile 6.
- A huge portion of the most innovative software technologies are coming out of the open source movement. This is bad news for a company that traditinoally buys out competitors, because when it comes to open source, there’s nobody to buy out.
- Other big players have emerged to dominate the areas that Microsoft ignored for too long. Google has successfully organized the Internet and is now raking in billions as a result. But Google is much more than just search, they’re huge in the web based email market with their GMail platform (and much like the iPhone destroying the Pocket PC, GMail destroyed Hotmail), their increasing acceptance with their Google Docs (a web-based competitor to Microsoft Office which is free and, dare I say, better for the majority of what most people do with a word processor)… then there’s Google Calendar, Google Reader, Google Earth, Google Photos, Google Video… essentially 99% of what you used to do on your desktop can now be done online, through Google, using nothing but a Web Browser – which is OS agnostic.
- The Open Source Software movement is being used, and uplifted, by the world’s biggest companies including IBM, Apple, and Google – where as Microsoft is still wanting to go in alone. The name of the game in today’s technology world is co-operation, but Microsoft is stubbonrly refusing to shift its gears.
- With the emergence of Google, Apple, and some seriously killer open source software frameworks (such as Django and Rails, to name only a couple), Microsoft is no longer alone in providing great tools to build great software, and as a result, developers are losing interest and leaving.
It’s point 5 that describes where I and several of my colleagues sit. Microsoft is slow to adopt emerging technologies, and as such a large portion of their developers are slow to adopt those emerging technologies. If you want to stay current with emerging technology chances are you’re going to have to walk away from Microsoft’s core suite and move towards Open Source and those companies that support Open Source. And this spells big trouble for Microsoft. One of the reasons why Windows remains the major operating system in the world is because there’s approximately 17 Billion programs that have been written for Windows. There’s a lot of software, and software developers, under the Windows umbrella. But when those developers start walking away to join Microsoft’s competition, it’s going to be bad news for the Redmond Giant.
In fact, we’ve already seen Microsoft trying to combat this by “opening up” the .NET Framework libraries (in the sense you get to see and debug their code, but you can’t make changes and re-distribute it). Microsoft also had a huge presence at this year’s OSCON. Microsoft is starting to feel the heat and they know they need to win over the “hearts and minds” of developers. But giving away free shirts and keynote speeches isn’t going to cut it; Microsoft has to start revolutionizing the computing experience for the consumer market, and they’re going to have to do it themselves – something they’ve never done before.
The Principle of Least Astonishment
There is a good “rule of thumb” in software engineering called “The Principle of Least Astonishment”. In a nutshell, the principle states that the result of performing some operation should be obvious, consistent, and predictable, based upon the name of the operation and other clues(1). This seems like a fairly obvious principle. Be warned, however, that it’s easier said than done, and breaking this rule in your code can become easy if the design under the covers is somewhat lackluster. This is an illustration of something that does not follow The Principle of Least Astonishment.
A Little Background
.NET 3.5 introduces some excellent new technologies. One of these new technologies is Extension Methods(2); a static method that can be invoked by using instance method syntax. In essence, extension methods allow you to extend existing types and constructed types with additional methods without having create a new class which inherits the class you want to extend (or by marking the original class as partial). The IEnumerable<T>(3) interface in .NET 3.5 has been extended with almost 4 dozen extension methods.
A few of the extension methods in IEnumerable<T> allow for easy comparison between 2 IEnumerable<T>’s (arrays,List<T>’s, etc.). For example, with a single line of code, I can create a new IEnumerable<T> that contains the elements common between 2 other IEnumerable<T>’s by using the Intersect<T>(4) extension method. For example:
int[] nArray1 = {1, 2, 3, 4, 5, 6}; int[] nArray2 = {3, 6, 7, 8, 9} int[] commonIntsArray = nArray1.Intersect(nArray2).ToArray();
In the above example, the Intersect method will return the values that are common between nArray1 and nArray2. In this case, [3, 6]. Slick rick! 1 line of code, no looping, and you have the common set. But what happens if you want to compare two IEnumerable<T>’s of some custom object, such as 2 IEnumerable<Order>? You can’t very well say that Order o1 = Order o2… what’s are you comparing on? Thankfully, .NET 3.5 provides us an interface which we can implement on a class.
The IEqualityComparer<T> Interface
The IEqualityComparer<T> interface allows us to tell .NET how 2 objects should be compared. We can create equality comparer classes for any class we want (including .NET types). We can then use this equality comparer by passing it into the overloaded Intersect<T>. For example:
public class OrderComparer : IEqualityComparer<T> // defines Equals and GetHashCode { // implements the IEqualityComparer<T>.Equals(T x, T y) : bool public bool Equals(Order x, Order y) { Return x.OrderID == y.OrderID; } // implements the IEqualityComparer<T>.GetHashCode(T obj) : int public int GetHashCode(Order obj) { return obj.OrderID.GetHashCode(); } } public IEnumerable<Order> GetCommonOrders(Order[] orderSet1, Order[] orderSet2) { return orderSet1.Intersect(orderSet2, new OrderComparer()); }
In the above example, GetCommonOrders will return the common Orders between the 2 order sets using a new OrderComparer. .NET will use the Equals() of our OrderComparer method to determine if 2 of our objects (both of type Order) are equal (in our case, 2 Orders are equal if they have the same OrderID). If we called Intersect without passing an IEqualityComparer<Order> then .NET would use the default equality comparer, which would be the virtual Object.Equals() method – not what we want.
I thought this post was about something astonishing…?
You’re right – it is. Here’s the thing. Over the last 2 work days (about a total of 6.5 hours) I’ve been trying to get the following, bolded line of code to work.
public class MyWcfService : IMyWcfService { public Customer UpdateCustomer(Customer updated) { // some miscellaneous code IEqualityComparer<Order> comparer = new OrderComparer(); IEnumerable<Order> commonOrders = updated.Orders.Intersect(original.Orders, comparer).ToList(); // save user stuff } } public class OrderComparer : IEqualityComparer<T> { // implements the IEqualityComparer<T>.Equals(T x, T y) : bool public bool Equals(Order x, Order y) { return x.OrderID == y.OrderID; } // implements the IEqualityComparer<T>.GetHashCode(T obj) : int public int GetHashCode(Order obj) { return obj.GetHashCode(); } }
I had a Unit Test that tests the above UpdateCustomer method, and I found that the bolded line in question, for some unknown reason, never, ever returned a common result set – despite my unit test having a common result set. The result was always an empty IEnumerable. What gives? Can you find what’s going on? Can you determine why my OrderComparer was not working? Think about it for a bit (I thought about it for 6.5 hours, so pay me some dues and take 60 seconds to see if you can figure it out).
The reason why the above line was not working had nothing to do with the call to ToList() (I do that so that the Intersect executes – the extension method itself is deferred and only executes when a call to GetEnumerator is called). It also has nothing to do with the OrderComparer.Equals method. I’ll let you think about it a little more.
Give up? The reason why the call to Intersect was failing was because of OrderComparer’s implementation of GetHashCode. I found this nice little nugget in the IEqualityComparer<T>.GetHashCode() documentation:
Implementations are required to ensure that if the Equals method returns true for two objects x and y, then the value returned by the GetHashCode method for x must equal the value returned for y.
Seriously? *cries* I changed my GetHashCode method to the following and everything worked (change bolded).
public int GetHashCode(Order obj) { return obj.OrderID.GetHashCode(); }
Oye
As far as I’m concerned, Microsoft breaks The Principle of Least Astonishment here (this also goes for if you override Object.Equals – you get a compilation warning that states you haven’t overridden GetHashCode either). When I have a class that implements IEqualityComparer.Equals(T, T), I fully expect the result used by whatever calls that method to, you know, adhere to the result of Equals. However that is not the case with Intersect<T> (and other comparative IEnumerable<T> extension methods) – it’s true result hinges on a call to GetHashCode – which frankly confuses me; a) I don’t understand why a call to GetHashCode is required to compare 2 values, and b) it’s completely unintuitive. Despite my having read the help file about a gazillion times on IEnumerable<T>.Intersect<T>, and despite reading a gazillion pages online about Intersect<T>, and despite stepping through over and over and over again in debug mode, I couldn’t figure out what was possibly wrong. 1 line of code. 6.5 hours. 1 unhappy coder.
So be warned, fellow coders! The Principle of Least Astonishment is critical to the sanity of others using your code (especially if you’re writing code/classes that are low level and used by others developers). Don’t surprise me! Don’t have subtle dependencies between methods and the only place where it’s described is in the documentation! When I have to implement an Equals method, I expect that Equals will be used to determine the equality between 2 objects, and not be coupled with the result of some other method I have to implement! Please, won’t somebody please think about the children!
Love,
-
ryan.