Friday, February 29, 2008

I Want...

If I had to make a list of wants this is what it would like:

  1. I want to develop applications using test driven development and domain driven design.
  2. I want good object orientated practices to be the norm.
  3. I want to be creative with design patterns.
  4. I want to work in a true agile environment.
  5. I want pair programming to be accepted by management.
  6. I want to work with XP.
  7. I want to work with Scrum.
  8. I want to help my team grow.
  9. I want to learn from my team.
  10. I want to work in a self organizing team.
  11. I want to work in iterations that range from 2-4 weeks.
  12. I want failing iterations to be caught fast and early.
  13. I want to introduce tests into legacy code.
  14. I want to work with bleeding edge technology.
  15. I want to work with passionate people.
  16. I want to work with knowledgeable people.
  17. I want to work with individuals who I can learn from.
  18. I want to work with fun people.
  19. I want to have friends rather than coworkers.
  20. I want to work in an environment that enables creativity.
  21. I want to work with a team of high performers.
  22. I want to use a build tool like NAnt.
  23. I want to have a CI Box.
  24. I want lots of whiteboards.
  25. I want to have time to read books, read articles and attend conferences.
  26. I want to take control of the .Net Framework rather than allowing it to control me.
  27. I want to have a chance to understand how a tool works before I use.
  28. I want my work to be appreciated.
  29. I want to help my company grow.
  30. I want to be active in the .Net community(present,attend presentations).
  31. I want to inspire others.
  32. I want to become a great software developer.
  33. I want my work to matter.
  34. I want to show people that I am Artist and software development is my canvas.
  35. I want to wake up every single day and be pumped about being a software developer.

It's remarkable but every single one of my wants is being fulfilled. I'm not sure why, but it took sometime before I came to the conclusion that I'm happy. I hope that every single one of your wants is being fulfilled.

Tuesday, February 26, 2008

Automating your Deployment

Check out this wicked NAnt target for clickOnce deployment. MageFileUpdater is a command line tool that I created for updating various parts of the deployment manifest and application manifest files. MageFileUpdater makes up for Mage.exe weak command line support. Mage via command line does not allow you to add an icon in the windows start menu or update the publisher name and product name. According to MSDN documentation the new version of mage packaged with visual studio 2008 allows you to update the publisher name. Even though that's kind of cool they are still missing a multitude of features.

In addition to this neat little target I am working on leveraging msbuild(exe) from nant to execute a msbuild file to create the boot strap that will install prerequisites for a clickOnce application.

The good thing about automating your deployment is that you only have to do it once. Hopefully in the near future I can throw together a few more posts about how we automated our deployment with NAnt and the many hurdles we had to jump. 

<target name="create.clickonce">   

    <call target="create.clickonce.dir" />

    <!--  Generates the application manifest file. -->

    <exec program="${dotnet.sdk.dir}\mage.exe" commandline="${mage.console.args.new.application}" verbose="true" />

    <!--  updates the application manifest file with the icon to be displayed in the start menu. -->

    <exec program="${tools.dir}\mageUpdater\MageFileUpdater.exe" commandline="${mageFileUpdaterConsoleArgumentsForApplication}"/>

    <!--  signs the  application manifest file -->

    <exec program="${dotnet.sdk.dir}\mage.exe" commandline="${mage.console.args.sign.application}" verbose="true" />

 

    <!--  Creates deployment manifest file -->

    <exec program="${dotnet.sdk.dir}\mage.exe" commandline="${mage.console.args.new.deployment}" verbose="true" />

    <!--  Updates the deployment manifest file with an association to the application manifest file. -->

    <exec program="${dotnet.sdk.dir}\mage.exe" commandline="${mage.console.args.update.deployment}" verbose="true" />

    <!-- Changes the deployment type in the deployment manifest. -->

    <exec program="${tools.dir}\click.once\click.once.console.exe" commandline="${clickonce.dir}\${app.exe}.application" verbose="true" />

    <!--  Updates the name of the publisher and product name. -->

    <exec program="${tools.dir}\mageUpdater\MageFileUpdater.exe" commandline="${mageFileUpdaterConsoleArgumentsForDeployment}"/> 

    <!-- Lastly deployment manifest file is signed -->

    <exec program="${dotnet.sdk.dir}\mage.exe" commandline="${mage.console.args.sign.deployment}" verbose="true" />

  </target>

Wednesday, February 20, 2008

What will this code YIELD

Can you figure out what the following code will yield on the screen.

using System.Collections.Generic;

using System.Windows.Forms;

 

namespace YieldReturnSpike

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

 

            uxPeopleGridUsingYield.DataSource =

                          new People().GetPeopleIWorkWith();

 

            uxPeopleGridNotUsingYield.DataSource =

                          new List<Person>(new People().GetPeopleIWorkWith());

        }

    }

 

    public class People

    {

        public IEnumerable<Person> GetPeopleIWorkWith()

        {

            yield return new Person("Mo Khan");

            yield return new Person("Joel Briggs");

            yield return new Person("Luu Duong");

            yield return new Person("Matt Gardiner");

        }

    }

 

    public class Person

    {

        private readonly string name;

 

        public Person(string name)

        {

            this.name = name;

        }

 

        public string Name

        {

            get { return name; }

        }

    }

}

Here are the puzzling results:

As you can see when the data source is set to a list with deferred execution the list is not bound to the data grid. I really don't understand why this happens. In order to figure this one out I will have to gain more insight into how the databinding works under the hood. I'll post my findings once I get some answers.

Saturday, February 16, 2008

Yield Return is Evil :-(Sometimes)

If you don't already know Justice Gray has put the word out that if don't read Mo's Khan Blog you are a loser. I would like to let everybody know that I read Mo's blog. Mo recently wrote up a great post about testing and deferred execution. Even though I was well informed by Mo's blog post I still fell victim to the evils of deferred execution.

I have decided to include the actual code that I was working on. I came to the conclusion that although a contrived example is a great tool for learning a real world example is better suited to exhibit how you can fall prey to deferred execution in the wild.

The Test Failure Message:

IMapper`2.MapFrom(any); Expected #1, Actual #0.
   at Rhino.Mocks.MockRepository.VerifyAll()
   at Rhino.Mocks.PlaybackModeChanger.Dispose()
   at...

The failure message simple states that the expected method MapFrom was never invoked.

The Test:

private MockRepository mockery;

private IXmlToIndustryCodesMapper mockXmlToIndustryCodeMapper;

 

[SetUp]

public void Setup()

{

    mockery = new MockRepository();

    mockXmlToIndustryCodeMapper = mockery.DynamicMock<IXmlToIndustryCodesMapper>();

}

 

public IXmlToWcbAccountMapper CreateSUTWithMock()

{

    return new XmlToWcbAccountMapper(mockXmlToIndustryCodeMapper);

}

[Test]

public void Should_leverage_the_industry_codes_mapper()

{

    StringBuilder xml = new StringBuilder();

 

    WcbAccountElementDefintion wcbAccountElementDefintion = new WcbAccountElementDefintion();

 

    string accountNumber = "123";

 

    xml.Append(wcbAccountElementDefintion.OpenTag);

    xml.Append(wcbAccountElementDefintion.AccountNumberElement.CreateElementFor(accountNumber));

    xml.Append(wcbAccountElementDefintion.CloseTag);

 

 

    using (mockery.Record()) {

        Expect.Call(mockXmlToIndustryCodeMapper.MapFrom(null)).IgnoreArguments().Return(new List<IIndustryCode>());

    }

 

    using (mockery.Playback()) {

        IEnumerable<IWcbAccount> wcbAccounts = CreateSUTWithMock().MapFrom(new XmlElementFactory().From(xml.ToString()));

    }

}

The implementation:

public IEnumerable<IWcbAccount> MapFrom(IXmlElement input)

{

    WcbAccountElementDefintion wcbAccountElementDefintion = new WcbAccountElementDefintion();

 

    foreach (IXmlElement wcbAccountElement in Parse.Xml(input).AllElementsNamed(wcbAccountElementDefintion.Name))

    {

        string accountNumber = Parse.Xml(wcbAccountElement).ForValueOfElement<string>     

                               (wcbAccountElementDefintion.AccountNumberElement.Name);

 

        IEnumerable<IIndustryCode> industryCodes = xmlToIndustryCodeMapper.MapFrom(wcbAccountElement);

 

        yield return new WcbAccount(accountNumber, industryCodes);

    }

}

The Problem:

The reason that this code fails is because of deferred execution. The following line is our culprit.

yield return new WcbAccount(accountNumber, industryCodes);

Simply calling MapFrom on the XmlToWcbAccountMapper will not invoke the MapFrom method.

IEnumerable<IWcbAccount> wcbAccounts = CreateSUTWithMock().MapFrom(new XmlElementFactory().From(xml.ToString()));

 

It's kind of like the wcbAccounts collection has a pointer to the MapFrom method. Once the Enumerator moves to the first item the MapFrom method will be invoked.

 

Since wcbAccounts is waiting to be iterated over the following line will never be called.

 

IEnumerable<IIndustryCode> industryCodes = xmlToIndustryCodeMapper.MapFrom(wcbAccountElement);

 

Actually none of the lines in the MapFrom Method will be invoked

 

The Solution:

 

The solve this problem we need to somehow cause the MapFrom Method to be invoked.

 

The first thing that comes to mind is that we could just loop over the collection of items.

 

foreach (IWcbAccount account in wcbAccounts) {}

 

If you were just interested in invoking the first call to yield you could do the following:

 

CreateSUTWithMock().MapFrom(new XmlElementFactory().From(xml.ToString())).GetEnumerator().MoveNext();

 

By moving to the fist element in the enumerator we are forcing the MapFrom method to be invoked.

 

To make this solution a little cleaner we could just create a new collection and pass the enumerable in as a parameter in the constructor. This would cause the new list to iterate over the collection.

 

new List<IWcbAccount>(wcbAccounts);

 

This is the final line of code that I ended up with:

 

new List<IWcbAccount>(CreateSUTWithMock().MapFrom(new XmlElementFactory().From(xml.ToString())));

 

Even though deferred execution has a few pitfalls it really is a powerful feature of the .Net Framework.

Wednesday, February 13, 2008

How to Avoid Embarrassing Build Errors

It happens to all of us at some point. We pull up the command window, type "build test" and before you know your knee deep in compilation errors. To make a situation worse your pairing partner has lost all faith in your coding abilities. Your partner no longer wants to work with and you are convinced that the other developers are laughing at you behind your back. Well don't fret, thankfully the good folks at JetBrains have a new feature in ReSharper 3.1 called Solution Wide Analysis. Solution Wide Analysis will help you avoid those embarrassing build errors by catching them before you even compile.

Honestly, you are losing productivity if you don't turn this feature on. By default solution wide analysis is turned off. To turn on solution wide analysis follow these steps:

1. With the Keyboard: Alt + R,  O

From here I recommend using the mouse since JetBrains seemingly forgot to add keyboard support. If you are listening JetBrains please add keyboard support to your options screen. It's some what silly that a product with so many keyboard shortcuts doesn't even have proper keyboard shortcuts in their own options screen. It's almost like the options screen was developed by a different development team or something. Anyhow back to the steps.

2. In the tree view under the code inspection heading click solution wide analysis.
3. Check the checkbox that says "Analyze errors in whole solution" I would have wrote "Analyze Errors" or "Analyze Errors in the whole solution". Now that I have found a grammar mistake please feel free to tear apart my blog posts.
4. Finally click the ok button and ReSharper will start to analyze your code.

If you look at the very bottom right corner you will notice a round icon. This round icon will display as green when the solution has no errors and red when there are errors. Double clicking on the icon will bring up a window that lists all errors. As an added bonus us keyboard junkies can simple press Alt + F12 to jump from error to error. If you would like to jump to a previous error just press Shift+Alt+F12. If you just want to jump to errors on the current page you can press F12.

This feature really comes in handy when you forget to implement a new method or property on an interface. I find that this typically happens when I mock out an object with Rhino Mocks. Everything appears to be fine with the test however a quick glance to the right corner of visual studio tells me immediately that there is an error. From there I just give it the old Alt + F12 and correct the error. Once the icon is green I know that I can build my solution without embarrassment.

What are you doing.... Go turn on this feature... Now... No excuses...

Tuesday, February 12, 2008

ThirdAngle has a Web Site !!!


Check it out, the company that I work for finally has a web site for our division: www.ThirdAngle.ca Just a little background: The company that I work for is called Media Logic. Media Logic has several divisions from software development to marketing to blah blah blah... etc... Anyhow the important thing is that you checkout our divisions web site.