Archive for June, 2007

Multilingual data and NHibernate

20 commentsWritten on June 28th, 2007 by
Categories: NHibernate, Software Development

Some applications need multilingual application data. Not just the user interface, but the actual data. There are different ways of handling this. Some people provide extra columns in their tables for translated values. Obviously, that's a bad solution. Other people create an extra translations table for each entity that has translatable columns. Better, but all those extra translation tables really clutter the data model. I prefer to store all translations in one table. This can be cumbersome to implement, but the following approach with NHibernate actually makes it pretty easy to work with.

First, create the following tables and sequences (I'm using Oracle btw...):

CREATE TABLE languages
(
  languageid NUMBER NOT NULL PRIMARY KEY,
  "name" VARCHAR2(50) NOT NULL,
  isoname VARCHAR2(2) NOT NULL UNIQUE,
  isdefault NUMBER(1,0) NOT NULL,
  version NUMBER NOT NULL
);

CREATE TABLE translations
(
  translationid NUMBER NOT NULL PRIMARY KEY
);

CREATE TABLE translationvalues
(
  translationvalueid NUMBER NOT NULL,
  translationid NUMBER NOT NULL,
  languageid NUMBER NOT NULL,
  "value" VARCHAR2(4000) NULL,
  version NUMBER NOT NULL
);

ALTER TABLE translationvalues
  ADD CONSTRAINT translationvalues_uc_1
  UNIQUE (translationid, languageid);

ALTER TABLE translationvalues
  ADD CONSTRAINT translationvalues_fk_1
  FOREIGN KEY (languageid) REFERENCES languages (languageid);

ALTER TABLE translationvalues
  ADD CONSTRAINT translationvalues_fk_2
  FOREIGN KEY (translationid) REFERENCES translations (translationid);

CREATE SEQUENCE sq_languages;
CREATE SEQUENCE sq_translations;
CREATE SEQUENCE sq_translationvalues;

The classes look like this:

translations class diagram

and these are the mappings:

    <class name="Language" table="languages">
        <id name="Id" column="LanguageId" type="Int32">
            <generator class="sequence">
                <param name="sequence">sq_languages</param>
            </generator>
        </id>

        <version column="version" name="Version"
            unsaved-value="negative" generated="never"/>

        <property name="Name" column="Name" type="String"/>
        <property name="IsoName" column="IsoName" type="String"/>
        <property name="IsDefault" column="IsDefault" type="Boolean"/>
    </class>

    <class name="Translation" table="translations">
        <id name="Id" column="translationid" type="Int32">
            <generator class="sequence">
                <param name="sequence">sq_translations</param>
            </generator>
        </id>

        <set name="TranslationValues" inverse="true" lazy="false"
            fetch="join" cascade="all-delete-orphan">
            <key column="TranslationId"/>
            <one-to-many class="TranslationValue"/>
        </set>
    </class>

    <class name="TranslationValue" table="translationvalues">
        <id name="Id" column="TranslationValueId" type="Int32">
            <generator class="sequence">
                <param name="sequence">sq_translationvalues</param>
            </generator>
        </id>

        <version column="version" name="Version"
            unsaved-value="negative" generated="never"/>

        <many-to-one name="Translation" class="Translation"
            column="TranslationId" not-null="true"/>

        <many-to-one name="Language" class="Language"
            column="LanguageId" not-null="true"/>

        <property name="Value" column="Value" type="String"/>
    </class>

Alright, now it's time to actually use this stuff... Suppose you have a Product entity and the Name of the Product has to be a translatable field. The Name property of the Product class would be mapped like this:

    <many-to-one name="Name" class="Translation" column="NameTranslationId"/>

Creating a product with its translations is now as simple as this:

   IList languages = session.CreateCriteria(typeof(Language)).List();

   Product product = new Product();
   product.Name = new Translation();

   foreach (Language language in languages)
   {
      product.Name.AddTranslationValue(language, "Name in " + language.Name);
   }

   session.Save(product);
   session.Save(product.Name);
   session.Flush();

The Translation class has an indexer property which provides easy access to specific translation values so you could easily modify the translations like this:

  product.Name["en"] = "English Name";
  product.Name["nl"] = "Dutch Name";

This approach makes it really easy to work with multilingual data and NHibernate takes care of all the messy details for us :)

The Arrival

6 commentsWritten on June 27th, 2007 by
Categories: Off Topic

Well, the MacBook arrived today. A coworker of mine got his about a week ago and he advised me not to boot up the laptop until i'd given the battery a full charge cycle. It would only take about 4 hours. I don't know about you, but when i get a new toy like this i can't wait 4 hours to play with it. Nevertheless, i followed the advice and i charged the battery first. Luckily, only 90 minutes later it was fully charged and i was ready to play.

Everything worked out of the box and after downloading the latest updates (all 5 of them) i downloaded Parallels Desktop. This product is truelly amazing. It's like VMWare or Virtual PC except without the suckage. So i get ready to install my virtual copy of Windows XP Pro (or as i consider it, my shell for running Visual Studio) and Parallels offers me an automated XP install option. I simply selected the .iso file and let Parallels work its magic. 17(!!) minutes later i had an XP desktop running within my OS X session.

Now as most of you know, i can't stand Windows. There's something about it that quite frankly annoys the hell out of me. Once again, it's Parallels to the rescue. Enter "Coherence" mode. This allows you to hide the XP desktop and it nicely integrates your windows apps into your OS X session. I'm too lazy to create screenshots but if you visit the link earlier in the post you'll see what i'm talking about. Allright, what's next? Well it is Windows after all so we better get all the updates. Luckily, my install CD already had SP2 slipstreamed. So about 95 updates later (and no, that wasn't a joke...) i had a fully patched XP system. I then installed Visual Studio 2005 Professional and the MSDN documentation. So far, i'm extremely impressed with the performance of windows apps within Parallels. Overall, i'd say Parallels is definitely worth the $80. And there's nothing like setting up an XP system to make you appreciate OS X again. I really do have a newfound respect for Windows users now. The crap they willingly go through... simply astonishing!

Ok so that covers the Windows side of things. What about OS X? It ran very smooth on my 1.6Ghz G5 iMac, and it obviously runs even better on this 2.16Ghz Core 2 Duo. I know most of you aren't OS X users so i won't go into further detail about how cool it is. Sooner or later, you're going to experience this yourself anyway ;)

So what about the hardware? Well, the macbook itself looks gorgeous. The attention to detail is incredible and just looking at it makes you wonder why Dell can't even manage to create a laptop that looks halfway decent, let alone one that isn't downright laughable. When running, the machine is hardly audible. In fact, you really have to stress the CPU or put a CD/DVD in the drive to hear anything at all. The keyboard is a joy to use, and in my humble opinion it feels better than the macbook pro's keyboard. The screen is fantastic... at first i was a little worried that the glossy screen would be annoying, but so far it hasn't bothered me yet. I'm actually very impressed with it.

So all in all, i'm very happy with my purchase and i'd definitely recommend this laptop to anyone :)

A Brand New Classic

No Comments »Written on June 24th, 2007 by
Categories: Books, testing

I'm currently reading Gerard Meszaros' xUnit Test Patterns book. This book was released in the last month, but i think it's safe to call this book a Classic already. I think it'll be soon considered to be as influential as Martin Fowler's Refactoring book. Perhaps even more influential in a few years.

Either way, this is a must-read. It follows the same style as Refactoring, starting off with the narrative chapters followed by a list of 'test smells' and then the catalog of test patterns. If you're into test driven development or are just forced to write tests at your job, you should definitely read this book. If you're into TDD you'll appreciate learning a lot of new ways to improve the quality of your tests. If you're not into it but are forced to at work, you'll appreciate the material in this book for making your job suck less. Hell, this book might even convince you that TDD is indeed A Good Thing(tm).

Why you should write tests before code

1 Comment »Written on June 24th, 2007 by
Categories: Rants, Software Development, testing

It's often hard to convince developers to write tests before writing the actual code. At least one of my readers (Hi Stefan! ;) ) knows all too well how hard it was to convince me. I didn't really believe it would be that beneficial to our projects. I could not have been more wrong. These days, i'm very much convinced that writing tests before writing code offers many advantages. Not only does it improve the code, it increases the chance of a successful project and can make developers better than they already are. Nevertheless, there are still lots of highly skilled developers that don't do it.

So this is my list of reasons (in no specific order) why you should be writing your tests first:

  • It leads to developer-friendly API's. When you write the test, you're already the first user of your class. You'll automatically define an intuitive API simply because you're forced to think about it before you do anything else. This is one of the most underrated benefits IMHO.

  • If you do it right, there will be no unnecessary code. We've all been there... you're implementing a feature and suddenly you think of something else you also need to write. A lot of times, that something else you write turns out to be unnecessary. And code that shouldn't be there is a shame. The best quote i ever read about code was something like "code is not finished when there's nothing left to add, it's finished when there's nothing left to remove". I don't remember who originated it, but it's oh so true. This unnecessary code is just a waste of time. That code wasted time while it was being written, and it will continue to waste time everytime it is read. Think about that. How often have you spent time trying to figure out code and you weren't really sure if it was actually being used? If you write your tests, and then only write the code to make the tests pass you should be able to avoid unnecessary code. It's not always easy and it's a matter of discipline but it's really a goal you should be striving for.

  • It leads to better code. Code that is easily testable is usually flexible code. Flexible code is easier to change and improve. And the tests back you up while improving the code to make sure you didn't introduce errors.

  • It increases the skills of your developers. In more than one way actually. When developers write code, they make mistakes. Every last one of them. The sooner you learn about the mistake, the higher the odds that you'll avoid the mistake next time around. Some bugs aren't discovered until the system is already in production. Often, the developer that made the mistake is not around anymore. How is he gonna learn from the mistake then? He won't. If he has a test that will inform him of his mistake immediately after writing the code, he will have learned something. Just to be clear: i'm not saying that writing tests first will eliminate all bugs. It won't. But it should severely reduce them. Another area where the developers will improve is design. The more tests they write, the more they will learn about creating code that is easy to test. And if it's easy to test, it's easy to change thus indicating good design.

  • A code base that is the result of test-first development is a code base that can be modified in a safe way. It allows developers to confidently make changes to code. We've all been in the situation where you need to fix a bug, but you're affraid of changing the code because it's very likely that you'll introduce new bugs. If you have an extensive suite of tests, you should immediately know if you've introduced new bugs. This allows you to confidently make the change you think is the best one. Make the change, run the tests and if everything remains green, perfect! If it turns red, great! You'll know it was the wrong fix before your customers, your manager and your boss knows about it.

  • Writing tests first allow you to significantly reduce defects. You'll never write bug-free software. It's very important that you realize that. But you should at least try to minimize the amount of defects in the software you develop. If you write your tests first, you'll not only get instant feedback on newly written code, but you'll also be better protected against regressions in the existing code.

This list is far from complete... these are just the benefits that i can think of at the top of my head.

I'm probably preaching to the converted already, but at least now I can simply direct the uncoverted to this post instead of repeating the same thing over and over again :)

New theme

2 commentsWritten on June 23rd, 2007 by
Categories: About The Blog

It's only been a week and i'm already changing themes... The previous theme (ChaoticSoul) looked great, but it wasn't very good for displaying code. This theme (Simpla) is not as good looking, but does increase the readability. It's a nice theme though... nice and simple :)