22 August 2009

HTC Hero

A week and a bit ago I upgraded my phone (a Nokia 6120 - read the saga that led to me getting that one here) to the HTC Hero and thought I'd share my experiences thus far. I'd been following the progress of Google's Android OS for a while and really quite like the T-Mobile G1 but I'm on Orange with no plans to switch network so was pretty excited when I heard Orange were introducing the HTC Hero just in time for my contract expiring. The big screen, WiFi and GPS were plus points and, whilst I would have preferred a real qwerty keyboard like that of the G1, this being effectively the third version of that phone it should hopefully have a fair few bug fixes and refinements.

HTC HeroFirst off it comes in a pretty nice Apple-esque white box and after you've phoned the connections people and turned it on you're presented with a detailed and bright screen. Setup is straight forward and you're up and running in no time.

I should mention that I'm a pretty big user of Google services; Mail, Calendar, Docs, Reader are apps I use every day. I've blogged in the past about syncing my phone contacts with those held in Google Mail and it was great to not have to do the usual chore of copying all my contacts over from my old phone. Once I set up my Google account details in the Hero my contacts were all synced down - brilliant! What's better is that my calendar was now synced too which didn't work with SyncML on the old phone. My only criticism of this being that "My Calendar" in the phone is not the same as my "Derek Fowler" Google calendar - this isn't immediately apparent, in fact the two calendars even share the same colour coding, but if you add an event to "My Calendar" it's not synced up to Google. Once you realise this and pick the [your name] calendar that option remains selected and you can even hide "My Calendar" on the phone to make things clearer.

A really nice extension to the contact list added by HTC themselves is the ability to link phone contacts to their Facebook and Flickr accounts so that whilst browsing contacts you also get their Facebook updates, their Facebook profile picture appears in the contact list and Photo Albums on the phone will also browser your contacts Facebook and Flickr photos in addition to any you have stored on the phone. All in all some brilliantly functional Web 2.0 integration.

Google Mail on the phone is pretty similar to the app you can get for other handsets and, oddly, is separate to the actual "Mail" app. Admittedly GMail has features like Labels that you don't get with normal e-mail but still. Text messaging is presented nicely with messages between you and a particular contact appearing as a never ending conversation - something that really does make a lot of sense and I'm surprised it's taken handset vendors this long to think of it.

The browser on the Hero is excellent. It renders pages well and has multi-touch for zooming which is invaluable when you're browsing normal pages rather than those tailored for a small screen. A double-tap zooms in until the object tapped on fills the screen, double-tap again returns to the full page view - very similar to the iPhone browser.

One of the things that I've found to really let the Hero down is the onscreen qwerty keyboard. Whilst it's quite usable in landscape mode it just isn't big enough in portrait mode and, comparing it to the one on the iPhone you can instantly see it's considerably smaller. Thankfully there's the compact qwerty and phone keypad modes you can switch to which are usable, I've stuck with phone keypad.

Other let downs are battery life and the odd bit of lag. Initially battery life was pretty poor, being less than a day between changes however after a few full changes it's now up to about two days. Whilst it's not the two weeks I was used to with the Nokia it's okay considering the big screen and multitude of devices inside the handset. Lag wise it's most noticeable when switching from portrait to landscape mode however in general the phone is very responsive and what lag there is generally isn't enough for you to start getting impatient so that's good.

The Google Market is already full of a wide variety of apps and what's brilliant is that most are free. Highlights I've come across so far are:

  • AndNav - a SatNav app that uses OpenStreetMap maps, no 3D view but promising
  • beebPlayer - an unofficial BBC iPlayer app that supports both on-demand replay of old TV and radio shows but also live TV and radio!
  • Last.fm - streams your recommendations, friends, neighbourhood etc radio
  • Layar - augmented reality browser, shows you a view through the phone camera with markers pointing you in the direction of particular things
  • Google Maps - excellent use of the built in compass in Street View to allow you to look around as if you're in the place
  • Google Sky Map - similar to normal Maps it makes use of the compass to allow you to look around the sky, the app telling you what stars/constellations you're looking at and it even has a search function that will guide you to looking at the correct point in the sky for a particular object

Finally I have to mention one aspect that had me pleasantly surprised about the Hero. If you read other articles on this blog you'll gather that I'm a pretty big hi-fi nerd so I was very impressed when I plugged my headphones in to the Hero (via the 3.5mm jack) and had a listen. Sound quality is really excellent with an airy detailed delivery - I'd be willing to bet it would give most portable music players a good run for their money.

16 May 2009

The always-valid entity anti-pattern

Jeffrey Palermo wrote an article about the fallacy of the always-valid entity recently in which he highlighted that guarding against an entity becoming invalid by having validation logic in the setters of properties raises more issues than it solves.

Another way of enforcing an always-valid entity is, what I have found elsewhere termed, the "verbose constructor". Having a constructor which requires a value for every property, or every valid combination of properties.

public Car(string make, string model, string serialNumber, 
           decimal engineLitres, int maxPower, decimal urbanMpg, 
           decimal extraUrbanMpg, decimal combinedMpg, 
           int fuelTankCapacity) { ... }

Car myCar = new Car("Audi", "A4", "12345ABCD", 1.8, 120, 
                    28.5, 51.4, 39.8, 65);

The "verbose constructor" is itself a good candidate for an anti-pattern for the following reasons:

  • Modifying the entity means modifying every instantiation of it also
  • Forcing a programmer to set these values when they may not be available will result in garbage data which is useless anyway
  • Derived classes must call this verbose constructor either replicating every parameter in their own constructors or hardcoding values for some parameters (another anti-pattern)
  • Unreadable code, without help from the IDE it's difficult to identify each parameter

The method Jeffrey highlighted in his post has to use exceptions to catch validation errors, which forces a programmer to use another anti-pattern; exception handling. Where programming logic is implemented by the throwing and catching of exceptions. Any call to a property setter of the entity must be wrapped in a try...catch... block.

The always-valid entity, however it's implemented, seems to lead to a minefield of bad code. The thinking behind the need for this blurs the line between two important distinctions:

  • not setting a value vs. setting it to something incorrect
  • what makes an object a valid type vs. what makes an object valid for a particular use

I touched on the first of these before; where it may be the case that a programmer doesn't yet have a value for a particular property available yet. So long as we ensure the entity doesn't leak out in this invalid state we're okay.

Which leads on to the second item; we should guard against a value being set where that value violates the type e.g. setting Day to 32 for a DateTime, something bad has occurred and this is a real exception case. However, this is a much lower-level problem than enforcing business rules, for example where a credit card applicant's date of birth must be at least 18 years earlier than the date of the application. It could be the case that one company actually requires applicants to be 21 so hardcoding that type of validation into the class is not only restrictive but enforcing this by throwing exceptions is very inefficient.

The always-valid entity just serves to be very restrictive and limits the entity's uses in its current form. Validating from outside means that its easy to skip validation or make it more stringent when needed. Also, if implemented along the lines Jeffrey describes in his post, it means mechanisms have a common way of validating objects without needing specific knowledge of the particular object or the current validation being applied which makes for more robust code.

14 February 2009

OpenSession with connection disables second-level cache in NHibernate

I've has this post in my drafts for nearly a year now so I decided I'd finish it off.

I came across an issue when using the second-level cache in NHibernate where none of my objects were being cached and NHibernate was always going to the database for them. What was more odd was the NHibernate debug output suggested the items were being retrieved from the datbase and added to cache but on the next request the items couldn't be resolved in the cache.

Attatching a debugger and stepping through shows a timestamp passed into Cache's Put() method is equal to MinValue which makes it skip the Cache.Add at the last minute (whilst outputting debug messages to the contrary).

Tracking this timestamp back revealed it was created when the session is first openned and was due to my passing in my own connection string rather than letting NHibernate provide one. I assume this is a safeguard because IDs aren't necessarily unique between databases so in that case the cache would perform oddly.

If in your case they are however then you can work around this by casting your ISessionFactory as an ISessionFactoryImplementor. This has an extra overload of OpenSession which takes a IConnection and a ConnectionReleaseMode but doesn't disable the second-level cache.

07 January 2009

ISNULL vs COALESCE

Consider this SQL Server statement:

SELECT ISNULL(2, 2.0), COALESCE(2, 2.0)

You might assume, as I did, that they're equivalent and will produce the same result, however this is not the case.

They differ in the way they determine what data type to return. ISNULL always returns the data type of the first argument and the second argument must implicitly cast to that type. COALESCE on the other hand returns the data type of the argument with highest data type precedence.

As a result what you get out of the example above is:

22.0

The reason being that the constant "2" is treated as an integer while "2.0" is treated as a decimal. Therefore ISNULL will return an integer because the first argument is an integer but COALESCE returns a decimal because decimal has higher precedence.

One possible issue I can envisage here is if you were to inadvertently COALESCE a float column in with your decimals and then try to do some arithmetic. You'd end up doing dodgy float arithmetic where you thought you were doing safe decimal arithmetic.