Tuesday, December 26, 2006

Zune - My Thoughts

Zune-blackI received a black Zune for Christmas, despite it’s lackluster sales and reviews by some.

I resisted getting an iPod for the longest time, because I wouldn’t buy into the hype.

I compared a number of features to decide between a Zune and an 30gb iPod Video.

Screen Size – The Zune has a very large screen compared to the iPod.  For video you turn it sideways for a widescreen view, and it makes watching movies very do-able.

Interface – Call me crazy, but I’m not too fond of the iPod interface.  When I used the iPod Video at the Apple Store, I was immediately annoyed that it asked me every time if I wanted TV on or TV off when I clicked on a video.  The TV wasn’t even connected!  For a company so anal about usability, making the users make a redundant and unnecessary choice before showing videos is a no-no.  The interface for the Zune is easy to use and the buttons make sense.  The iPod isn’t bad, I just don’t care for it very much.

Wireless – I originally thought this was one of the coolest features of the Zune.  It uses standard WiFi to transfer data between 2 Zunes, however it doesn’t connect to my wireless network at home, which is a disappointment.  I don’t know anybody that has a Zune, so I haven’t yet tried out the Social aspect of it.  There are hacks that allow you to transfer a file unlimited times between Zunes wirelessly, but it involves registry hacks on the host computer, and renaming the file as an image.  That makes it pretty much useless because I have a usb thumb drive in my pocket that can do the same thing easier.

Podcasts – I’ve become addicted to a number of podcasts, some with video, so I wanted good podcast support.  I was disappointed to find that the Zune has almost NO notion of podcasts.  Sure I can point the Zune software (which sucks, more on that later) to a folder where I download podcasts, but they don’t live in a separate section on the Zune.  I hope Microsoft fixes this in a future firmware update.  iPod / iTunes wins on this hands-down.  I’m currently using uTorrent for BT feeds, and Doppler for video/audio feeds.  These go into my podcasts folder which gets picked up by the Zune software.  The video has to be re-encoded to the Zune format, which is annoying.  I would think that WMV would be playable out of the box.

Video – I originally dismissed Video as excessive in a portable player, but now it’s my favorite feature.  I have a lot of downloaded tv shows, and I plan on putting them on the Zune to watch while I work out.  I ride an exercise bike to strengthen my leg and I can easily watch a TV show in that time.  The problem I see now, however, is that my shows are in Divx or Xvid format, which I have to re-encode using Any Video Converter to AVI or MPEG, then it has to be encoded again in the Zune format.  I’m hoping this process gets easier, or that the Zune will support Divx in the future.  One thing that would be nice is if I could encode video before I’m ready to sync.  I find it annoying that I have to surrender my Zune for at least 30 minutes if I need to transfer a couple diggnation episodes.

Music – This is a no-brainer for most MP3 players.  Both the iPod and Zune have excellent usage in terms of usability.  I like the large album art that is displayed during playback on the Zune, though I hear the new iPods do this as well.

Size – The iPod wins in this category.  The Zune is about 1/2” thick, which is quite large.  The iPod is about 1/4” thick, so it’s twice as thin.  I decided that the other features were worth the trade-off in Size.

PC Software – The Zune software sucks.  Big time.  It reminds me a lot of iTunes, but it doesn’t really deliver.  I ignore the Marketplace, so for me it’s just a mechanism to transfer files over.  I’d like to use MediaMonkey, but it’s not supported yet.  I found a few mistagged files while listening to music on the Zune, so I flagged them.  They showed up in my Zune “inbox” the next time I sync’ed.  From there it shows me the file, but it doesn’t let me edit the tags!  How stupid is that?  The only option I have is to delete the file and look at Properties, which is useless to me. 

The Zune software also has zero support for subscribing to podcasts, let along distinguishing my podcasts between regular music aside from Genre.

Audiobooks – I haven’t yet tried listening to an Audiobook, however I plan on it.  I listed to the Da Vinci code about 8 months ago and I loved it.  I’m hoping that it will be easy to listen to Audiobooks.

All in all, you can’t go wrong with an iPod or a Zune.  Both are fantastic devices, and I am very happy with my Zune.  I hope for a few improvements via firmware soon, but it’s a new device and I think Microsoft will catch on soon.

Now, the question is… do I attempt the 80gb mod?

Christmas with Family

Silvia’s family is in town, and it is a lot of fun to have so many kids in the house.  They (9 people) drove down from upstate New York.  It took them about 23 hours driving time and they were very tired when they arrived.

On Christmas Eve, we all spent about 4 hours wrapping gifts and talking over coffee.  It was fun, but we were all exhausted.

We had presents for all of the children, and it was quite a sight!  We probably had 80 presents under the tree.  The morning arrived and the kids went crazy!  There was wrapping paper everywhere, but I think everyone enjoyed their gifts.

I received a Zune from Silvia, which I will write about next.

Silvia’s family will stay for our wedding, which happens this Saturday.

Thursday, December 14, 2006

A Journey with Domain Driven Design (and NHibernate) - Part 8

We left off last time with our first association mapped and tested.  Let’s dig in a bit deeper with NHibernate mapping. 

Today I decided to separate my inherited classes into their own mapping file.  This was as easy as creating the new files and <hibernate-mapping> root elements, copying the <joined-subclass> elements over. 

I created the Item.hbm.xml:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0" assembly="Flux88.Videocracy.DomainModel" namespace="Flux88.Videocracy.DomainModel" default-lazy="false">

  <class name="Item" table="Items">

    <id name="Id" column="itemId">

      <generator class="identity" /> 

    </id>

 

    <property name="Name" not-null="true" />

    <property name="Upc" not-null="true" />

 

  </class

</hibernate-mapping>

and Video.hbm.xml:

<joined-subclass name="Video" extends="Item" table="Videos">

    <key column="itemId" />

 

    <many-to-one name="Movie" class="Movie" column="movieId" />

    <property name="Format" type="Int32" column="videoFormatId" />

 

  </joined-subclass>

In the video mapping, you can see how it inherits from the Item class.  If you recall back to where I explained how inheritance works, you can see it in action here.   Each video will have it’s Name and UPC stored in the Items table, and the Format and MovieId in the Videos table.  The Movie.hbm.xml is below:

  <class name="Movie" table="Movies">

    <id name="Id" column="movieId" access="nosetter.camelcase-underscore">

      <generator class="identity" />

    </id>

 

    <property name="Name" not-null="true" />

    <property name="Year" not-null="true" />

    <property name="VideoReleaseDate" not-null="true" />

 

    <property name="Category" type="Int32" column="categoryId" not-null="true" />   

 

  </class>

This should give you an idea on how to map your entities.

I also did a little refactoring on the naming of my classes.  I didn’t like the naming of VideoGame because I thought it was better represented as a GameTitle.  I also renamed Transaction to RentalTransaction.  This will help avoid confusion when talking about database transactions.  I realize that not everything will be a rental (obviously most video stores also sell movies and candy, etc) but this name will suffice for now.  Since I am backed up by tests, I can refactor often and with complete confidence that I haven’t broken any old code.

So let’s revisit our feature list

  • Add new Customer / Account
  • Add other members to an account
  • Restrict Certain members from renting certain content
  • Query for a customer by customer # (swipe card, etc), phone number, or last name
  • Add new rental item (move game, console, vcr, etc)
  • Rent an item to a customer
  • Check Items Back in
  • Get movies checked out for a customer
  • Query for an item, see who has it

Some of the remaining things on the list involve querying, so we’ll create a class to assist in that.  Listed below is the overview of a class called Repository.  

CropperCapture[5]

Repository takes advantage of generics to avoid a lot of duplicate code.  This is a quick implementation of the Repository pattern, you’ll find more in-depth implementations in Ayende Rahien’s Rhino Commons and Dave Donaldson’s NHibernate Repository.  The main point here is that we can abstract 90% of NHibernates functionality in an easy to use class.  If we need to do something complex, we can either expose some more methods here, or we can expose the session to the rest of your project.  This is a design choice that is really up to you.  I generally choose to hide NHibernate from UI developers, especially junior developers.

I provided some static members for just retrieving data, however to save data and participate in transactions, I created instance methods.  This class will serve most all of our data access needs.  It is the single communication point with our persistence layer to the presentation layer.

One side-note.  I have not written any tests for this class (shame on me!).  I find it difficult to test it without duplicating what I have already done with the integration/persistence tests.  I imagine that I could use a mocking framework like NMock or RhinoMocks, however this would distract from the series and frankly I am not very skilled at mocking.  If someone would like to inject a few words about this in the comments, I’d love to hear them.

Ok, back to our list.  I’ll tackle Restrict Certain Members from renting certain content.  This basically means that minors shouldn’t be able to rent rated R movies. 

The ratings for our items apply not to the items themselves, but to the Movie and GameTitle classes.  So to validate that the customer can rent one of these items, we must inspect the rating.

A naïve approach would be like this:

public void AddRental(Rental r)

{

    //don't allow the same rental to be added twice

    if (_rentals.Contains(r)) return;

 

    if(r.Item is Video)

        if(!((Video)r.Item).Movie.Rating > _customer.RentalRestriction)

            throw new ApplicationException("Customer cannot rent this movie.");

 

    if(r.Item is Game)

        if(!((Game)r.Item).GameTitle.Rating > _customer.RentalRestriction)

            throw new ApplicationException("Customer cannot rent this game.");

 

    _rentals.Add(r);

    _subTotal += r.RentalPrice; 

}

 

The bold portion is what I added to check for the rating.  This code should never see the light of day.  Each new type of item needs another cryptic if statement here.  A better solution is to use the Template Method design pattern.  We’ll leave it up to the item to setup a construct for verifying that rentals are allowed.

By default, we won’t restrict rentals.  In the item class, we’ll provide a virtual method that returns true always.  Inherited classes can make their own decisions by overriding the method.

public virtual bool CanRentFor(Customer customer)

{

    return true;

}

In our Video class, we need to base our decision off of the Movie’s rating.

public override bool CanRentFor(Customer customer)

{

    return _movie.Rating <= customer.RentalRestriction;

}

In our Game class, we need to base the decision on the GameTitle’s rating.

public override bool CanRentFor(Customer customer)

{

    return _gameTitle.Rating <= customer.RentalRestriction;

}

unit test results

For another Item we might create, say Console, we can choose to accept the default behavior or write our own.  This will ensure that certain customers do not rent items that they are not allowed to rent.

I’ve added a few tests and ensure they are passing.

Now I’ll switch gears and look at the next item on the list, which is Can Query for Account by # (swipe card) or customer phone number.  This requirement will allow us to bring up the customer’s account when they are at the counter.  We would normally extend this requirement to add many more search options, however to be brief, we’ll just implement the two of them.

For this we can make excellent use of the Repository class we wrote earlier.  This test will involve the database, so we will place it in the Persistence test project.

 I want to keep the database related code out of the DomainModel class.  I created a class that can hold any of our queries for us.  This way we keep a clean separation between the model and persistence.  Remember, we cannot have a dll reference to the persistence project in the domain model project.  (This would lead to circular references – not to mention a bad design idea).

Here is the AccountFinder class:

public class AccountFinder

{

    Repository<Account> _repository;

 

    public AccountFinder(ISession session)

    {

        _repository = new Repository<Account>(session);

    }

 

 

    public Account FindById(int id)

    {

        return _repository.Session.Get<Account>(id);           

    }

 

    public IList<Account> FindByCustomerPhone(string phone)

    {

        string hql = "SELECT a FROM Account a JOIN a.Members c WHERE c.HomePhone LIKE :phone";

        IQuery query = _repository.Session.CreateQuery(hql);

 

        //this will set our parameter named :phone

        query.SetString("phone", phone);

 

        return query.List<Account>();

    }

}

Here I am allowing you to specify the session to use in the constructor. This way we can easily supply a session with a transaction (which will come in handy for the test).  In the first method we simply defer the call to Session.Get().  The second method takes advantage of HQL, or Hibernate Query Language.  This allows us to write queries easily, using familiar syntax, only we speak in terms of our objects.  You don’t see any database columns here.  HQL is very powerful, but can take some getting used to, because the results of your queries go directly into objects.  I’ve found that the best reference so far for HQL is Hibernate in Action book.

I created 2 tests to verify the above functionality:

[Test]

public void CanQueryForAccountByIdWithRepository()

{

    using (ISession session = SessionSource.Current.GetSession())

    {

        using (ITransaction tx = session.BeginTransaction())

        {

            Account acct = new Account();

            Customer customer = new Customer("Some", "Dude");                   

            customer.HomePhone = "212-224-3456";

            customer.Address = new Address();                   

            acct.AddMember(customer);

 

            session.SaveOrUpdate(acct);

            session.Flush();                   

 

            int id = acct.Id;

 

            AccountFinder finder = new AccountFinder(session);

 

            Assert.AreEqual(acct, finder.FindById(id));                   

 

            tx.Rollback();

        }

    }

}

 

[Test]

public void CanQueryForAccountByCustomerPhoneWithRepository()

{

    using (ISession session = SessionSource.Current.GetSession())

    {

        using (ITransaction tx = session.BeginTransaction())

        {

            Account acct = new Account();

            Customer customer = new Customer("Some", "Dude");

            customer.HomePhone = "212-224-3456";

            acct.AddMember(customer);

 

            session.SaveOrUpdate(acct);

            session.Flush();

 

            int id = acct.Id;

 

            AccountFinder finder = new AccountFinder(session);

            IList<Account> matches = finder.FindByCustomerPhone(customer.HomePhone);

            Assert.IsTrue(matches.Contains(acct));                   

 

            tx.Rollback();

        }

    }

}

 

And they are both passing!  We’ve come to a good stopping point here.  I’d like to wrap up our feature list next time, then start on a basic UI.

 

I’ve gotten a lot of positive feedback so far with this series, and I always welcome more!  If you haven’t downloaded the code to follow along I encourage you to do so.

 

Here is the latest source: Videocracy - Part 8

Friday, December 08, 2006

Firebug 1.0 Beta released

The very handy Firebug javascript debugger for Firefox has just released a major update.  Click here to get it.

If you aren’t using Firebug, you’re missing out.  It is hands-down the best javascript debugger out there.

It can intercept and log all XMLHttpRequests, you can set breakpoints, inspect and modify the DOM, execute javascript on the fly with the console, and a lot more.  New features allow you to tweak and visualize CSS metrics (with rulers), and monitor network activity.

Seriously, what are you waiting for?  Go get it.

Monday, November 13, 2006

A Journey with Domain Driven Design (and NHibernate) - Part 7

After a very long spell of inactivity, we’re back for Part 7 of the series!

Last time we left off with a decent domain model, a database, and the beginnings of NHibernate.

Since the last article, the NHibernate team has produced the ever-so-fantastic v1.2.0 beta 1.  This release supports numerous new exciting features.  Topping the list of cool new features is:  native support for .NET GenericsNative SQL 2005 is also supported.  Another feature was just enabled that will really help bridge the gap for those folks who will clutch to stored procedures forever:  Stored Procedure / Custom Query Support.

I’ll start today by slapping in this version of NHibernate and do a little bit of housekeeping.  With this new version of NHibernate, I no longer have a need for NHibernate.Generics (and thus I will remove it).  Some people might still use it, as it has the nice side-effect of automatically managing bi-directional relationships (which we’ll visit later), however I’m going to show this manually in this series.

I’ve changed my EntityList<T> / EntityRef<T> / EntitySet<T> to normal generic collections, and NHibernate will use them automatically.  These classes do provide you with an extra nifty feature (explained later), but it’s important to understand what it does under the hood, so I will implement the functionality the manual way, and later I’ll reference these classes to show how you might still want to use them.

So I’ve remove the old dll of NHibernate and I referenced in the new one.  I also updated my nhibernate schema file in Visual Studio so that I get the updated intellisense.  I compile, nothing is broken, and we’re ready to test!  The beauty of having our unit tests is that we have much more confidence that we know exactly what to fix, and we also know the instant that we are done fixing any breaking changes.  Our application returns to a known state of behavior very quickly.

Since I’ve made persistence level changes (the new NHibernate dll) as well as domain model changes (replacing NHibernate.Generics.Entity*<T> with standard .NET generic lists) I need to run both test assemblies.

 Here are the immediate results of the tests:

TestCase 'Flux88.Videocracy.Persistence.Tests.PersonTester.TestCanListPeople' failed: NHibernate.InvalidProxyTypeException : Type 'Flux88.Videocracy.DomainModel.Person' cannot be specified as proxy: method get_Id should be virtual
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Proxy\ProxyTypeValidator.cs(28,0): at NHibernate.Proxy.ProxyTypeValidator.Error(Type type, String reason)
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Proxy\ProxyTypeValidator.cs(76,0): at NHibernate.Proxy.ProxyTypeValidator.CheckMethodIsVirtual(Type type, MethodInfo method)
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Proxy\ProxyTypeValidator.cs(63,0): at NHibernate.Proxy.ProxyTypeValidator.CheckEveryPublicMemberIsVirtual(Type type)
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Proxy\ProxyTypeValidator.cs(22,0): at NHibernate.Proxy.ProxyTypeValidator.ValidateType(Type type)
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Cfg\Configuration.cs(915,0): at NHibernate.Cfg.Configuration.ValidateProxyInterface(PersistentClass persistentClass)
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Cfg\Configuration.cs(891,0): at NHibernate.Cfg.Configuration.Validate()
	c:\net\nhibernate-1.2.0.Beta1\nhibernate\src\NHibernate\Cfg\Configuration.cs(1035,0): at NHibernate.Cfg.Configuration.BuildSessionFactory()
	c:\sandbox\Videocracy\Flux88.Videocracy.Persistence\SessionSource.cs(55,0): at Flux88.Videocracy.Persistence.SessionSource.Initialize()
	c:\sandbox\Videocracy\Flux88.Videocracy.Persistence\SessionSource.cs(81,0): at Flux88.Videocracy.Persistence.SessionSource.GetSession()
	c:\sandbox\Videocracy\Flux88.Videocracy.Persistence.Tests\PersonTester.cs(27,0): at Flux88.Videocracy.Persistence.Tests.PersonTester.TestCanListPeople()

We have a few failing tests, however they all relate to the same problem.  NHibernate 1.2.0 beta 1 now sets everything to lazy-load by default.  This means that our objects must be able to be inherited so that NHibernate can inject proxy subclasses of our objects (the consumer doesn’t know or care that this happens).  To do this all of the methods and properties need to be virtual.   This is a large change, and it’s not something I entirely agree with, but it’s very easy to turn off.   (It pays to read the release notes of these 3rd party products!)  We’ll discuss how to effectively lazy-load a bit further on.

In our mapping file, we can specify default-lazy=”false” to override this behavior.  At a later time we may investigate and find that the class will benefit from lazy loading and we’ll revert it, but until then I’ll just make all the classes default-lazy=”false”.

Here’s the change:

<?xml version="1.0" encoding="utf-8" ?>

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"

                  namespace="Flux88.Videocracy.DomainModel"

                  assembly="Flux88.Videocracy.DomainModel"

                  default-lazy="false"

                  >

 

  <class name="Person" table="People">

     …

  </class>

 

</hibernate-mapping>

Once that change is in place, all 5 of my persistence tests are passing.   I have 6 failing tests in my domain model, mostly due to my careless replacement of the EntityRef stuff with standard .NET collections.  The tests expose my oversights and once I fix them I’m back on track.

Ok, now where were we?  (It’s been a while, so I open NUnit and see that we have Save/List/Load for a Person object, but nothing else). We introduced some simple mapping concepts, and this time we’ll dig in a bit deeper.

How does NHibernate deal with associations?  Lets start with Account.  Account has a collection of Customer objects that represent its members.  In standard database terms, Account is a one-to-many with Customer.  How do we map this kind of relationship with NHibernate?

There are a few choices when looking at the documentation for NHibernate.  To understand them you must understand the semantics of each kind of list.  Ask yourself these questions:

  • is it one-to-one?  many-to-one?  many-to-many?
  • does order matter?
  • is it bidirectional?

From the NHibernate FAQ, we find this informative nugget, that explains the collections available to us (and their .NET counterparts):

  • The <list> maps directly to an IList.
  • The <map> maps directly to an IDictionary.
  • The <bag> maps to an IList. A <bag> does not completely comply with the IList interface because the Add() method is not guaranteed to return the correct index. An object can be added to a <bag> without initializing the IList. Make sure to either hide the IList from the consumers of your API or make it well documented.
  • The <set> maps to an Iesi.Collections.ISet. That interface is part of the Iesi.Collections assembly distributed with NHibernate.

Our Account -> Customer relationship is one-to-many.  I could choose to allow one customer to have many accounts, but I don’t see any real use for that yet.  Order does not matter either.  I could have 4 members on an account, and it doesn’t really matter what order they are given to my in a list. 

We also have to consider what each end of the association looks like.  Right now I’m looking at it from the perspective of Account, where Account has many Customers (members).  On the customer object, the customer only has one Account, so this isn’t a bidirectional association.  (We’ll see an example of this later).  Techically our collection maps to an ISet, but I’d rather not depend on the Iesi.Collections.dll, so I’m going to map it to a list (the only drawback is that the list will allow the same member twice, so I’ll just get around this in our model manually).

Here’s how we’ll deal with that:

/// <summary>

/// Adds a member to this account

/// </summary>

/// <param name="customer"></param>

public void AddMember(Customer customer)

{

    //ignore multiple adds for the same customer.

    if(_members.Contains(customer)) return;

 

    _members.Add(customer);

 

    //make sure that our association is handled on both sides

    customer.Account = this;

}

 

/// <summary>

/// Removes a member from this account.

/// </summary>

/// <param name="customer"></param>

public void RemoveMember(Customer customer)

{

    //ignore the call if the customer isn't a member of this account

    if (!_members.Contains(customer)) return;

 

    _members.Remove(customer);

 

    //make sure that our association is handled on both sides

    customer.Account = null;

}

 The rest of the class is self-explanatory, so I won’t include it here.  You’ll  be able to download the project at the end of today’s article, however.

Next up is the mapping.  Let’s take another look at the table structure for reference:

CropperCapture[4]

This is slightly different than what was in the last archive.  Instead of an account having a single primary customer, any customer can be the ‘Owner’ of his/her account.  I chose to keep the association simple for this demo.  I also wanted to allow multiple ‘Owners’ for a single account.  I’ve updated the tests to reflect this change.

Here you see that many customers belong to exactly one account.    This is a one-to-many relationship from Account to Customer.

If we stop and think about the domain for a minute, we can determine that the Customer will be identified first (by his/her ID or Account #) and that needs to be able to pull up the account.  I’d also like to keep this relationship bidirectional.  That means that I need to map the relationship on both classes so that we can do this:

customer.Account ….  

or this:

for each Customer c in _account.Members { … }

Here is the relevant mapping for Customer:

 <!-- CUSTOMER  -->

 <joined-subclass name="Customer" table="Customers">

  <key column="PersonId" />

 

  <!-- todo:  map this to an enumeration -->

  <property name="RentalRestriction" type="Int32" column="rentalRestrictionId" />

 

  <many-to-one name="Account" class="Account" column="accountId" cascade="save-update" />

 

 </joined-subclass>

This tells NHibernate that this is the *many* end of a one-to-many association.  We tell it the property name, type, foreign key column name, and our cascade strategy.  This basically means, whenever we save or update our Customer, cascade the save/update to the Account as well.  You can also specify to cascade deletes as well if you need to.

The Account mapping looks like this:

 <class name="Account" table="Accounts" where="Active=1">

 

    <!-- ... -->

 

    <bag name="Members" access="nosetter.camelcase-underscore" lazy="true" 
         
cascade="save-update" inverse="true">

         <!-- this key refers to the Account key in the Customer table -->

         <key column="accountId" />

         <one-to-many class="Customer" />     

    </bag>

 

 </class>

This section tells NHibernate to map this association as a bag.  Lazy=true means that the collection will only actually be retrieved from the database once it is accessed.  NHibernate does this by silently replacing our IList with a proxy that knows about the session and how to hydrate the collection.  This is 100% transparent to our consumers, so make sure you are using this in appropriate places.  Lazy=false will force NHibernate to pre-load the entire association (and it’s associations(and it’s associations(…. you get the point…))). 

To test that this association worked, I wrote a simple test:

 [Test]

 public void CanSaveCustomerAndAccount()

 {

    Customer c = TestHelper.GetTestCustomer();

 

    Account a = new Account();

    a.AddMember(c);

 

    using (ISession session = SessionSource.Current.GetSession())

    {

        using (ITransaction tx = session.BeginTransaction())

        {

            session.SaveOrUpdate(c);

            session.Flush();

 

            session.Evict(c); //make sure we don't get an object from the cache

 

            Assert.AreNotEqual(0, c.Id, "Customer didn't get an Id after save");

            Assert.AreNotEqual(0, a.Id, "Account didn't get an Id after save");

 

            Customer customerFromDb = session.Get<Customer>(c.Id);

 

            Assert.AreNotSame(c, customerFromDb, "Got same instance of customer!");

            Assert.AreEqual(a, customerFromDb.Account, "Account didn't get saved");

 

            tx.Rollback();

        }

    }

 }

This test is passing and we have our first association mapped!

I think this is a good stopping point.   We have migrated our version of NHibernate and our tests forced us to fix any outstanding issues before continuing.  We also identified our first association, mapped it, and tested it.

From here on out I will step up the pace and start glossing over the details a bit and focus on getting working product done using this domain model.  As I begin writing some UI components I will come across some features I have not developed, which may require more mapping changes and tests.  In order to finish this series sometime this year I’ll be speeding up a bit.  I will still continue to post the source so that you may follow along.  If you have comments or questions, feel free to comment.

Here is the latest source:

File Attachment: Videocracy_07.zip (44 KB)

Agile Houston - Finally!

I was very excited to hear the creation of the first Houston Agility User Group, Agile Houston.

If you are interested in Agile practices and methodologies and live in the Houston area, I encourage you to join the group and attend the first meeting!

Currently I expect the first meeting to occur sometime in January, so as soon as I find out a definite date, I’ll post it here.

Wednesday, October 18, 2006

TulsaTechFest 2006 was a Blast

I attended TulsaTechFest 2006 this past weekend and I had a fantastic time.  I was able to meet a number of interesting people and learned quite a bit.

I attended…

  • NUnit Extensibility with Tim Rayburn
    Tim is an incredibly passionate guy.  He didn’t have quite enough time to fully cover his presentation, though I did learn from it.  He ended up spending about 15 minutes of it just pimping CodeRush.
  • IoC / DI with Dru Sellers
    Inversion of Control / Dependency Injection has been an interest of mine for some time now, but it’s a tad difficult to wrap your head around how it actually works.  In theory I understood it, but with Dru’s explanation I am now fully onboard with it and will definitely start utilizing it in my projects at home to get better at it.  Dru was very excited about it and it showed.  His talk was very casual and informative.
  • POCOS In Action with Dru Sellers
    POCOs, or Plain Old CLR Objects, is a concept adopted from Java (you guessed it: POJOs) which is basically a move away from Entity Java Beans.  The gist of it is that we’d like to focus on simple objects that express our domain model and business rules and nothing else.  No infrastructure mixed in with our logic.  No persistence related concerns embedded in our objects.  This talk was very high level and actually blended with IoC and NHibernate, so I wish I would have attended another talk.  Dru did a great job explaining the POCO mentality and I know he made a great impact on my buddy Tom, a Java developer.
  • NHibernate with Dru Sellers (see a pattern?)
    I attended this talk mainly to show the flag, as I knew it would be more of an introductory overview.  The audience seemed genuinely interested in the subject and Dru explained it well.  I also contributed my two cents and I hope I wasn’t intruding .
  • The Science of Great UI with Mark Miller
    UI Design is a big interest of mine, but the fact that Mark Miller was presenting sealed the deal on this talk.  Mark is crazy, and if you haven’t listened to him on Mondays or Millahseconds, you really should.  He’s insanely hilarious and I thoroughly enjoyed his presentation.  My favorite part of this presentation was when Mark shoved his kid off of his lap to take a picture of a “horribly conceived modal dialog box ever” in a Lego game he was playing with his kids.  I can totally see him doing that.
  • Component-based Architectures with Mark Miller
    This talk was about to get very interesting when Mark ran out of time.  Some of us were a bit confused on where he was going, and we talked to him about it afterwards and he was eager to hear the feedback.  Basically he argued that in order to gain the best competitive advantage, we as developers should focus on implementing new features faster, (features and time being two out of 4–5 aspects of a product that we control) and to do that we have to understand how difficult it is for new developers to just get work done.  He argued that the less visible structure that your code has, the easier it is to add new features.  Mark is a fan of building components (yes, like the ones you drag onto a component surface in visual studio).  If you aren’t clicking with this yet, and I fully understand why, then you should go try to create a plug-in with Visual Studio and see if you can get a simple one completed.  Then go try it with the free DXCore and see if you aren’t blown away at its simplicity.

I also won a book, Professional Ajax (WROX) which is now 8th on my reading list.

After the event I met up with Tim Gifford and Javier Lozano, and we went to an Irish pub and later mosied on down to Arnie’s to where Microsoft was buying drinks!  I met up with Shaun Walker (from DNN fame) there and I made sure to give him a hard time about his picture.   Sorry Shaun, no hard feelings!  (He’s really a cool guy).  At the bar we enjoyed some tech conversation and jager bombs (ouch) and had a good time.

I can’t wait to go again next year.

Sunday, October 08, 2006

Tulsa Tech Fest

I’ll be attending Tulsa Tech Fest this weekend.

I’m excited to see quite a few people speak, including:

  • Markus Egger
  • Mark Miller
  • Carl Franklin
  • Dru Sellers
  • Bill Vaughn

However I was saddened to hear that Jean-Paul Boodhoo will not be speaking anymore.  I was mostly excited about his sessions on Continuous Integration and Mock-Objects.  Ah well, I’ll catch him next time around.

I haven’t finalized my schedule yet, but I’m looking forward to some of the Agile sessions, some Ajax, some WPF, and general architecture.  I’ll post my schedule later on, if anyone wants to meet up.

Is anything going on after the event?

Friday, October 06, 2006

Compiled vs Dynamic Laguages and the Code Feedback Loop

So I bit the bullet and installed Ruby on Rails.  I’ve been reading a lot about Ruby (mainly blogs) and decided that it’s about time to learn another language.  The Pragmatic Programmers believe that you should dedicate some time to learn a new language every year.

My first impressions are probably pretty common.  Ruby is not easy to jump into.  They have a lot of great information on the internet, but I found that things didn’t go as smoothly as I had hoped.  This is probably due to the fact that there are major changes between each version of ruby/rails, and there are old tutorials directed at older versions of Ruby or Rails.

The second hinderance I found was that, with Ruby (among other dynamic languages), you don’t get any intellisense.  Being brought up with Visual Studio made me spoiled, I suppose.  The fact is, with any dynamic language, such as Ruby, Python, or Javascript…  Intellisense is difficult to provide.  Type information often isn’t available until runtime.

This really annoyed me at first, and I was quick to dismiss dynamic languages. 

Intellisense really makes your learning experience much easier.  When I started in .NET, I had a few books, but mainly I just used Intellisense to navigate my way around the framework.  If you didn’t know how to send email with .NET, you could easily just type System.Web.Mail. and you’d see the relevant classes involved.  Intellisense is an extremely effective discoverability tool.  

Now that I am an experienced .NET developer, I know all of these things by heart.  There’s not much stopping me from writing my programs in Notepad2.  I don’t rely as heavily on Intellisense like I did before.  I still use Visual Studio, though, because having your compiler and debugger integrated with your editor is almost a necessity.

This isn’t the case with dynamic languages.  You write a program (often times in a single file with FAR fewer lines of code) and you run it.  That’s it.  There’s no compilation or startup time.  You get your results right there.  If you mispell a type or call a method on the wrong class of course you’ll get an error.  But you find this out sooner that your C# / Java program will compile.  If you can write 5 lines of code and push a button to see if it worked…  without waiting for a compiler or debugger, then your code-feedback-loop is MUCH tighter.  Agile principles thrive on having small feedback loops.  This is (in my opinion) the single largest reason why Agile is so effective.

The compiler is becoming less and less popular these days because it cannot protect your program from logic flaws.  It’s becoming much like the spell-check feature of word processors.  They can tell you that you mispelled the word definate definite, but a sentence like this one will pass spell-check just fine:  We will meat at the movie theater.  A compiler can only take you so far.  To verify your program works, you have to compile it, run it, navigate to the section, and test it.  In a dynamic language, half of these steps are removed, leaving you with a much tighter code-feedback-loop.

We all love intellisense (and I will welcome it for Ruby with open-arms), but don’t let that stop you from writing your next small program in a language like Python or Ruby.  It will give you another tool in your developer toolbox and make you a better programmer in *any* language.

 

Wednesday, September 27, 2006

I'm not dead

I’m just posting this to let my readers know that I am not dead

I’ve been eager to finish the articles on Domain Driven Design and NHibernate, however work has been very busy lately, combined with kids soccer, volleyball, cub scounts, and other activities….there’s not enough time in a day!

Ahh, and I’d also like to personally thank Aaron Murrell and Ayende Rahien for their hugely appreciated assistance in overcoming some very obscure issues.  Thanks guys!

Mortgage Calculator - Loans - United Specialties - Wills