Today a friend woke me up by phone wanting to ask me how to best do internationalization (i18n) in .NET. He already had read some guides that involved compiling satellite assemblies with global resource files etc, and that didn’t work all that well. My first thought went to that article I had read half a year before when I was tasked with i18n, and I tried to remember how I did it back then.

I remembered: I didn’t.

At no point in time was the scope of the application so big that it had warranted to jump through the hoops Microsoft hat set up to get to real internationalization. If you Google for the thing or ask on StackOverflow, you realize rather fast that you don’t want to have any of this i18n “goo” in your application logic, so the smartest thing is to simply abstract everything away into a separate class that handles all those things.

And once you have it abstracted from your application, nobody forces you any more to use the .NET i18n stuff any more. Simple switch statements will do if you only need 2 languages for a couple of strings, even reading something on the Globalization stuff from .NET takes longer than simply writing something similar to this:

Now, the only trouble here is to fill that dictionary with values, and that can even be simply hardcoded into the application.
To further facilitate the use of this you can now write Facades for your languages like this:

Also mind that since everything follows a rather simple Interface I can easily change these implementations later if I need to. But for something simple, this will do just fine.
Also I advise to use this through an IoC container like Windsor so you could even go as far as to swap hardcoded translations through the configuration.

Note the StringComparison.OrdinalIgnoreCase that makes this ignore casing.
Now, the catch here is that Sqlmetal (the thing that magically generates Sql from the expression tree), can’t translate IndexOf into Sql and you’ll get an exception.

So, we’re screwed right? :)
Yes! We are, since Contains is not marked as virtual we can’t just subclass List<string> and override the behavior of Contains (assuming we could interfere with the objects creation through some factory). We are bound to write different code for querying Linq2Sql and Linq2Objects. That’s what I call a rather leaky abstraction.

Yes, it’s that simple. I have an Image and I want to modify the behavior of the Url getter method for it (I can’t compose the URL string inside a Linq to Sql expression since I’d have to call a resolveFileType method that can’t get translated into SQL). So, I figured the best way to solve that problem is to have a subclass with a custom implementation of Url to handle that. I supply the required information through the ctor and when called the Url gets composed. The general idea is to assign an BoxImage to an Image field, hiding the custom implementation from the rest of the code.

Since I had not marked my fields as virtual I could not override them, I thought just writing new would do the job. That failed miserably.

Actually, the new keyword does not hide the base classes method. Instead, a new method gets created that lives only on the derived class and that won’t get called if you are calling the base type.

The unit test should be self explanatory, only if the type that gets the call is actually a BoxImage the new method will get called, if not, the base implementation will get used and your polymorphism goes out of the window :).

Doing this right would require the Url method to be virtual so you can properly override it:

Oh, and by the way. If you got the impression I don’t know about the fundamentals of the language I’m using, you are right. I try to learn as I encounter the problems, one feature at a time, one minor annoyance at a time :).

When your dbml designer shows an association, you’d expect to be able to traverse it in code don’t you?

So, funny thing. The Post entity lacks a “PostTags” Field that should be there according to the designer.

After a few minutes of tinkering, I realized that PostTag has no primary key of it’s own. Since in my real application it’s a m:n association table and no entity on it’s own I didn’t use a primary key. But apparently Linq to Sql needs a primary key to work with, so once I changed the table to have a PK magically a PostTags field appeared:

Once again I get how “version 1” Linq to Sql really is, but sadly there won’t be a version 2 since Microsoft is now pushing all resources towards the Entity Framework.

Why not EF? Too complex, once I reach a level of complexity that would justify the use of EF, I use NHibernate. What I need out of Microsoft right now, is some Linq enabled ORM that’s dead simple with a very DB-centric view that works. Something like Linq to Sql v2.

I’ve been using Google reader for a very very long time now, and it’s besides Gmail one of the most important tools out there for me to stay informed. I don’t read newspapers, I don’t read blogs directly, I only stop once in Gmail and once in Reader.

The only thing I really consider “missing” from Reader is some way to declare a rule that Reader should never mark a feed as “unread”.

Why? Simple: Many online newspapers and sites give out full-text feeds and I subscribe to them to occasionally read some articles. But, in case of sites like Engadget or Gizmondo, there is no way you can keep up with 30+ posts per day and still do work in between reading. So, my “News” folder in Reader grows pretty fast to 1000+ unread items and I have to go in and mark them all as read every now an then.

I consider those feeds as a constant stream of information, so I don’t want Reader to track their read/unread status. If I’ve got free time I go in there to see what’s going on right now, while most of the time I simply ignore those feeds.

A very long time ago I went through the Ruby in 20 minutes tutorial when I saw this:

@names.each do |name|
puts "Hallo, #{name}!"
end

When C# came out later I always wondered why there is no functional equivalent on the IEnumerable<T> interface, since it would be a perfect place for quick inline method calls without having to write a full foreach statement.

At that time my knowledge of extension methods and delegates was too limited to do this myself, but that doesn’t mean it has to stay that way.
I finally remembered that I never got to it last time and implemented it today.

I shipped a accounting application in January and got asked to implement some new features into the software lately. That customer I worked for on that project was absolutely amazing, we really found a common ground to communicate about the needs of the business and my implementation of it. I tried to apply domain driven design as much as possible, and it really worked out exceptionally well. The customer now has a basic knowledge of what I’m doing and how I’m doing that, while I understand most of his business needs and how to translate those to code.

The dark side of this is that the customer now started to use the system in ways I never intended it to because he knew how to achieve his desired output.

For example, the system has no built-in support for selling set-products. Meaning that buying 1 meta product actually is selling 5 different products for a different set-price.

We once briefly talked about that feature, but neglected it to get more important stuff done, and it never came up since then.

Turns out, the customer implemented that feature himself, by creating a product representing the set, and whenever selling it, he added the set and the 5 sub products to the order. Changing the price of the 5 sub products to zero caused the bill to appear right while still removing the items from storage.

This bit me yesterday when I was asked to implement another feature did some calculations that aren’t based on the actual sell price of the products but on their base price. This screws my complete calculation because now that data is indistinguishable from another kind of data in the system that has to be treated differently. So I end up with a new type of sale that the system has no means of identifying (without doing some rather complicated and error prone rule matching stuff I want to avoid).

Now, a rather trivial feature has turned into a major system refactor since I need to re-implement the set functionality and some creative ways how to fix the old sales to reflect that change.

Time I would have rather spent working on other things, instead of running with scissors :).

Watch out for how you communicate with your customers and make sure they tell you anything about the system and their intended uses. If you give them enough power through the UI, they will start to fill in bogus values to achieve their business needs without you knowing.

I guess my laptop is officially broken. I am currently digging for my Dell Support CDs to reinstall Vista on it, but I don’t really think that will help at all(except with the Dell support people).

I do credit the crashes to my hardware simply because I’ve been a Vista user on multiple machines since day 1 and know how rock solid the OS really is. I suspect the mainboard of my laptop to be faulty in some way.

The funny thing is (besides that my laptop fails to boot 50% of the time), I am still doing active development on that machine. It works, I see some weird errors sometimes, but I can still work normally on the system once it’s booted.

Today is one of those days where I really expect UFOs to land or drunk reindeers to drop some white bearded guy off at my doorstep. It can’t possibly get any worse does it?

First thing I look out of the window to see everything covered in snow right when I’m already late to an appointment, then I finally realize that my laptop is broken.

Now, back at home I went up to the attic where I keep all hardware boxes I acquired during the last 10 years and searched for the DELL OEM support CDs I got with my sweet little laptop.

Guess what? Nowhere to be found.

Turns out, my little brother bought himself a Dell Inspirion 1530 Laptop some time ago. When the Laptop came it turned out that it lacked the required GPU power (they just switched the 15XX series from Nvidia 8600M to ATI X1330 graphics) so he sent it back and got a refund on his money.

Now, what also happened was that my Laptop box was lying around right next to his laptop box on our attic, so when he repacked his laptop to send it back, he accidentally packaged it in my box. So, not only did that box contain all the packaging material I keep around in case I need to send stuff back, no it also contained all driver and support disks (and the bundled Creative Headphones I got with the XPS).

So now I’m really screwed in a way because I am having trouble with a Laptop that is running Windows 7, I have no way of restoring it to Windows Vista, and I have to explain to Dell that the problem is not caused by Windows 7 because it also was there when I used Vista.

Oh, and while at it. I can’t find the bill and shipping notice for my laptop at the moment. What a great day. I wish I had given in to that voice in the morning telling me to stay in bed because I felt sick.