Friday, February 29, 2008

Was the Y2K Bug a Hoax?

This is one of those questions that may never be answered. There was no worldwide disaster at the turn of the millennium. In fact, there were no reported cases of a Y2K-caused system failure anywhere. So was the entire issue a mere fear-mongering hoax perpetrated by the IT industry to make money? Or did the IT industry do such a good job of identifying the threat early and fixing it that they deserve our collective thanks and appreciation?

Advocates of the former view (that it was a hoax) have had the benefit of the doubt all along, but yesterday's events lend strength to the opposite argument - that we escaped by the skin of our teeth on 1st January 2000 only thanks to alertness and good crisis management.

I just heard from a friend of mine that his company suffered a major outage of its entire phone system yesterday. The time the problem started gives a clue as to what the issue was.

When the phones went dead in their Sydney office, it was 10:59 am, and the date was 29 Feb. If that doesn't signify anything, think about what time it was then in Greenwich.

11:59 pm, 28 Feb.

In a leap year.

That's what they apparently found out during the investigation. A firmware bug in the phone system's processors couldn't handle the date change on the leap year correctly, leading to a crash.

OK, so it was a relatively isolated bug restricted to one system (the phone network). Other computer systems reportedly chugged along without missing a beat. They had been designed to handle leap years because leap years are a well-known and frequent event.

Y2K was neither. It started as an obscure issue with no public awareness, and represented (literally) a once-in-a-lifetime event. How many systems would have been designed for it? Even farsighted designers were up against the high cost of computing in the sixties, seventies and even eighties. Saving 2 bytes with every date stored meant a lot of money, and therefore there is a real argument to be made that the huge sums of money that were spent on fixing the Y2K problem were worth it because of the larger sums of money that the design shortcut saved them in 60s, 70s and 80s dollars.

I have always believed (perhaps because I'm in the IT industry) that Y2K was a real problem, and that it was effectively fixed. Perhaps it was fixed too well. Perhaps there should have been some systems that were neglected and then allowed to fail on 1 Jan 2000, just to prove to the skeptics that there was a serious problem.

After all, if everyone in town takes a flu shot, and no one gets the flu that winter, is the flu shot a hoax, or did it just work as it was designed to?

Modelling Service Verbs as Java Classes

OK, so this is probably just an intellectual exercise for now, but someone may find a way to make it practical. Read on.

I've been going on in the recent past about how Services need to be verbs that make sense from a service consumer's point of view. Let's say we can articulate such verbs that reflect our domain from the outside looking in (the Viewpoint Flip of service-orientation). In other words, we manage to model the Service Interface quite independently of the Domain Objects.

How do we implement the verbs in this Service Interface? If we use a language like Java which is noun-oriented, that's going to be hard, as this hilarious article illustrates so well.

I propose we use the features of Java 5 to promote our service methods to the level of first class Java entities, i.e., classes. How do we do that?

Look at this example:

import java.text.DecimalFormat;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutionException;

// It's a noun! It's a verb! It's a Callable!
//
public class GetStockQuote implements Callable
{
private String stockCode;

// Constructor
//
public GetStockQuote( String _stockCode ) { stockCode = _stockCode; }

// Actual method, but it's effectively hidden and only implicitly called.
//
public String call()
{
DecimalFormat decimalFormat = new DecimalFormat( "0.00" );

// In a real system, use the stock code to look up the stock price.
// Here, just generate a random price.
//
double stockPrice = Math.random() * 100;
return decimalFormat.format( stockPrice );
}

// Test the "service".
//
public static void main( String[] _args )
{
String stockCode = "JAVA";
String stockPrice = null;

ExecutorService executorService = Executors.newSingleThreadExecutor();
Future future = executorService.submit( new GetStockQuote( stockCode ) );

try
{
stockPrice = future.get();
executorService.shutdown();
}
catch ( InterruptedException ie )
{
System.out.println( ie.toString() );
}
catch ( ExecutionException ee )
{
System.out.println( ee.toString() );
}

System.out.println( "The price of " + stockCode + " is " + stockPrice );
}
}

As we can see, the Future interface makes the call asynchronous. We could have performed the service in one line:

stockPrice = executorService.submit( new GetStockQuote( stockCode ) ).get();

That would have been a synchronous call.

It's a bit strange to see a verb like GetStockQuote strutting about as a class. In fact, it seems as wrong as those horrible C# method names with initial capitals ;-). But hey, that's the only way King Java will allow verbs to walk around by themselves without a noun chaperone. They've got to become nouns themselves, and the set of classes and interfaces in the java.util.concurrent package makes this passably easy to do.

Now that we've done this, we don't mind too much if someone annotates this verb "class" and generates a SOAP interface and a WSDL description from it. We have already performed the viewpoint flip (in Java), and since we believe that operation is the distinguishing feature of SOA, we are confident that even auto-generating a Web Services interface from this viewpoint-flipped class will not curse it with RPC semantics. It will be a true service.

The reasons why this still isn't going to be easy to turn into SOAP services is this: GetStockQuote will be the WSDL name for the service all right, but what will the operation be called? (The "service" in WSDL is just the wrapper for a number of "operations", which correspond to object methods.) I think "call()" is a rather weak name for the operation, but I guess it corresponds to "processThis()", which is the "uniform interface" of the SOAP messaging model (MEST).

More practically, the Callable mechanism requires the call to be made in two passes. The first pass involves calling the constructor with the parameters to the service. The second pass involves calling the "call()" method (indirectly) by submitting the class to an executor. How would that mechanism translate to a WSDL definition? I must confess I'm stumped there.

Anyway, this is my rough idea for a way to accommodate the automatic interface generation approach provided by SOA tools today without compromising the spirit of SOA by embracing RPC semantics. I'm sure some refinements to this idea will be proposed by wiser heads than mine.

Thursday, February 28, 2008

So What Gives SOAP its RPC Flavour?

(This is a summing-up of several threads from the past.)

When do we say that SOAP usage is RPC-style?

1. When we pretend to pass domain objects by reference but pass them by value?
2. When we use the "rpc/encoded" style instead of "document/literal"?
3. When we use WSDL (which forces request/response semantics) instead of SSDL?
4. When we expose domain methods as service operations without a viewpoint flip?

Not surprisingly, although all these criteria have merit, I'm now leaning towards the last view, because that represents my latest thinking. I believe that what makes SOA service-oriented is the flip in viewpoint from the inward-facing domain model to the way an external consumer would view the domain.

Example:

How we humans view our world (our "domain"):
Our behaviours - eat(), sleep(), makeMillionDollars(), payOffMortgage(), etc.

How aliens may view our world:
"Services" they can use - explore(), trade(), conquer(), etc.

I now think that if we achieve a semantic flipping of viewpoint from the methods within domain objects to the verbs that a "service interface" must expose, then we have decisively broken the RPC link.

1. There is no way we can pretend to be passing objects by reference. There is a very tenuous link between a method inside a domain object and a service verb, so the illusion of calling a local method on an object simply cannot exist.

2. The "rpc/encoded" style really doesn't hurt after the viewpoint flip is achieved. Does it really matter if we say

<param1/>
<param2/>

at the top level instead of having a single document root like this:

<method-name>
<param1/>
<param2/>
</method-name>

I don't think so. I think that's a technicality.

3. And even if WSDL forces request/response semantics on SOAP, a suitably viewpoint-flipped service is still not a remote procedure call because the service consumer still sees things their way.

On the other hand, if you take a domain method and (without a Viewpoint Flip) turn it into a SOAP operation in the doc/lit style, and also describe it in SSDL, I would say it's still RPC, because we're merely making domain methods remotely invocable.

So if that's all there is to it, let's call RPC "domain-oriented" in contrast to "service-oriented".

Tuesday, February 26, 2008

A Rant about GlassFish and Jersey

So you want to play around with Web Services, both SOAP and REST? Maybe you've had your fill of WSO2's Mashup Server, drooled over its strengths (XML processing and service exposure) and understood its limitations (legacy resource connectivity including persistence - no, Data Services didn't cut it for me). Now you want to look at a more conventional, Java-based (as opposed to JavaScript-based) server.

I had attended a Sun Tech Day many months ago when they demonstrated the GlassFish JEE app server and its REST implementation called Jersey. I had also heard a lot about Sun's advanced SOAP/WS-* stack, Project Tango. One of my consultant colleagues (a REST advocate, no less) showed me a Tango demo he had put together and was himself impressed with the policy-driven interoperability that it made possible.

So it was with fond visions of being able to build a Domain Model using Java objects and then expose the domain as services using both SOAP/WS-* and REST paradigms from the same box that I downloaded GlassFish.

The GlassFish Quickstart Guide gave me my first indications of trouble.

Why would you have instructions labelled Step 1 and Step 2 if there's something you need to do before either of them? (Shouldn't that at least be labelled Step 0?)
Steps
1. Add the install-dir/bin/ directory to the PATH environment variable.
2. Start the server by entering this command: asadmin start-domain domain1.

After searching in vain for the "bin" directory under the directory where I had installed (well, unzipped) GlassFish, I found this line above the two steps listed:

Once you install using "ant -f setup.xml", you start the server by starting the domain.
Casually, just in passing. Why they didn't just say
Step 0: Install GlassFish using "ant -f setup.xml"
beats me.

So I finally installed GlassFish and started up a "domain" from the command line. (All right, I'll go with your idiosyncrasies, although why I should know about "domains" and why you couldn't just give me a Linux "startup.sh" script and a Windows "startup.bat" script beats me once again.)

Oh, then I found that Jersey doesn't come bundled with GlassFish. I'd have to get that separately.

No problem, GlassFish has a tool called "Update Center", which lets you download modules like Jersey automatically.

Uh-oh. Update Center doesn't work through proxies. (You idiot, configure the proxy settings in the tool.) I did that. The "doesn't work" comment refers to after I configured my proxy settings in Update Center. And I didn't get a meaningful error message either, so I had no clue how to fix the problem, if indeed the problem was my fault. (These guys are starting to bug me.)

OK, good news, bad news. It appears from someone else's experience that Update Center only shows you older versions of Jersey, not the very latest one, so you can't use it anyway. You'll need to download and install Jersey manually.

All right, so I downloaded Jersey and ran the recommended script

$ ant -f jersey-on-glassfish.xml
-Dgf.home=$HOME/bin/glassfish install

Got the predicted error message, edited "jersey-on-glassfish.xml" and commented out the offending line. (Seriously Sun, even teeny-tiny Open Source projects provide working code. Why can't you?)

Finally got the ant script to work.

Hold on! Turns out there's something more. A lot more. To quote Drop By,
Be aware! This procedures will only install the examples and won’t add auto-magically the jersey jars to Glassfish’s runtime classpath. So
you have to take care by yourself to include the jars to the build target, see the provided examples:
Okay-doke. I ran
ant -f build-impl.xml library-inclusion-in-archive
I got an error with a TaskDef of all things. Some class (I forget what it was now) wasn't found, although it should have been. That's when I finally gave up.

There's simply no excuse for the abysmal state of readiness of GlassFish and Jersey. I know Jersey isn't yet at version 1.0, but GlassFish is at version 2.1, for goodness sake! In contrast, WSO2's Mashup Server worked, and worked pretty well, way back in the days of version 0.2. It was trivial to install and get running, the examples worked, and all my test examples worked as well. There were some problems that I faced, but those were when I had gone well past the basic stuff and started pushing the envelope.

I don't know if I have the time and patience to try GlassFish and/or Jersey again. It's just too hard.

Friday, February 22, 2008

The Deciding Characteristic of SOA - The Viewpoint Flip

I used to tell the curious that SOA's distinguishing characteristic was loose coupling. That definition probably says it all who those who already "get" it, but probably fails to communicate anything meaningful to those who don't already know what it is.

These days, I try and emphasise one particular kind of loose coupling that I think epitomises what SOA is, and I call it The Viewpoint Flip. The Viewpoint Flip is a more tangible concept than "loose coupling", and therefore more practical advice to give to aspiring SOA architects. The Viewpoint Flip is more important than breaking the synchronous request-response paradigm and replacing it with asynchronous messaging - that's transport sugar. The more important decoupling happens in the application domain, and I'll talk about it again in this post, although I've covered it in the past. A recent discussion with a colleague has convinced me that this aspect of SOA is often underappreciated even by SOA practitioners. That's why I'm talking about it once again.

The flip in viewpoint that I'm talking about is from the application domain's own navel-gazing view of itself to the view of an external party who wishes to interact with the domain for their own purposes. It's not for nothing that SOA is called "service-oriented". You can't be service-oriented, even in the English sense of the term, if you're focused on your own view of the world. You need to think about what your customers want. Ironically, object-oriented systems (supposedly the pinnacle of modelling paradigms) may require the most wrenching viewpoint change, because their model is, by design, internally-focused. Older, procedural languages are often more naturally oriented to the viewpoint of an external party.

Two examples, one of which I've touched on before:

Take a drum (the musical instrument, not the vessel that stores water). Model its (State and) Behaviour using the OO paradigm. What methods can you think of that would model the drum's behaviour? If you said "beat()", you're still thinking procedurally. Beating is something you do to the drum, not something that the drum does. What the drum does in response to the beating is make a sound. Therefore "makeSound()" is an appropriate method for the Drum class. That's how you would model the domain. (If you had a Drummer class, then "beat()" could be a legitimate method of that class.)

But "makeSound()" is not a service-oriented verb! It's not what a prospective external user of the drum would do. It's too internally-focused. Funnily enough, "beat()" is a good service-oriented verb. Procedural thinking is alive and well in the SOA world, it would seem.

Another example is the common one of funds transfer between bank accounts. For some reason, this simple example seems to tie everyone up in knots. I've seen examples like this:
fromAccount.transferTo( toAccount, amount )
or alternatively,

toAccount.transferFrom( fromAccount, amount )
Neither of them is aesthetically satisfying. Neither of them models the inherent symmetry of the "transfer funds" operation.

What we want is an unashamedly procedural syntax

transfer( fromAccount, toAccount, amount )
But we're too tied up in OO thinking to be able to do this elegantly. But that, if I may point out, is precisely what we need to be able to say in SOA-speak.

Insight 1: SOA thinking requires a fallback to procedural logic. This is one of the fundamental drivers for the Viewpoint Flip.

[The Domain Model for the banking Account class would probably have methods like "acceptDebit()" and "acceptCredit()". The "transfer" verb would be modelled from the start as a Service, if one goes by the principles of Domain-Driven Design, because "transfer()" (whether to or from) is not part of the behaviour of the Account class. It's this non-Object-Oriented Service that would acquire the two account entities from a repository based on the identifiers passed to it, and then (transactionally) invoke the "acceptDebit()" method of one and the "acceptCredit()" method of the other.]

By the way, REST is beautifully elegant, partly because it achieves the Viewpoint Flip without anyone even noticing. GET, PUT, POST, DELETE - these are all things that you do. They're not verbs that model the behaviour of resources. They're verbs that model what service consumers do to resources. When you adopt the REST model, you are unconsciously forced into service-oriented thinking and away from object-oriented thinking. With SOAP/WS-*, there's a degree of conceptual sophistication that's demanded of the designer, without which the whole thing degenerates into a bunch of remote procedure calls in XML syntax, needlessly complex and brittle beyond belief.

If I may fire my pet arrow at SOAP in the eternal REST-vs-SOAP debate, the approach of many Web Services tool vendors is to generate SOAP interfaces and WSDL files by annotating methods on objects. This is so naive I don't know whether to laugh or cry. There is no annotation in the world that can cause the "makeSound()" method on a Drum class to transform itself into the "beat()" service that should be exposed to external systems. The Viewpoint Flip is a sophisticated conceptual exercise that only a human designer can engage in. If you rely on tooling to expose services from your domain objects, and you end up with a SOAP operation called "makeSound()", that's not SOA, that's a horrible Distributed Objects train wreck. Distributed Objects don't work.

In contrast, so many good things come together thanks to the singular concept of the Viewpoint Flip.

RPC goes out of the window, because we're not doing remote method calls. We're fundamentally transforming the nature of the verb. So it can't be about taking a local method on a class and making it remotely invocable. People have railed against SOAP-RPC for years (and I have as well), but the most damning argument against SOAP-RPC, I now realise, is that it doesn't implement the essential Viewpoint Flip that's required to turn a Domain Model into a Service Model.

Contract-First Design is another approach that emerges naturally out of accepting the need for the Viewpoint Flip. If you can't automatically generate a service interface from methods on objects, then it follows that it must be independently designed. In other words, the Service Interface and the Domain Model are independent, first-class entities. Neither can be generated from the other. They must be mapped to each other.

Did you notice that that's loose coupling? Change either the Domain Model or the Service Interface, and the other doesn't necessarily have to change. You may just have to change the mapping logic between them and hence preserve the other.

Nowadays, when someone asks me what SOA is all about, I don't glibly say "loose coupling." I say very slowly, "It's about being s-e-r-v-i-c-e o-r-i-e-n-t-e-d, being oriented to the viewpoint of the service consumer. SOA thinking means looking at a domain from the outside in, from the perspective of a consumer and what they wish to achieve, rather than how the domain sees itself, i.e., as a set of inter-related objects." [As Kirstan observes, it's also the most natural way in which a business analyst looks at the domain, i.e., as a set of service "steps" that can be composed into a business process.]

A bit of philosophy: I read somewhere that when a student embarks on the study of Zen, the mountains are nothing more than mountains. Partway through the training, the mountains are no longer mountains. But finally, when the student has mastered Zen, the mountains are once again mountains, but they're somehow not the same as what they were.

So let it be with models of the world. From procedural thinking to object-orientation and back again to procedural thinking. But this time around, procedural thinking isn't quite the same thing. It's service-oriented.

Wednesday, February 06, 2008

REST Eye for the Relational Guy - The "Uniform Interface" Explained

My thanks go to Rhys Frederick for the analogy I'm about to share with you. Just the day after my last post, in which I'd said, "On the 'uniform interface' issue, I'm hearing the words, but I'm not seeing the REST vision", Rhys asked me to remind him of the name for a certain pattern used in relational database design, and casually mentioned that it was analogous to the uniform interface of REST. I did a double-take. A few Google searches later, I finally grokked the REST Uniform Interface concept, thanks to my experience with RDBMS in a past life. Thanks again, Rhys. The coincidences in my life never cease to amaze.

It's funny how many times I've had to change my way of thinking in the last twenty years of my career. I learned programming with BASIC and FORTRAN, complete with that wonderful "feature" called GOTO. I feared GOSUB. I couldn't understand it. GOTO was easy to understand. Then I learned structured programming, and GOSUB suddenly became the most natural construct in the world. GOTO became (cough) a four-letter word. As relational databases became popular, data for me became a set of tables, and with SQL came the shift from procedural to declarative thinking. Then came the difficult shift to object-oriented thinking (although I'm grateful it didn't have to be through the torture of C++!) A combination of PowerBuilder (yes!) and Java got me over that line. The latest change in my thinking has been thanks to SOA. I've now learnt to think "between domains" in addition to peering "inwards" at a domain with pure OO eyes. And while I've been able to fit REST fairly naturally into my generic SOA worldview, I have struggled to see the world through RESTian eyes, the way the REST folk seem to see it.

Until now.

Now at last, one major facet of REST lies exposed before me, and the irony is that I had to fall back to relational thinking in order to understand it.

Let me launch into the analogy. It's variously called (as I learned) the Value-Pairs Pattern, the Vertical Schema and the Object-Attribute-Value Pattern.

Consider some arbitrary domain modelled using an Entity-Relationship Diagram. The model looks something like this:

Note that each entity has an ID (its primary key), some attributes, and also some foreign keys that refer to the IDs of other entities. This is a specialised model, tailored to this particular application. But there may be a common pattern here. If you find that the attributes (names and types) are similar for all the entities, it may suggest a generalisation of the form shown below:

What we've done here is create a separate table (ATTRIBUTE) listing the names of the different attributes that an entity may have. Then we create mapping tables (ENTITYn_ATTRIBUTE) that create an association between each entity and the generic attribute table. Each row here holds the value that an attribute has for a particular entity. The entity tables themselves are now much smaller. They only hold foreign keys. This model is no longer tied so strongly to a particular domain, because we've taken part of what makes it unique to a domain and genericised it. If we next assume that each entity ID is globally unique, we can apply some generic thinking to this aspect of the model as well.

Here's a completely generic schema.

Look at the names of the tables now! They're all completely generic (ENTITY, ENTITY_RELATIONSHIP, ATTRIBUTE, ENTITY_ATTRIBUTE). The new ENTITY_RELATIONSHIP table even takes the foreign key constraints out of the various ENTITYn tables and holds it as an external mapping. Now all the different ENTITYn tables can be collapsed into a single generic one called simply ENTITY. This model is completely generic. We can add and remove entities, attributes and foreign key relationships at will. We don't have to change the schema at all. Contrast this with the specialised model we started with. Every such change there would have required a change to the schema.

What's more, the generic schema is simple and can be universally communicated, even turned into assumed knowledge. Then all you're concerned with when you talk about a particular domain is the data. The schema ceases to be a differentiator. It's universal. With specialised schemas, on the other hand, you need to communicate the schema as well as the data. Now I understand why the REST guys say REST doesn't need a WSDL equivalent. When the schema is generic and well-known (the "uniform interface") why would you need to describe it?

More analogies creep out of the woodwork as I gaze at the model. See the IDs? They're URIs. It was the assumption of global uniqueness that allowed us to mix the IDs of completely different entities in the one table. URIs are globally unique too. Nobody is going to confuse http://something.com/customers/1234 with http://something.com/orders/1234.

See the foreign keys? They're hyperlinks between entities.

And because we're assuming a limited number of attributes (but not restricting it to a particular number), it vaguely corresponds to REST's limited set of verbs.

URIs, hyperlinks, a limited set of verbs - there's the relational analogy for REST!

Message to the REST folk: I finally get your model :-).

</euphoria>

There is something, though, that we lose by going down the generic path, and that is understandability. I can understand a domain pretty well by studying a specialised Entity-Relationship Diagram, but a generic schema does not speak to me at all. If all domains look the same, what makes them unique? Infinite plasticity makes me very uncomfortable. I can't "see" the domain from the data. I need a schema. When we talk about automated reasoning, perhaps schemas are more important than ever...?

To turn an old REST argument around, constraints empower. If I make my schemas more rigid, I gain something - obviousness of purpose. So the vertical schema pattern isn't a constraint, it's the absence of one. Anything will fit into it, and so it describes nothing.

I must say I'm enjoying this journey. Each day brings fresh insights, and fresh questions...

Monday, February 04, 2008

Decoupling Interface from Implementation - Is REST Really Better Than SOAP/WS-*?

(New diagrams - download from here)

In a previous post, I tried to argue that the REST and SOAP/WS-* models were duals, and that they could be seen as two views into the same domain. Mark Baker disagreed, and his point centred around the decoupling of interface from implementation.

Now, as an architect, I am rather sensitive to issues of tight coupling, and have often railed against examples of this, such as the SOAP-RPC style itself and the generation of WSDL files from Java implementation classes. But Mark goes much further. He would like to change the implementation of a service from a Stock Quote service to a Weather Report, and he would like to see his interface unchanged! To my mind, this goes beyond the reasonable. It's like changing from pasta to soup, and expecting to continue using a fork.

The decoupling I expect is far more modest, and dare I say, more of the kind expected to be encountered in practice? A change in an algorithm, an extra parameter or two, changes to qualities of service or a change of business domain owner. All of these except the second (extra parameters), I would expect to support without breaking the service interface. For the second, I would expect to be able to create a new version of the service while supporting the older version in parallel for a time until deprecated.

I don't know if it's a Zen thing. On the "uniform interface" issue, I'm hearing the words, but I'm not seeing the REST vision. Maybe one day it'll come to me in a blinding flash, and I'll be a RESTafarian myself, but for now, I'm in the "both models are valid" camp.

So with my current state of understanding, I've drawn a new set of diagrams which shows how one can implement services using the SOAP/WS-* and REST models, and the degree of decoupling between the Service Contract (the interface) and the Domain Model (the implementation) in each case. I see no difference in concept between the two approaches. In fact, the two are extremely similar. I would agree with Mark on one point, though. The SOAP/WS-* world today does not practise the kind of decoupling I describe in this diagram. I guess I'm proposing what I think to be "best practice" in this space. Let's see what responses I get.

Saturday, February 02, 2008

DRM is Well and Truly Dead

The death sentence on DRM was pronounced more than 6 months ago when EMI and Apple joined hands to break the music industry's cartel and drop DRM from the products they sold. Now the beast is well and truly dead. The last (and the dirtiest) of the big four music labels (Sony) has finally joined EMI, Warner and Universal in dropping support for DRM.

Yesss!!!

And as I wondered in April last year, where does this leave Microsoft? Vista runs like a dog compared to XP partly on account of DRM and the other anti-user "security" features it's bloated with. Well, now that DRM is a waste of time, why bother upgrading to Vista (even if you did like handcuffs)? These handcuffs don't even work!

I was very worried at a certain point in time that the intellectual property pendulum had swung so far to the right that some music industry executives even had the nerve to say in public that people skipping ads on TV were "stealing". The cartel is still dangerous, but the death of DRM has surely hurt them.

It gives me great pleasure to see the world slowly but surely changing for the better.

John Howard - gone. DRM - gone. George W Bush - going. Microsoft ...