Archive for September, 2010

Agatha 1.2 Is Available

9 commentsWritten on September 28th, 2010 by
Categories: agatha

Agatha 1.2 is now available... keep in mind that this version targets .NET 4 and Silverlight 4 only. The most important change in this version is by far the client-side caching support, but there are some other improvements as well. These are the changes that were made between 1.1 and 1.2:

  • Client-side caching (BREAKING CHANGE: EnableResponseCachingAttribute no longer exists, use the EnableServiceResponseCachingAttribute instead) -> this is not supported in the in-process model
  • RequestProcessor now has an AfterHandle(request, response) virtual method which is called after the request has been handled by the handler
  • ReceivedResponses now has a Responses property which returns all of the retrieved responses
  • ExceptionInfo now has a FaultCode property (string) which will be automatically filled in as long as your BusinessException type contains a FaultCode property (thanks to a patch from Huseyin Tufekcilerli)
  • Agatha.Spring has been included (thanks to a patch from Jernej Logar)
  • Agatha.StructureMap.Container has been fixed so that it instructs StructureMap to use the default constructors of RequestProcessorProxy and AsyncRequestProcessorProxy (thanks to a patch by Bart Deleye)
  • Added BeforeResolvingRequestHandler virtual method to the RequestProcessor which gets called right before a RequestHandler is resolved through the container
  • Fixed logging of WCF messages where some requests were logged as "... stream ..." (thanks to patch by Bart Deleye)
  • Added Agatha.Ninject.Silveright (thanks to patch by Bart Deleye)
  • Updated Agatha.Unity and Agatha.Unity.Silverlight to use the 2.0 version of Unity
  • Applied patch from Andrew Rea to improve REST support (xml and json)

Thanks to everyone who contributed to this release. It's very nice to see the list of contributors growing with each release :)

You can download the source code or the binaries here.

Review: Kindle 3

17 commentsWritten on September 26th, 2010 by
Categories: Books, gadgets

I ordered a Kindle 3 (WiFi only) on September 8th, and it was delivered last week, on September 22th. I've only had it for 4 days now, but i think i've done enough reading with it already to write a review of it. When i took it out of the packaging i was immediately impressed with its size. It really is that small and thin, though it's not too small or too thin. Its weight is ideal as well. Because of its ideal size and weight, you can easily and comfortably hold it for hours on end:

As you may have noticed from this picture (click on it to see it in its full size), the screen is really the killer feature of the Kindle. Text is crystal-clear, and remains that way even if you change your viewing angle:

Even when looking at it from the side, the text is still as clear as it would be on actual paper:

Most importantly, the impact of direct light on the screen is minimal. In the following picture, the camera flash was directed straight at the screen and IMO, the impact of it is minimal:

No matter what kind of light exposure you're dealing with while reading, tilting the Kindle slightly always leads to a fantastic reading experience. That is, as long as there is some kind of light. The screen itself doesn't emit any light so you can forget about reading in the dark. The clearness of the text and the fact that the screen doesn't emit any light are probably the 2 most important reasons why i like reading on the Kindle so much. You can simply keep reading for hours without your eyes getting tired. I had one stint where i read continuously for 5 hours and didn't notice any discomfort whatsoever. My eyes still felt great after those 5 hours, and because of its form factor, i could sit or lie on the couch in whatever manner i wanted to without the physical shape of the book constraining me in any way, sometimes simply by balancing the device with just one finger.

The only thing i'm not thrilled about when it comes to the form factor of the device is the location of the next/previous page buttons. They're located on both sides of the device, and while that is indeed useful depending on how you're holding it and what kind of position you're in at the time, it also caused me to press those buttons accidentally quite frequently in my first few hours of reading. By now, i'm used to avoiding those buttons unless i actually want to switch to another page, but in the beginning it was a bit frustrating though. Obviously, this is just a very minor complaint and for those who also have difficulty with this in the beginning, it'll only be for a few hours.

The battery also appears to be great... I've only used the device for 4 days, and even though i've used it a lot, i still have over 75% of battery life left out of a single charge. Obviously, the wonderful e-ink screen is the reason for this since it only consumes power while you're switching pages but once a page is displayed, it uses no more power whatsoever. Your battery usage will obviously vary on how often you use the wireless connection, or the 3G connectivity for those who've bought that edition.

So far for the great things about the device... now it's time to focus on some of the things that aren't quite great. First of all, reading PDF's really is a hit-or-miss experience from file to file. I only tried about 10 different PDF books, and none of them were displayed good enough to read them in portrait mode. In landscape mode, some of them looked good enough to read, while others are just acceptable. In those cases, i'm quite sure i can't keep reading them for hours and hours like i can with books in the native Kindle format. Converting them to MOBI format or having Amazon convert them to Kindle format leads to mixed results. While the actual text was then displayed almost as good as native Kindle books, you lose quite a bit of the formatting which is especially detrimental for programming books... code samples will lose most, if not all, of their indentation and become a pain to read.

As for technical books in the Kindle format, i haven't bought any of those yet, but i did try a few sample chapters of a few technical books, including ones that were listed as optimized for the larger Kindle DX screen. I found every sample to be of high quality (visually speaking) and am looking forward to reading all of my technical books on the Kindle from now on. In fact, i'm not really looking forward to finishing a few physical books i bought recently before ordering the Kindle. It would be cool if Amazon would offer free Kindle editions of physical books you've bought with them, but i don't see that happening since that would mostly be of major benefit to the consumer and publishers don't really seem to care about that.

Which brings me to my next complaint: why on earth is the price difference between Kindle editions of books and physical editions so small? In many cases, the difference is merely a few dollars. While i assume that Amazon takes a nice share of the profit for every electronic book purchase, i can't for the life of me imagine that that amount is comparable to the extra cost of producing and shipping physical books. The price difference should be bigger, given the fact that the cost of distributing electronic books can never even come close to the cost of producing and shipping physical books and let's not forget the positive impact on the environment of not having to waste all that extra paper. Surely, that ought to be worth something?

Another thing that's worth nothing is that the software of the Kindle feels very dated, and is somewhat clumsy to use. It's certainly not a big issue since the reading experience more than makes up for it, but every time i have to interact with the software i feel like i'm back in the 90's. Navigating the menu items or options with the '5-way' control, or navigating in the Kindle store is far from a great experience and it does occasionally make me sigh. Flipping through a bunch of pages is also a weird experience because it often makes me think "is it waiting for me to do something or am i still waiting for it to do something?". Finally, the included keyboard is so small that i doubt that you'll make heavy use of the annotations feature with this device. For me that's not an issue since the annotations feature doesn't interest me, but i can imagine that it would disappoint people who've bought it with the intention of making great use of that feature.

Now, despite some of the negative things i just mentioned, i'm still very impressed with this device, and i look forward to watching it improve in the editions that we'll hopefully see in the next couple of years. The reading experience more than makes up for any other shortcoming that you might find with it, and you can't argue with the price either. Amazon charged me 158 euros for it (which included shipping costs plus customs fees) which i think is a fantastic deal (well apart from the customs fees obviously, which i've always considered to be a rip-off). I was at an electronics store yesterday and strolled by their selection of e-readers from a variety of brands, and none of them impressed me after having used this. Even worse, pretty much every single device that i saw in that store was more expensive, looked more clumsy and had a screen that wasn't nearly as impressive as the Kindle's.

In short: if you're looking to buy an e-reader: get this Kindle. Odds are that you'll love it as well, and in the small chance that you don't: you'll have no problem selling it off to someone else who will.

Using NHibernate To Persist And Query Ruby Objects

5 commentsWritten on September 23rd, 2010 by
Categories: NHibernate, Ruby

As some of you already know, i've been experimenting with getting NHibernate and Ruby (through IronRuby) to play nice together. In this post, i'll go over what already works and how i got it working.

Suppose we have the following 2 NHibernate mappings:

  <class entity-name="Artist">
    <id name="id" column="ArtistId" type="int">
      <generator class="identity"/>
    </id>

    <property name="name" length="50" type="string" />

    <bag name="albums" cascade="all-delete-orphan" inverse="true" >
      <key column="ArtistId"/>
      <one-to-many class="Album" />
    </bag>
  </class>

  <class entity-name="Album">
    <id name="id" column="AlbumId" type="int">
      <generator class="identity"/>
    </id>

    <property name="title" length="50" type="string" not-null="true" />
    <many-to-one name="artist" column="ArtistId" not-null="true" class="Artist" />
  </class>

And suppose we have the following 2 classes:

class Artist
  attr_accessor :id, :name, :albums
  
  def initialize
    self.albums = System::Collections::ArrayList.new
  end
  
  def add_album(album)
    self.albums.add(album)
    album.artist = self
  end
  
  def remove_album(album)
    self.albums.remove(album)
    album.artist = nil
  end
end

class Album
  attr_accessor :id, :title, :artist
end

The only atypical thing about that Ruby code is the usage of System::Collections::ArrayList. That's something i haven't been able to workaround yet: if you want to use collections, you'll need to use the .NET ones for now.

I'm relying on 2 things to get everything working. One is NHibernate's Map EntityMode, the other is my own Ruby magic which i'll cover later. The important thing to know is that the Map EntityMode basically works without classes, but with dictionaries. Instead of instances of entity classes, NHibernate will return or accept dictionaries where the keys correspond to property names and the values correspond to their respective property's value. Though the goal was that the developer need not use the dictionaries directly, as the above 2 Ruby classes show. I'll get into the details of the Ruby magic later on in this post, but for now it's important to know that there's an ObjectFactory class which takes care of transforming the dictionaries that i get from NHibernate to either real instances of entity classes, or proxies of them.

First, let's take a look at transitive persistence:

    using (var session = sessionFactory.OpenSession())
    {
        var artist = ruby.Artist.@new();
        artist.name = "Rage Against The Machine";

        var album1 = ruby.Album.@new();
        album1.title = "Rage Against The Machine";

        var album2 = ruby.Album.@new();
        album2.title = "Evil Empire";

        artist.add_album(album1);
        artist.add_album(album2);

        session.Save("Artist", artist);

        session.Flush();

        artistId = artist.id();
    }

The output of running that code is this:

NHibernate: INSERT INTO Artist (name) VALUES (@p0); select SCOPE_IDENTITY();@p0 = 'Rage Against The Machine' [Type: String (50)]
NHibernate: INSERT INTO Album (title, ArtistId) VALUES (@p0, @p1); select SCOPE_IDENTITY();@p0 = 'Rage Against The Machine' [Type: String (50)], @p1 = 355 [Type: Int32 (0)]
NHibernate: INSERT INTO Album (title, ArtistId) VALUES (@p0, @p1); select SCOPE_IDENTITY();@p0 = 'Evil Empire' [Type: String (50)], @p1 = 355 [Type: Int32 (0)]

As you can see, transitive persistence is working nicely, even with collections. Now let's see how we can retrieve that data from the database and into our Ruby objects. First i need to show the following 2 helper methods for displaying the data:

    private static void PrintArtistData(dynamic artist)
    {
        Console.WriteLine("Artist: " + artist.name());
        PrintAlbumData(artist.albums());
    }

    private static void PrintAlbumData(dynamic albums)
    {
        foreach (dynamic album in albums)
        {
            Console.WriteLine("\tAlbum: " + album.title());
        }
        Console.WriteLine();
    }

Now we can get the artist we just created with a simple call to session.Get:

    using (var session = sessionFactory.OpenSession())
    {
        dynamic artist = ruby.ObjectFactory.create_from_nhibernate_hash(session.Get("Artist", artistId));
        Console.WriteLine("display output from session.Get");
        PrintArtistData(artist);
    }

And here's the output of that in the console:

NHibernate: SELECT artist0_.ArtistId as ArtistId0_0_, artist0_.name as name0_0_ FROM Artist artist0_ WHERE artist0_.ArtistId=@p0;@p0 = 355 [Type: Int32 (0)]
display output from session.Get
Artist: Rage Against The Machine
NHibernate: SELECT albums0_.ArtistId as ArtistId1_, albums0_.AlbumId as AlbumId1_, albums0_.AlbumId as AlbumId1_0_, albums0_.title as title1_0_, albums0_.ArtistId as ArtistId1_0_ FROM Album albums0_ WHERE albums0_.ArtistId=@p0;@p0 = 355 [Type: Int32 (0)]
        Album: Rage Against The Machine
        Album: Evil Empire

As you can see, the lazy loading of the albums collection works just as you'd expect it to. Speaking of lazy-loading, we can do the same thing with a call to session.Load instead of session.Get:

    using (var session = sessionFactory.OpenSession())
    {
        dynamic artist = ruby.ObjectFactory.create_proxy_from_nhibernate_hash(session.Load("Artist", artistId), "Artist", artistId);
        Console.WriteLine("display output from session.Load");
        PrintArtistData(artist);
    }

As you may or may not know, session.Load returns a proxy of an entity instead of actually fetching it from the database immediately (unless the instance is already in the session cache, which my current ruby code can't handle yet). NHibernate doesn't hit the database until you access any of the properties of the entity outside of the identifier, which the output of this code clearly shows:

display output from session.Load
NHibernate: SELECT artist0_.ArtistId as ArtistId0_0_, artist0_.name as name0_0_ FROM Artist artist0_ WHERE artist0_.ArtistId=@p0;@p0 = 355 [Type: Int32 (0)]
Artist: Rage Against The Machine
NHibernate: SELECT albums0_.ArtistId as ArtistId1_, albums0_.AlbumId as AlbumId1_, albums0_.AlbumId as AlbumId1_0_, albums0_.title as title1_0_, albums0_.ArtistId as ArtistId1_0_ FROM Album albums0_ WHERE albums0_.ArtistId=@p0;@p0 = 355 [Type: Int32 (0)]
        Album: Rage Against The Machine
        Album: Evil Empire

Notice that the select statement is outputted right before we access the name of the artist, instead of immediately as in the previous example.

We've got lazy-loading covered, but what about eager loading? Well, take a look at the following code:

    using (var session = sessionFactory.OpenSession())
    {
        var artistHash = session.CreateCriteria("Artist")
            .Add(Restrictions.IdEq(artistId))
            .SetFetchMode("albums", FetchMode.Join)
            .List()[0];

        dynamic artist = ruby.ObjectFactory.create_from_nhibernate_hash(artistHash);
        Console.WriteLine("display output from session.CreateCriteria without any lazy loading");
        PrintArtistData(artist);
    }

This fetches our artist and immediately joins its albums in the same query. When we access the albums of the artist, it no longer needs to go to the database:

NHibernate: SELECT this_.ArtistId as ArtistId0_1_, this_.name as name0_1_, albums2_.ArtistId as ArtistId3_, albums2_.AlbumId as AlbumId3_, albums2_.AlbumId as AlbumId1_0_, albums2_.title as title1_0_, albums2_.ArtistId as ArtistId1_0_ FROM Artist this_ left outer join Album albums2_ on this_.ArtistId=albums2_.ArtistId WHERE this_.ArtistId = @p0;@p0 = 355 [Type: Int32 (0)]
display output from session.CreateCriteria without any lazy loading
Artist: Rage Against The Machine
        Album: Rage Against The Machine
        Album: Evil Empire

Obviously, if we omit setting the fetchmode of the albums association we get the same output as we would get from using session.Get:

    using (var session = sessionFactory.OpenSession())
    {
        var artistHash = session.CreateCriteria("Artist")
            .Add(Restrictions.IdEq(artistId))
            .List()[0];

        dynamic artist = ruby.ObjectFactory.create_from_nhibernate_hash(artistHash);
        Console.WriteLine("display output from session.CreateCriteria with lazy loading of albums");
        PrintArtistData(artist);
    }
NHibernate: SELECT this_.ArtistId as ArtistId0_0_, this_.name as name0_0_ FROM Artist this_ WHERE this_.ArtistId = @p0;@p0 = 355 [Type: Int32 (0)]
display output from session.CreateCriteria with lazy loading of albums
Artist: Rage Against The Machine
NHibernate: SELECT albums0_.ArtistId as ArtistId1_, albums0_.AlbumId as AlbumId1_, albums0_.AlbumId as AlbumId1_0_, albums0_.title as title1_0_, albums0_.ArtistId as ArtistId1_0_ FROM Album albums0_ WHERE albums0_.ArtistId=@p0;@p0 = 355 [Type: Int32 (0)]
        Album: Rage Against The Machine
        Album: Evil Empire

Eager fetching also works in the other direction, when fetching albums with their artist included automatically:

    using (var session = sessionFactory.OpenSession())
    {
        var albumsList = session.CreateCriteria("Album")
            .CreateAlias("artist", "a", JoinType.InnerJoin)
            .SetMaxResults(5)
            .List();

        dynamic albums = ruby.ObjectFactory.create_multiple_from_nhibernate_list(albumsList);

        foreach (dynamic album in albums)
        {
            Console.WriteLine(string.Format("'{0}' by '{1}'", album.title(), album.artist().name()));
        }
    }

This results in the following output:

NHibernate: SELECT TOP (@p0) this_.AlbumId as AlbumId1_1_, this_.title as title1_1_, this_.ArtistId as ArtistId1_1_, a1_.ArtistId as ArtistId0_0_, a1_.name as name0_0_ FROM Album this_ inner join Artist a1_ on this_.ArtistId=a1_.ArtistId;@p0 = 5 [Type: Int32 (0)]
'For Those About To Rock We Salute You 2' by 'Accept'
'Balls to the Wall' by 'Accept'
'Restless and Wild' by 'Accept'
'Let There Be Rock' by 'AC/DC'
'Big Ones' by 'Aerosmith'

Finally, we'll retrieve our artist and modify some of its data:

    using (var session = sessionFactory.OpenSession())
    {
        dynamic artist = ruby.ObjectFactory.create_from_nhibernate_hash(session.Get("Artist", artistId));

        artist.name = "RATM";
        artist.albums()[1].title = "The Battle Of Los Angeles";

        artist.remove_album(artist.albums()[0]);

        dynamic newAlbum = ruby.Album.@new();
        newAlbum.title = "Renegades";
        artist.add_album(newAlbum);

        session.Flush();
    }

If we then run the following code again:

    using (var session = sessionFactory.OpenSession())
    {
        dynamic artist = ruby.ObjectFactory.create_from_nhibernate_hash(session.Get("Artist", artistId));
        Console.WriteLine("display output from session.Get");
        PrintArtistData(artist);
    }

We can see that the data has indeed been changed as it should:

NHibernate: SELECT artist0_.ArtistId as ArtistId0_0_, artist0_.name as name0_0_ FROM Artist artist0_ WHERE artist0_.ArtistId=@p0;@p0 = 355 [Type: Int32 (0)]
display output from session.Get
Artist: RATM
NHibernate: SELECT albums0_.ArtistId as ArtistId1_, albums0_.AlbumId as AlbumId1_, albums0_.AlbumId as AlbumId1_0_, albums0_.title as title1_0_, albums0_.ArtistId as ArtistId1_0_ FROM Album albums0_ WHERE albums0_.ArtistId=@p0;@p0 = 355 [Type: Int32 (0)]
        Album: The Battle Of Los Angeles
        Album: Renegades

Ok, so how does this all work? After all, NHibernate returns and expects dictionaries and as you can see in the code of the ruby classes, there are no dictionaries being used. The answer is actually pretty simple. NHibernate returns and expects dictionaries. I return and expect entity instances. Clearly, all we need to do is make sure that our entities pretend to be dictionaries and NHibernate will never need to know what on earth we're doing.

The first thing we need to do is to modify the implementation of the ruby classes that we have created for our entities. Obviously, i wouldn't want anyone to have to do that manually, so my ruby magic just does this at runtime. The only limit that is placed on the code you write in ruby is that within the entity classes, you can never touch the private instance fields of the attributes that you've defined. You always have to go through the accessors. Because of that limit, i can just replace all of the accessor methods with implementations that use the dictionary that NHibernate gives me as the backing store of the data instead of using instance fields. I also make sure that all equality checks are based on the underlying dictionary instead of the actual object. This passes everything but a straight-up reference check. Finally, we need to make sure that our objects can be cast to an IDictionary and that we implement the indexer property of the IDictionary interface because NHibernate will use that when we pass it transient instances to insert into the database.

First, let's take a look at the ObjectFactory class, which has a couple of class methods that we use from our .NET code to create entities based on the dictionaries that we get from NHibernate:

class ObjectFactory
  def self.create_from_nhibernate_hash(hashtable)
    entity_name = hashtable[NHibernator::TYPE_KEY_NAME.to_clr_string]
    entity = const_get(entity_name.to_sym).new
    entity.hydrate_from hashtable
    entity    
  end
  
  def self.create_proxy_from_nhibernate_hash(hashtable, entity_name, id)
    proxy = const_get("#{entity_name}Proxy".to_sym).new
    proxy.hydrate_from hashtable, id
    proxy
  end
  
  def self.create_multiple_from_nhibernate_list(list)
    entities = []
    # TODO: differentiate between proxies and normal entities in the list
    list.each { |hash| entities << create_from_nhibernate_hash(hash) }
    entities
  end
end

(as you can see from the TODO statement, this whole thing is still a work in progress)

Pretty simple stuff so far... We either create a new instance of the entity class, or of a proxy class for that entity type (i'll cover the creation of proxy classes soon). We then call its hydrate_from method, which is also added to each entity class dynamically. There's another (temporary) limitation here... i search for the class name constant in Object, which means that our current approach doesn't work when our entities have namespaces. Not really a problem for this example, and is easy to add later on when i actually need it. That's it for the ObjectFactory... the real magic is all contained in the NHibernator module. And no, i couldn't come up with a better name. Long-time readers should know by now that i absolutely suck at coming up with good names so that's why we ended up with the NHibernator module.

The NHibernator module does 2 things: it offers a method that you need to use when initializing your application so we can create the proxy classes based on NHibernate's metadata, and it also modifies the accessor methods and adds some new methods whenever it is mixed in to another class. I'm going to show the code of the NHibernator module in multiple steps to hopefully keep everything as clear as possible. First of all, i'm gonna show the declaration of a constant and a simple helper method that we're going to need:

  TYPE_KEY_NAME = "$type$"

  def self.each_writeable_accessor_of(klass, &block)
    setters = klass.public_instance_methods(true).select { |name| name =~ /\w=$/ }
    setters.each { |setter| yield setter }
  end  

The TYPE_KEY_NAME constant contains the string that NHibernate uses as the key in its dictionaries for the value which returns the current entity's type name. And the each_writeable_accessor_of method executes the given block for each writeable acessor that a class contains.

And this is how we initialize everything:

  def self.initialize(session_factory)
    all_class_metadata = session_factory.get_all_class_metadata
    
    all_class_metadata.keys.each do |key|
      metadata = all_class_metadata[key]
      realclass = Object::const_get(key)
      realclass.send :include, NHibernator
      create_proxy_class_for realclass, metadata.identifier_property_name
    end
  end
  
  def self.create_proxy_class_for(klass, identifier_name)
    proxyclass = Class.new(klass)
    Object::const_set "#{klass.name}Proxy", proxyclass
    
    proxyclass.class_eval do
      define_method identifier_name do
        @id
      end
      
      def hydrate_from(hashtable, id)
        @nhibernate_values = hashtable
        @id = id
      end
    end
    
    each_writeable_accessor_of(klass) do |setter|
      proxyclass.class_eval do
        define_method setter do |value|
          # execute the getter to force NH's lazy proxymap to fetch the data
          send setter.to_s.chop
          super value
        end
      end
    end
  end

The initialize class method takes an NHibernate ISessionFactory instance and retrieves each mapped entity with the information that we need about it. Each mapped entity's class is sent the include message with the NHibernator module as a parameter. This basically mixes in the functionality of the NHibernator module into each entity's class. I'll discuss this in the next part of the post. After we've mixed the module into the entity classes, we call the create_proxy_class_for method for each class. As you can see, creating the proxy classes is very easy stuff. Any proxy class that we create inherits from the class of the entity, and overrides the accessor method to retrieve the identifier value so that it immediately returns the identifier value. If we would've kept the default implementation, it would access the dictionary that we got from NHibernate, which would cause a select statement for this proxy to be issued, which we obviously don't want. Again, this is a work in progress and one limitation that this current proxy implementation has is that you'll get a reference to a dictionary instead of an entity when you access a reference-property of a proxy. That too will be easy to fix :)

Next up, we need to cover what happens when the NHibernator module is mixed into an entity class. Ruby has a great hook method for that, which is this:

  def self.include(base)
    # everything you do within this method will be executed whenever
    # this module is included in a class... the base parameter is
    # the class that included the module
    
    # ...
  end

I'm doing quite a bit within that method and i want to cover each item in detail. So, the next couple of pieces of code are all part of the self.include(base) method implementation. The first thing we do when this module gets included in a class is this:

    each_writeable_accessor_of(base) do |setter|
      getter = setter.to_s.chop
      
      base.class_eval do
        undef_method getter
        undef_method setter
        
        define_method getter do
          return nil if @nhibernate_values.nil?
          value = @nhibernate_values[getter.to_clr_string]
          return value unless value.is_a? System::Collections::IEnumerable
          # TODO: cache the WrappedList instance
          WrappedList.new(value)
        end
        
        define_method setter do |value|
          @nhibernate_values = System::Collections::Hashtable.new if @nhibernate_values.nil?
          @nhibernate_values[setter.to_s.chop.to_clr_string] = value
        end
      end
    end

This is pretty simple, we're just getting rid of all of the original accessor methods and replacing them with our own implementations that use the dictionary we get from NHibernate as the backing store. Note that i will discuss the WrappedList class that you see in those getters soon. The setter methods will also instantiate a new Hashtable if we don't already have a dictionary. This is necessary for transient instances since NHibernate will treat them as IDictionary instances when we pass them to the session. Speaking of which, this is the next thing we do:

    base.send :include, System::Collections::IDictionary

This single line enables any piece of .NET code to cast our instances to an IDictionary reference. Note that we haven't even implemented any of the IDictionary interface's methods yet. We don't need to implement all of them anyway, just the ones that we know will be used.

Finally, we add all of the following methods to each class that included this module:

    base.class_eval do
      def nhibernate_values
        @nhibernate_values
      end

      def hydrate_from(hashtable)
        @nhibernate_values = hashtable
        referenced_entities = Hash.new

        hashtable.keys.each do |key|
          value = hashtable[key.to_clr_string]
                    
          if value.is_a? System::Collections::IDictionary
            if value.is_a? System::Collections::Hashtable
              referenced_entity = ObjectFactory.create_from_nhibernate_hash(value)
            else
              type = value.hibernate_lazy_initializer.entity_name
              id = value.hibernate_lazy_initializer.identifier
              referenced_entity = ObjectFactory.create_proxy_from_nhibernate_hash(value, type, id)
            end
          
            referenced_entities[key] = referenced_entity
          end
        end

        referenced_entities.keys.each { |key| send "#{key}=", referenced_entities[key] }
      end
      
      def Equals(other)
        self == other
      end

      def GetHashCode
        hash
      end
            
      def ==(other)
        return false if other.nil?
        return @nhibernate_values.Equals(other) if other.is_a? System::Collections::IDictionary
        return false unless other.respond_to? :nhibernate_values
        other.nhibernate_values.Equals(@nhibernate_values)        
      end
            
      def hash
        @nhibernate_values.GetHashCode()
      end
                                                
      def [](key)
        self.send key
      end 

      def []=(key, value)
        self.send "#{key}=", value
      end      
    end

I think that code speaks for itself, except for the Equals and GetHashCode methods... those are just there because i had some issues with IronRuby mapping calls to Equals or GetHashCode to their corresponding ruby alternatives (== and hash). I eventually upgraded to the latest IronRuby revision from GitHub, because i didn't get correct results with the IronRuby 1.1 alpha 1 to get the equality checks working correctly.

Finally, i needed the following 2 helper classes to make the albums bag work correctly:

class WrappedList
  include System::Collections::IList
  
  def initialize(list)
    @list = list  
  end
  
  def each(&block)
    @list.each do |item|
      if item.respond_to? :nhibernate_values
        yield item
      else
        yield ObjectFactory.create_from_nhibernate_hash(item)
      end
    end
  end

  def GetEnumerator
    WrappedListEnumerator.new(self)
  end

  def add(item)
    @list.add item
  end
  
  def clear
    @list.clear
  end
  
  def contains(item)
    @list.contains item
  end
  
  def count
    @list.count
  end
  
  def remove(item)
    original_count = count
    if item.respond_to? :nhibernate_values
      @list.remove item.nhibernate_values
    else
      @list.remove item
    end
    original_count != count
  end
  
  def is_read_only
    @list.is_read_only
  end
  
  def index_of(item)
    @list.index_of item
  end
  
  def insert(index, item)
    @list.insert index, item
  end
  
  def remove_at(index)
    @list.remove_at index
  end
  
  def [](index)
    item = @list[index]
    return item if item.respond_to? :nhibernate_values
    ObjectFactory.create_from_nhibernate_hash(item)
  end
  
  def []=(index, item)
    @list[index] = item
  end
  
  def Equals(other)
    self == other
  end

  def GetHashCode
    hash
  end
            
  def ==(other)
    return false if other.nil?
    @list.Equals(other)
  end
        
  def hash
     GetHashCode
  end
end

class WrappedListEnumerator
  include System::Collections::IEnumerator
  
  def initialize(wrappedlist)
    @wrappedlist = wrappedlist
    reset
  end
  
  def reset
    @current_index = -1
  end
  
  def current
    @wrappedlist[@current_index]
  end
  
  def move_next
    @current_index += 1
    return false if @current_index >= @wrappedlist.count
    true
  end
end

And that's all there is to it. This is probably the longest blog post i've ever written, but the amount of code involved in getting this working really isn't that much. Granted, there are still limitations to this approach so some stuff will need to be added to it. I'm also not saying that this is actually a great idea or that you should start doing this from now on, but well, at least this is possible now :)

Keep Your Eyes On The Road

35 commentsWritten on September 18th, 2010 by
Categories: Opinions

There's been a lot of talk recently in the blogosphere and the twitterverse about the future relevance of Silverlight. Many people are questioning or debating whether or not it's a 'dead' technology considering how important HTML5 is going to become in the next couple of years. I don't think it's going to be 'dead' anytime soon, but i do think there are some very important factors you need to keep in mind before committing to develop new products in Silverlight.

I'd like to make it very clear that i'm not anti-Silverlight. A year ago i wrote a post called "5 Reasons Why Silverlight Is My Preferred Web Development Platform", which i hope will prevent the Silverlight fanbois from labeling me as an uninformed Silverlight basher. I've also never been a HTML/CSS/Javascript enthusiast so the things that i will say below aren't based on any preference for a certain technology or language. If anything, my current opinion on building Silverlight vs HTML apps is strictly based on observations of what's been going on on the web in the past couple of years, and how i've seen the software development community change gradually over the past few years.

One of the most important factors in your decision to use Silverlight or HTML/CSS/JavaScript for new products is the long-term strategic importance of the product. If the product you're going to build is not going to define the future of your company, your organization or your endeavor, then there's nothing wrong with going for Silverlight. There are a lot of benefits that come with choosing Silverlight and as long as none of the downsides are a problem for your situation, then it might very well make a lot of sense for you to build your product with Silverlight.

If however, your product is supposed to become the basis of your long-term success, then the choice of Silverlight over HTML/CSS/JavaScript is short-sighted and ultimately flawed for a number of reasons. The first of which is that Silverlight is a proprietary technology in the worst possible way. Its future will be determined by a single company who naturally hold their own best interest at heart, and not yours. As long as it makes sense for them to keep improving Silverlight, they will and you can benefit from that. As soon as it no longer makes sense for them, the technology will become increasingly irrelevant. Obviously, that is a risk that you face with any kind of technology. Sticking with open standards and open source software might very well result in the same outcome but there is one tremendously important difference here: with Silverlight, you have no migration path.

With Silverlight, your product runs in a browser plug in. It doesn't look like a normal website nor does it behave like one. You are forever tied to Silverlight in your client-side code. If you want to migrate to other technologies, which is not as uncommon or unlikely as you may think it is now, your only option on the client-side is to rewrite from scratch in a different technology. Depending on how much functionality your product offers, this might be a very large undertaking and it could take quite a while before you'll get any financial benefit of the large investment that this will no doubt require.

You might be thinking: well, i'm surely not expecting to migrate to other technologies, so your first point is moot to me. But consider this: over the past few years, we've seen an ever increasing popularity of a variety of open (as in: non-proprietary) technologies. I don't think anyone can reasonably argue that there's little or no truth to that statement. But i will make the following claim, which is something i'm sure many of you will disagree with: non-proprietary technologies tend to innovate and improve faster based on real-world requirements from developers who are using those technologies. Proprietary technology only improves and innovates when its proprietor has an incentive to do so. And what a proprietor considers to be an incentive to further improve a technology might not always correspond with what its real-world users truly need or are asking for. I hope i don't need to point out that Microsoft has a history of halting improvements/innovation in their products if they feel secure enough about a certain product's ability to generate recurring income.

By now i'm sure i've lost quite a few of you already. But i will go even further: a lot of developers are increasingly moving away from these proprietary technologies in favor of open technologies. Well, at least the developers that truly matter. They yearn for continuous improvement in not only their own skills but in the technologies that they choose to use as well. I obviously expect more and more developers to start looking at non-proprietary technologies for exactly that reason. I'm not saying that will happen this year, or next year or even the one after that. But i do think that there will be a strong shift towards non-proprietary technology about 5 years from now. And again, keep in mind that i said that it's important to consider all of this when your product is your basis for success in the long-term. And again, there is no migration path when you choose Silverlight and i don't expect that there ever will be one.

There are two more important things to keep in mind. How many success stories have you seen in the past couple of years that were based on proprietary technology outside of the enterprise systems space? There are only 2 that i can think of. The first is iPhone/iPad development. Objective-C might not be truly proprietary, though in practice it does turn out to be so. The operating system is also proprietary. Yet neither of these has prevented or had a noticeable effect on the success of iPhone/iPad development. The second example is YouTube which is (or at least was for a long time) dependent on the proprietary flash plug in. If you have other examples, please leave a comment to mention them because i'd really like to know. On the other hand, i think we can all name quite a few really successful sites and products that are based on non-proprietary technology, no? This is inherently related to what i mentioned earlier about developers that matter moving increasingly to non-proprietary technology.

And last but not least, you need to think in terms of 'devices'. The success of the iPad is a fantastic example of how important the 'device'-story of your product is, or at least will surely become. Websites built in Silverlight or Flash don't work on the iPad. Yet, the iPad is a hit. People love using it and are using it for a variety of things. Products that were based on HTML/CSS/JavaScript worked on the iPad without their creators even having to think about supporting a device like the iPad. They just work. And they work on smartphones as well. Gone are the days were the internet is solely used from computers and laptops. Mobile devices will become an increasingly important market and it would be unwise for anyone to base their long-term success on a technology that has such hard limits as to what kind of device the user must use in order to be able to use your product.

If you're going to build a product for the long term, you're undertaking a journey. And in any journey, it's important to keep your eyes on the road because you can never know for sure what will or what won't happen during that journey. You do not want to be forced to a sudden standstill because you weren't paying attention. Nor do you want your vehicle at some point in the future to prevent you from following the direction you need to follow.

Highly Recommended Book: Metaprogramming Ruby

No Comments »Written on September 12th, 2010 by
Categories: Books

One thing that you'll see popping up frequently as you're learning Ruby is the word 'metaprogramming'. But what exactly does it mean? Simply put: metaprogramming code is code that dynamically enhances/modifies the behavior of your classes and even single objects. There are a lot of very cool things you can do in Ruby thanks to metaprogramming and it's probably one of the biggest reasons why a framework like Rails is able to deliver such tremendous productivity gains. Which means it's definitely a topic worth learning about, which is why i picked up Paolo Perrotta's Metaprogramming Ruby book.

As you can imagine, some of the concepts that you'll have to learn about to apply metaprogramming techniques effectively are somewhat advanced (or at least, they appear to be at first). Paolo does an extraordinary job of explaining all of this in a very easy to grasp manner. The writing style is clear and very easy to follow. There are some parts that you might need to read twice (or thrice) before you get it, but that's more due to your mental conditioning from static languages than it is because of Paolo's writing.

The book is divided in 2 parts (well, 3 if you count the appendices). In the first part, you'll learn everything there is to know about metaprogramming. You're going to learn all about how objects and classes (which are really just objects) work in Ruby, and you'll explore a variety of ways of changing or extending existing classes and objects. You'll get a full grasp on Ruby's object model and you'll see how you can use that knowledge to your advantage.

In the second part, you'll see how metaprogramming is used in various Rails libraries. But don't worry, you don't need to know Rails to get value out of this part. It just shows a lot of real-world examples of the tricks and techniques you learned in the first part of the book and it very well might fill your head with ideas of stuff that you want to do as well (i know it did for me). You'll also find some good advice on how to apply metaprogramming safely. There's a lot of power in metaprogramming, and you're going to feel the pain if you go overboard with it. Follow some of Paolo's advice and you might avoid or at least minimize that pain :)

The second part closes with a redefinition of the metaprogramming concept. Paolo does a good job of making clear that metaprogramming really is just, well, programming. It's different from 'regular' programming, but it's still just programming. It's the kind of programming that truly leads to less repetitive programming.

If i had to describe this book in one word, i'd go with 'fascinating'. It's eye-opening, highly informative and fun to read. It'll inspire you to change the way you write your code and the perspective you'll gain on OO topics that you already thought you knew well is just invaluable.