Friday, January 26, 2007

My Presentation on Continuous Integration

I gave a talk on Continuous Integration last night at the Houston Sark Office.  Thanks to all who attended.

We had pizza and discussed some of the processes and principles behind CI, as well as some of the tools to get you there.  I did a live demo of an app, connected to source control and a build server.

A-la Jeremy Miller, I had my CCTray audio clips setup, so when the build failed, you’d hear Napolean Dynamite say “Freakin Idiot!”

I think it went well, however for those of you who attended, I’d really like to hear your thoughts!  Please take a second to leave a comment.

Here are the files used in the demo:

continuous integration.zip (8323 KB)

(included are the sample project, cruise control config, and power-point slides)

I left out the build server installation because it was over 70mb.  It consisted of Subversion binaries, Nant, and a Cruise folder with some project state data.

I got amazing help from Jean-Paul Boodhoo, who has a 9 part NAnt starter series, which ends on a screencast of setting up CruiseControl!

Additional resources were:

Monday, January 22, 2007

My Wedding

Many of you already know, I got married to Silvia on December 30th, 2006!

We had a beautiful ceremony with lots of friends and family.  Everyone had a good time.  My wife and I are quite the happy couple!  As promised, here are some pictures from the wedding.  The entire album is avaiable on flickr.

IMG_2246

IMG_2258

IMG_2293

IMG_2325

IMG_2365

IMG_2456

IMG_2551

IMG_2604

IMG_2635

IMG_2714

IMG_2725

IMG_2741

IMG_2854

 

Saturday, January 20, 2007

Database Migrations for .NET

In my search for the one-command automated build, I’ve often stumbled upon how to deal with the database while writing code on a multi-developer project.

Most of us use source control, however only a small fraction of us actually store the database scripts in source control.  This is a powerful tool that is often missed completely.

This is a development process I see frequently:

  • get the latest version of the source from VSS
  • exclusively check-out the code files you need
  • make changes to the code and the database to enable your new features
  • check in the code once it is all done
  • do a sql compare to the dev/test databases to get a delta script
  • run the compare script in the test environment and deploy the project to test.

There are a number flaws in this process, but it doesn’t stop people from continuing along this path for an entire project.  Rather than point out everything that scares me from that list, I’ll focus on the database portion.

What’s wrong with just making changes and then doing a SQL compare?  Well, for starters… that compare script is used once and thrown away.  It is never checked into source control.  If we need to restore the state of an application as of 4 months ago, we can do it with the code, but not the database.  The database only stays on the current version, and there’s no going back.  Another drawback is that the process is a manual one, and we want to get into automation.  Lastly, SQL Compare (and SQL Delta) are both licensed tools, and not all of us can purchase them.  At home I cannot justify the cost, so I am forced to come up with something else.

The Ruby on Rails community is lucky.  Baked into the Rails framework is something called migrations.

Let’s say you’re on a ruby project for managing houses for sale.  You get a new feature request where you want to know how many bathrooms a house has (strange request, huh?).  You make the changes to model (adding a bathrooms property) but now you need the database to support it.  So you type rails script/generate migration Add_House_Bathrooms.  This will generate a ruby code file in the /project/db/migrations/xxx_Add_House_Bathrooms.rb file.  (the xxx will be replaced with sequential ordering, so rails knows what order to execute the migrations) Inside this file are 2 methods:  up and down.  This is, how to I create the changes, and how do I remove the changes.  Inside these methods you can write code that adds and removes the column you want.

So then when you need to deploy, rails knows what version the database is on (by having a version table), and can apply the migrations since that version to bring the database up to speed with the code.  If something goes wrong, it can roll the changes back to the original version (by using the down methods).

You can even create migrations that load dummy test data, or default values for static lookup tables.

It usually only takes a little while for a cool idea to make its way into the .NET world, and migrations are no exception.  The Castle Project is a collection of many RoR-esque utilities packaged into one.  One of those utilities is called Migrator, which lives in the Generator project.

To generate a migration, you type:

generate migration Add_House_Bathrooms

With this, you can enable this style of migration in .NET.  You create migrations, these end up as C# code files in your db/migrations folder.  The same concept applies.

The migrator is fairly young, but it was extracted from CastleContrib into the main Castle trunk, so that is a good sign that it is here to stay and will have active support.

When I have more time to play with this, I’ll try and post a little demo.  For now, check out the castle project at http://www.castleproject.org

What does your team do to manage database changes and enable versioning?

Friday, January 19, 2007

Free book on Domain Driven Design

InfoQ has published a small book on DDD called Domain Driven Design Quickly.  They're giving away the PDF for free!  The print version is only $22, so I'll probably buy it if I like the PDF version.

Check it out:
http://www.infoq.com/minibooks/domain-driven-design-quickly

Solid Gold CSS Resource

I came across this site today, which boats 53 CSS Techniques you can't live without.

Normally I don't like to blog just links, but this one is definitely worth it.  It covers most of the major techniques, both simple and advanced for styling web pages.

Thursday, January 18, 2007

Eliga - A New Development Methodology

My latest assignment at work was somewhat small, and the requirements were fairly straightforward so I got to work immediately.  My early requests to meet with my user were met with “let’s get a demo first.”  Given the availability of all parties involved, this took longer than I would have liked.

So here I am, 60 work-hours later, I have a fully functional, ready-to-deploy application, and I have yet to meet with my user.  Let’s sincerely hope he doesn’t decide that this isn’t what he wanted in the first place.

Then my office-mate recognized our new development process.  Ladies and gentlement, I give you Eliga! 

Eliga is the opposite of agile.  Here is our manifesto:

Forget users, they will only slow me down!  Don’t disturb me when I’m coding you peons!  I’ll hear your impressions when I’m finished!  I can’t be bothered with workflow changes!  They’re already coded and set in stone!

Tuesday, January 09, 2007

Tag I'm It! - 5 Things you didn't know about me

Well the internet sure is a tiny place. I was tagged by JP Boodhoo and Aaron Murrell.

Here it goes, 5 things that you probably didn't know about me before:

  • I was born on a farm in Oregon.  I still remember my favorite cow (Jesse) from our farm.  One day he was gone.  Where did he go?
  • I used to be insane on rollerblades.  My friends and I would jump pretty much anything.  It’s actually amazing that I didn’t break any bones jumping over staircases and stuff, especially since I am so accident prone.
  • I got my first guitar when I was 7, however I didn’t really pick up playing until 12 or so.  I still play, but not as often as I would like to.
  • I first got into computer programming watching my dad write a hangman game from scratch.  I picked up QBASIC when I was 13 or 14, and I would write little screen savers using the primitive graphics drawing routines it had.  My pinnacle QBASIC program was a hoax that my friend and I pulled on his younger brother.  We called it “DelBug” and it was supposed to remove bugs from programs, such as Doom 2, which just-so-happened to be causing him troubles.  It went through a series of fake menus and ended up pretending to format his hard drive.  It was great!  He almost wet himself when it started flashing and rebooting in a loop.
  • And lastly, I just got married!  (Pictures coming soon).  Silvia and I had a beautiful ceremony and lots of close friends and family were present.

And I’ll tag:

 

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

Credit Card Consolidation - Hotel Las Vegas - Share Dealing - Credit Counseling