September 2006 Blog Posts

Mocking with TypeMock

TypeMockI've been a slow convert to the whole test-driven development movement. I'm ashamed, but it's true. I've believed in TDD in principle, but when it came down to it, designing specifically for testability always made my code feel so bloated. I always ended up writing unit tests after the fact, and many times would end up writing loads of helper objects and dummy interface implementations to get things to work.

No longer.

We started looking at mock object frameworks for the latest project at work. After checking out Rhino Mocks (admittedly a decent framework), we stumbled upon TypeMock.

Holy crap, this thing is hot. In technical terms, you might call it the bomb-diggity.

There are several things that make TypeMock the framework to go with. The syntax of the "Natural Mocks" is nice and clean, making the majority of the mocking easy to use. It'll mock static methods, constructors (and static constructors), and non-public methods - stuff Rhino [currently] won't let you do.

"But," you might say, "mocking frameworks are hard to work with because you can't really see what's going on 'behind the scenes.'"

No longer! TypeMock has a trace utility where you can watch in real-time as the mock framework sets up and fulfills expectations. If you want to know what it's doing, check the window. Want to know specifically what expectations are set up and which ones were left? It's right there. No more fighting with stack traces and expectation exceptions. It really doesn't get any easier than this.

A co-worker showed me some code he had written using Rhino. Frankly, I found it confusing and it wasn't his code making it that way. I tried writing my own tests in it and had a heck of a time figuring it out. I picked up TypeMock this morning and minutes later was flying through it.

Ever tried to test an abstract class? You know how you have to create a dummy class that implements all the abstract stuff just so you can test the functionality? Not anymore - you can get a mock of the abstract class with no "placeholder" or "dummy" classes. Ever tried to test a factory that returns values based on configuration files in the filesystem? You know how you end up having to dump fake config to just the right spots in the filesystem in order to test that factory? And you know how much more trouble it is to test classes that make use of that factory? Forget that. No more having to fight with all that. It's a piece of freakin' cake.

Let's use that factory example. Say I have a factory called CoolFactory that has a method CoolFactory.GetCoolObject(). That method looks up a value in configuration and returns an object of type CoolObject. Now say you have a class called WorkingClass (pun?) that uses the CoolFactory to do some work in the WorkingClass.DoWork() method.

You used to have two options: either over-architect CoolFactory and have a load of various pluggable providers that the factory could use and clutter the API with so you can sub in configuration at test time; or set up configuration, dummy objects, etc., all to support a single test.

With TypeMock, you can mock that static CoolFactory.GetCoolObject() method and skip all that. Here's what an NUnit test might look like:

public void MyTest(){
  // Set up the object you want the factory to return here
  CoolObject factoryGenerated = new CoolObject();

  // Record the actions you want to play back
  // and tell the factory to return your object.
  using (RecordExpectations recorder = new RecordExpectations()){

  // Call the method that uses the factory
  WorkingClass testObj = new WorkingClass();

  // Make your test assertions here...

  // Verify the DoWork method called the factory

That's it - when the DoWork method calls the factory, it'll return the object you set up. No need to dump config to the filesystem, over-architect the factory, or dummy up a lot of extra "helper" classes.

I haven't been this stoked about a technology for quite some time.

Now, I'm using the Enterprise edition (they offer a "community edition" that doesn't have the "Natural Mocks" in it - don't bother with that, you want the Natural Mocks). I'm not sure if I'd have been so excited if I was stuck at the "community edition" level. But I'm not, so I'll play ignorant and revel in what I've got.

No more designing for testability! No more huge efforts to create dummy objects to get various components working and tested!

You know what? With a framework like TypeMock, I can 100% buy into test-driven development. I can keep API as a deliverable and still get full test coverage - I get my cake and I eat it, too.

Check out TypeMock. You'll be glad you did.

Are Mock Objects Too Powerful?

Playing with matches will get you burned.Lately at work we've been working towards test driven development and not just "having a lot of tests." For pretty much anyone who has written unit tests for anything with any complexity, you know that's a lot harder than it sounds. You need to be able to test certain components in an isolated fashion and the bits that you need to integrate with may not actually be written yet.

To get around this, you generally end up writing a lot of test and helper classes to stub in the functionality your component interacts with, but that's a heck of a lot of work. In some cases, you might have to drop live configuration files into the system to get things to work correctly, you might need to craft some dynamic logic into your test classes... it's a big pain.

Some folks choose to architect their components to be easier to test. This usually implies there are more publicly exposed methods than you might normally have so that certain internal properties can be checked on, substituted in, or otherwise dealt with in a test environment. It also means there are a lot more moving parts - interfaces for "plugging in" components that wouldn't normally be there except for the need to swap in at test time. We'll call that "designing for testability."

Unfortunately, much of what I work on has the API as a deliverable. Which is to say, I can't just have a load of exposed public methods floating out there solely to support my tests. I can't "over-architect" the usage of the components because part of the goal is to make the components simple to use. Instead of designing for testability, we have to test what's designed.

The problem, then, is how to "plug in" or stub out things in testing to isolate the component being tested? Enter mock object frameworks.

Mock object frameworks allow you to do that sort of thing on the fly. You can say "give me a mock data provider and whenever anyone queries it for data, have it return this data set here." It's a really nice, simple way of doing things that doesn't require you to bloat your design just so you can test it.

Okay, so that's your quick "mock objects" intro. The question I'm leading to is: mock objects are very powerful. You can do a lot of stuff with them. So much, that if you aren't really paying attention, you could very well mock your way into invalid tests. The question on the table, then, is "are mock objects too powerful?"

This is actually an ongoing debate at work as we investigate different mock object frameworks. If we end up with a site license for a fairly powerful mock object framework, what's to stop an untrained developer from misusing it and giving us a false sense of quality by writing invalid tests?

My view: it's a tool, like a screwdriver or a hammer. Or matches. If you don't know what you're doing with the matches, you're going to get burned. If you know what you're doing, matches can be very helpful. It all comes down to education. People just need to be smart enough to know when they're not smart enough to start using the tool and get educated before picking it up and heading down that path. I don't think "people might misuse it" is a convincing enough argument to not use the tool. I might also consider that if it's worrisome to a particular team or project, the folks overseeing that team or project need to pay attention and ensure the right tools are being used by the right people for the job.

Besides, there are so many other ways the uninitiated can mess up production code, somehow I think "using a mock object framework improperly in testing" doesn't qualify on the top 10 threat list.

Stepped Up to PSP

PSP Entertainment PackAfter thinking about it for a while and talking about it for, like, a year or more, I finally stepped up and bought myself a PSP (PlayStation Portable).

I realize I'm a little late to the show on this one, but it's pretty bad-ass. The screen is nice and crisp, no dead/stuck pixels (that I've found so far), and I've got a couple of games for it that are pretty neat.

I actually ended up with it since I'm going to be taking a couple of trips soon (Vegas this weekend, Aruba for the honeymoon) and want to watch some movies and play games on the flight. I figured, for the price, as a portable game and media platform, it can't be beat. Plus the package I got was pretty good for all the extra stuff you get.

Now I just need to get a protective case and I'm set to go.

Going to KA at MGM Grand

Cirque du Soleil: KA

Stu, Jason, Jason's brother Adam, and I are all going to Vegas next weekend for my bachelor party. Come 9:30p on Saturday the 30th, though, you know where I'll be?

Front and center for the Cirque du Soleil show, KA!

Center of the front row for KA

Actually, literally front and center. Stu and I, middle of the first row. Of course, tickets are $150 a piece, so I can't say it didn't cost me, but I've yet to be disappointed by a Cirque show.

Oh, hell yeah. I'm altogether too stoked. Jenn is going to be soooo jealous.

Maybe Time for PSP

I've been considering getting a PSP for a while now but just haven't been pushed over the edge. My gadget interest has been generally low for a while with no cool tech really calling out to me lately, so the PSP has surfaced again as something I might be interested in.

I was at the store this morning picking up a copy of the Rush album The Spirit of Radio: Greatest Hits 1974 - 1987 (Neil Peart being arguably the best drummer ever) and the guy at the store mentioned they were coming out with a new PSP value pack of some sort that includes more stuff.

A little research brings us to the PSP Entertainment Pack, which is like the existing "Value Pack" but with a 1GB memory stick, a movie, and a game. A little better deal for the money, though, granted, the system's not brand-spanking-new to the market, either.

It's something to think about. I hate to be on the tail end of technology, but it's becoming a better deal so it might be worth a shot.

Wedding Registry

For folks curious, Jenn and I are registered at Target, Bed Bath and Beyond, and Macy's.

DVD ISO via MediaPortal

I've been looking at ways I can make my DVD collection more accessible. I find that I end up watching crappy On-Demand movies through cable rather than getting into the ol' DVD collection because the DVD collection is a pain in the ass to find things in and it ends up being, frankly, too much effort. (Yeah, the collection is that big. Well into the hundreds of discs.)

The notion of a media center PC springs to mind, but the problem I've seen with most media servers is that they require you to rip the DVD into just the video and a single soundtrack or some such, losing the menu and the features and the rest of the DVD that you paid for. I want the whole thing - I bought the movie and all the extras, I want access to all of that.

I found MediaPortal today and I think that may be the answer. It's got native support for Daemon Tools so you can just rip your DVD to ISO format and have the media server play it just as though you had put the physical DVD into the drive. That's exactly what I'm looking for. Plus it's free!

I may have to get a test of this going at home. If it pans out, the new year may find me building a home theater PC with a loooot of storage and ripping the DVD collection onto that. I'd like to enjoy the movies I own again and not just be in the media storage business. The iPod has liberated me from CDs (well, the iPod with iTunes and a fairly sizable external drive); it's time to be free of DVDs as well.

General Irritation

I'm generally irritated today and I don't think it's any one particular thing, so I can't say what the root of it is, but I'll gladly share some of the stuff pissing me off. Granted, more of a cathartic effort for me than a great entry for the readers.

There's one week left for RSVPs to come back for the wedding and we've only gotten about half back. Yeah, folks have a week left, but I think it's time to start chasing people down. There's really no margin for folks to just be showing up without having replied. Which means I'm going to have to start getting email reminders out to folks with email and call the rest personally. I'm not sure what the difficulty is with sending a pre-addressed, pre-stamped postcard, but apparently it's a showstopper for some folks.

I'm concerned that a good friend of mine is becoming a workaholic, possibly entirely out of boredom, as they have become fairly distant in recent times. Not to mention pretty conservative with information about what they've been up to. I'm not interested in the gory details of peoples' lives, but when you get together to talk to someone and it's a one-way information sharing street unless you ask just the right questions, it becomes a little stilted.

On that same note, I got an instant message from another friend who seems to know a hell of a lot more about what I'm doing than I know about what they're doing. It's been a while since I've gotten together with this friend, but somehow they are entirely up to speed on a lot of things - things I've not posted, emailed, IM'd or talked to them about. That's a little disconcerting, and I'm not sure how I really feel about it. I'm glad to reconnect with this friend, but I think if my friend wants to know what's up with me and Jenn... they should ask me and Jenn.

I'm super bored with the latest project at work which involves a hell of a lot of "review this stuff you've already done." And I'm tired of people telling me when I mention how boring it is that, "you have to take the good with the bad" or "business needs require tasks that aren't as fun sometimes" or whatever. I get it. I mean, I'm doing what needs to be done, right? That doesn't make it fun, it only justifies the requirement. I'm not debating the requirement. I'm debating my motivational difficulties in completing the task.

Anyway, it'll get done, I just have this vehement ennui.

Hey, that's a good band name. "Vehement Ennui."

Okay, done ranting. Time to get to work.

Just Say No to Amazon Unbox

Amazon has this new "video on demand" service called "Amazon Unbox." For about a second it looked interesting - get digital versions of movies rather than buying DVDs - until you look at the license agreement you have to accept to get these movies.

There's a great write-up of this at Boing Boing.

I think I'll be passing on the old Amazon Unbox.

I'd Starve On A Deserted Island

CoconutI went to the store last night to pick up some unsweetened shredded coconut for use in a recipe I plan on trying out. Unfortunately, it looks like the market for unsweetened coconut is somewhere between nil and zero, so they have seven brands of sweetened coconut but not a single unsweetened bag to be seen.

This being the case, I crossed the store to the rarely-visited produce section and picked myself up a fresh coconut. The only way to get unsweetened coconut is to get it right from the source, right?

It's three bucks for a coconut. Three American dollars! For one coconut! Somehow I think they're getting me coming and going on that one. But what choice have I got? Three bucks later, I'm out the door and on the way home.

Fast-forward a bit and it's Travis vs. The Coconut. The coconut, staring up at me from the counter with its three beady eyes, me staring back at it, not really sure how to proceed. I mean, I watch Survivor, I've seen folks open coconuts, but it usually involves a large rock and a machete, neither of which I have readily available. Plus, somehow I think that's going to create a larger mess than I'm willing to clean up. As it stands, that sonofabitch is shedding its shell crap all over my counter.

It crossed my mind that "I know computer stuff, maybe Jenn knows how to open the coconut," but I was disappointed in that effort - she didn't really have an idea, either.

Good Housekeeping to the rescue. There are actually two pages on how to deal with coconuts in there. (It sort of reminds me of my mom's [really] old Joy of Cooking cook book that explains how to prepare squirrel and other crazy shit.)

Here's what you do: get a hammer and a screwdriver. Yeah, because you have those sitting in the kitchen. Okay, so take the screwdriver and pop two of the eyes of the coconut out. Take that, you stupid coconut! Drain the liquid out of the coconut because it's freaking nasty and if you need coconut milk the stuff in the can at the store is better. Now bake the coconut at 350°F for 15 minutes. (I think the baking is to dry it out, but it wasn't dry when I finished baking it.) Finally, take the coconut into the garage and beat the shit out of it with the hammer until you have reasonably sized coconut chunks.

Now comes the hard part. You have to use some sort of cutting utensil to get the coconut meat off of the shell. I found that it was easier to do this with some of the larger pieces of coconut because once you get a large section going, it all comes off in one big piece. Smaller bits are harder to get started. Once you've got the thing shelled, use a peeler to remove the hard brown outer skin on the coconut meat. (You would think that removing the shell is enough, but no, there's like this "shell within a shell" bullshit so there's still more shell to remove.)

That peeling is actually the hardest part because coconut meat is slippery so you can't really get a good grip on it while you're working. Again, larger pieces of coconut were easier to deal with here. Of course, you can't escape unscathed, and I peeled my left middle finger just a little in the process.

That's when I decided that if I were on a deserted island, I'd just starve. Cracking and shelling and fucking peeling and everything else really is just a hell of an effort to get a little bit of coconut. I think you'd be better off trying to catch fish with your bare hands or wrestle an alligator or something. They must have some sort of coconut shelling/peeling machine at the coconut factory. This is ridiculous.

The end result of all this is that we now have a shelled, peeled bunch of coconut we can run through the grater tonight and use in the recipe. Let me tell you, that coconut had better be the best damn addition to any recipe ever tasted by a human tongue. I'm gonna be so hella pissed if I just spent all that effort for some mediocre crap.

Anson Horton on C# XML Doc

Interesting article about a couple of lesser known features of XML doc comments - multi-line comments and easier support for referencing generics.

Tech Podcasts Take Over

Is there a tech geek out there without a podcast? First Hanselminutes, now Millahseconds. Maybe I should come up with a podcast produced by Carl Franklin that also makes a time-based wordplay.

Sandcastle: I Don't Get It

I've finally taken some time and looked at Sandcastle, the new Microsoft alternative to API documentation rendering. Now that I've used it, I've decided that either Microsoft is jumping the gun on releasing this thing as any nature of "Community Technology Preview" or Microsoft just generally hates people who need to compile documentation.

"But why," you might ask, "would you say something like that?"

You, the asker of such a question, have obviously not used Microsoft help compilers.

First Microsoft gave us HTML Help Workshop. If you haven't used HTML Help Workshop, save yourself the trouble. It sucks. It's the epitome of late 90's UI design that basically gives you no indication of what to do or how to do it. RTFM, you loser. You are not smart enough to start up HTML Help Workshop and go.

But HTML Help Workshop is what we've got and that's about where it stayed. It comes with the HTML Help Compiler, which basically crunches all of your HTML help documents into one file that can be distributed - a CHM file. The HTML Help Compiler is actually the important part of the workshop package and is generally the only piece that any normal human can take advantage of.

The problem then becomes figuring out what all the pieces are to get the compiler to run. You've got your project file, your index file, your table of contents file, your HTML files that actually contain the body of your help... it's clunky.

Enter products like RoboHelp that make the process simpler for the standard documentation person. Docs get written, the clunkiness of the process gets abstracted away, and out the back end comes the CHM. Magic! The world forgets about HTML Help Workshop and uses products that work.

Fast forward a bit and along comes along .NET, with its fancy inline XML documentation comments. A stroke of genius, really - you can write your API doc along with the code it corresponds to and automatically create an XML document with that API documentation that can be transformed however you like.

For a very short period of time (relatively speaking), we were back to clunky, but before you know it, lickety-split, we have NDoc rescuing us. Not only that, but NDoc extends on the basic set of XML tags (sort of the way Netscape and IE "extended" HTML and ended up helping to shape the standard) to encompass common elements that get documented.

Anyone who is anyone uses NDoc. Seriously. We all use it, we all love it, it's the de facto standard for generated API documentation. The really cool thing is that not only is it simple to use by itself, but it's integrated into NAnt, so it can be automated in the build. It's The Way and The Light.

So we're in the Age of Not Clunky and chugging along great...

...until Microsoft trots up and chucks this... thing... out there called "Sandcastle" that they apparently use to render their own internal documentation. The community seems to want to latch onto this thing, but the truth of the matter is: it sucks. And you know why? We're back to clunky. It's just as difficult to use as HTML Help Workshop. Microsoft hasn't made a single step forward on the path to easy help generation, they just keep throwing half-baked tools at it.

For the record, I'm using the August 2006 CTP of Sandcastle as the basis for my statements. I've got some test classes that I have for CR_Documentor that I use to see if CR_Documentor renders the preview the way NDoc does. Today I got the Sandcastle docs building for my test classes so I could get started on the Sandcastle renderer in CR_Documentor.

Holy crap.

I mean, seriously.

First, it takes 12 steps to render a CHM out of Sandcastle, each step involving running a different command-line tool to transform this XML into that XML or compile this HTML into that CHM or whatever. In fact, the last line is a call to the HTML Help Compiler previously mentioned, so don't forget to have that installed.

Okay, so that's not horrible, and it can be automated, but one would think that the automation scripts would be part of the CTP. Unfortunately, not so much. The community has rallied and there are now upwards of ten different GUIs and scripts and tools to automate this thing, most of which will become obsolete when (if) we get something decent out of the Sandcastle team.

Let's ignore the bajillion step process for a moment, though. Let's instead look at the documentation they provided to help us get going and... what? What's that you say? No documentation provided?

That's awesome.

Okay, so bajillion-step-process and distinct-lack-of-any-sort-of-formal-documentation aside, what's really eating me here is the lack of out-of-the-box support for tags we NDoc users all sort of consider standard. For example, the <see langword="null" /> sorts of things that are strewn throughout documentation but are blatantly missing from Sandcastle.

I found a forum on this very issue and the recommendation from the Sandcastle team thus far is to modify the "main_sandcastle.xsl" file to add custom support for the tags.

Commonly used tags as a "custom extension" is a patently unacceptable solution. It's sort of like someone saying, "Yeah, we just came out with this new VCR, but only tapes from Maxell will play in it. In some cases you'll luck out, but in most cases you will probably have to do some extra work to fix the VCR so it'll play the rest of your tapes."

I've posted to the forum that I think they should support more out-of-the-box tags rather than sticking to the small subset that appear in the MSDN documentation. We'll see what comes of it. Right now I can't even get all of the standard tags to render right. For example, good luck getting a <list /> to render (which is one of the tags they actually list in the MSDN documentation as supported). I sure haven't succeeded. Sort of puts a damper on the CR_Documentor emulation since I have no idea where they're actually going to end up.

I guess I'm just irritated that such a big stir has been made over this thing and it's not all that great. I can write a set of utilities to do something and make it super cumbersome and not support common stuff, too, but somehow I don't think I'm going to get the level of community adoption we're seeing here. It's like they released an alpha level product and they maybe should have waited until it was at least beta before issuing a preview.

Maybe they should have a comprehensive list of what's done and what they plan to do and let us all see that so we can go, "Oh, hey, they might not support such-and-such now, but they will soon" or, "They think this feature's done, but it sure doesn't work for me." As it stands... it's just frustration.

I really do wish them well on it, but I think for now, I'll be sticking with NDoc.

myFairTunes6 v0.2b

I've been lamenting the fact that JHymn can't deal with the latest iTunes DRM. So much so that I haven't upgraded to iTunes 6 and have consequently been having odd crashes whenever I search the iTunes store. (Why remove the DRM? Because it locks me into only playing the songs I bought through iTunes - for example, the iPod support on Xbox 360 won't let you play protected songs, and I think I should be able to play the stuff I bought wherever I want.)

Seems there's potentially a new sheriff in town: myFairTunes6 v0.2b

Might have to get Stu to give this a go. (It's his turn to be the guinea pig.)

Pretty Cool Labor Day Weekend

Amp Big Rig (in the center)I had a pretty decent Labor Day weekend, but I'm tired this morning, so I'm drinking an Amp Big Rig, possibly the largest can of caffeinated beverage I've ever seen. Oh, hell yeah.

Friday night not a lot happened, or at least nothing of interest that I'm remembering right now. That's quite alright, though, as a quiet Friday night after a long week at work is just fine by me.

Saturday morning we were up bright and early and headed down to Wilsonville for the Hollywood Video warehouse sale. They opened the main office for a big previously viewed video sale where movies were between $2 and $6 each. We met my parents down there and good thing, too, because they got there far earlier than we did and got a decent spot in line. You should have seen the line! Unreal. And due to fire code, they could only let 100 people in at a time, so the line was moving sloooooow. But we got eight movies of varying cost for a total of $38. Not bad.

After that, we headed over to Fry's to see what was cool and new. I ended up getting MacGyver Season 1 for $20, which is a total steal.

We then headed to the mall to burn a little time and had someone comment on how they liked my shirt and someone else comment on how much better my car looked than theirs. Can't say the compliments didn't boost my ego a bit. Just a tad. I am the center of the universe! Okay, better now.

Didn't really do much at the mall. Walked around, looked at stuff we can't afford, etc. Had a little lunch, then headed over to pick up Jenn's dress from the bridal shop. After that, headed home and... watched movies. Woohoo!

Sunday Stu came over and we put in some units on Oblivion. Actually got several hours in on that and finished quite a few missions. On lunch break we went to get our tuxes measured for the wedding, so that's an item checked off the list of things to do. We all followed the units up with a Flavor of Love marathon (catching us up to current) and called it a night.

Monday was the downer of the three day weekend. I always have that dilemma on the long weekends of when to do the work that needs to be done. If you do it at the beginning, it sets a bad tone for the rest of the weekend. If you do it at the end, it makes you feel like you wasted the last vacation day available to you by doing work.

I fixed the stupid trim around the front door first thing. Of course, I had to sand the existing paint down to get rid of the majority of the brush strokes the painters left, which made the whole area dusty, so I got out the broom... and promptly fucked up the finish on the front door. I guess I figured the super-mega-paint they were supposed to use would hold up to a brush off with the broom, but not so. Well, nothing to be done about that now. You don't notice it from far away, but up close, it's there. Bah.

So, yeah, the trim got fixed. Then I went in and sanded down the tops of two doors in the house that wouldn't shut (or shut really tight, as the case may be). All doors work, now, but what a messy nightmare.

Jenn had some stuff to do at the mall, so I tagged along and ended up picking up Kameo Elements of Power for like $28, which is pretty decent for a 360 game. I tried the demo and it was OK, and after realizing I will never finish GRAW on hard mode, I thought it might be fun to get a new game. I have a few that I should probably play out on the online modes (I have the stupid Xbox Live Gold membership but somehow rarely actually get online) but just haven't done it yet. Maybe that will be something to do as the money gets tighter come holiday time.

Anyway, went to the mall, got the game, had some lunch... during which Jenn got something on her shirt, so we had to get her a new shirt at Macy's. Found the cutest little G-Unit shirt for her, totally on sale, so we got that. My little gangsta baby is hot hot hot. Then we headed to the theater and saw The Wicker Man.

That was pretty much the weekend. Not a bad one, if I do say so myself.

The Wicker Man

The Wicker ManJenn and I went to see The Wicker Man yesterday. While it doesn't seem to be soaring in the ratings on IMDB, I didn't think it was all that bad.

The premise of the movie is that Nicolas Cage is a cop who witnesses a traumatic accident. While he's taking some time off to get his head straight, he gets a letter from an old girlfriend (played by Kate Beahan) asking him to come to this isolated commune she lives on called Summersisle because she needs help finding her daughter. When he gets there, he finds that there are all nature of weird things going on and its up to him to figure out what the real story is.

I thought it was OK. I wasn't blown away or anything, and I guessed the twist at the end with about half an hour to spare. I also had an issue with Beahan's mouth the whole time - her lips are sort of weird (too large? misshapen?) and I had a difficult time concentrating on what she was saying when her mouth was moving. There was also this odd disconnect between the accident that Cage witnesses at the beginning of the movie and his arrival on the island. What relevance did that have? Was it just a mechanism to get him into convalescence so he would be receptive to getting the letter? A plot convenience? I'm still figuring that out.

That said, I've seen some pretty sucky movies lately, so I can't really bag on this one too bad. I think it'd be a decent rental, but you might not want to pay full price for it at the theater.

Interesting item I didn't know - it's a remake of a 1973 movie. Kind of makes me want to see the original to see if it's any better. It's got almost double the ratings as the remake, so maybe it's doubly good.