The Norwegian Developers Conference was held last month on June 17-19th. From all accounts this conf was bordering on epic. The videos of each session have been posted on the website and it might be worth taking a look at them.

Some points of interest:

Michael Feathers

Scott Hanselman

Uncle Bob Martin

Udi Dahan

Ted Neward

Jeremy D. Miller

Roy Osherove

Ayende Rahien


 
Categories: Development | Events

I have been working a lot with JQuery recently. It is rapidly becoming a core library for doing client side scripting in our primary application.

I discovered a great video series last night intended to introduce you to JQuery from the ground up. The first one is located here. They are a great way to learn the basics.


 
Categories: Development | JQuery

This one is for all my contractor buddies out there.

Stolen from {CodeSqueeze}.


 
Categories: Commentary | Random

During the Olympia Software Craftsmanship Workshop last weekend, Jeff Olsen (@olsonjeffery) demonstrated the use of the web testing framework Selenium. I was really impressed with the Selenium IDE and how easy it was to use in Firefox. One of the menu items of the IDE is to export a test as C#.

Export

This piqued my curiosity and I wanted to find out exactly what it takes for a .NET developer to get started using Selenium. This post is intended to help others get started.

First, a list of the stuff you will want to download:

You can get started right away by simply downloading the Selenium IDE for Firefox. There is a great tutorial here that will guide you through getting started. The other downloads are not required to use the IDE.

If you want to integrate your tests into your build process or write tests as if they were unit tests, you will need the two asterisked items at a minimum. The Selenium Remote Control comes in two parts. There is a server that runs under the Java Runtime Environment and several Client libraries for just about any flavor of programming you may prefer.

SeleniumRC

As, you can see I have added a batch script to launch the server on my local machine. The file contains a single command:

"C:\Program Files (x86)\Java\jre6\bin\java.exe" -jar selenium-server-1.0\selenium-server.jar

If you run the batch script, this is what you will see.

SeleniumRunning

Selenium is now listening on its default port of 4444 for commands from the client library. The server portion of Selenium can run anywhere. It would be fairly easy to set it up to run on a VM or on your build server with minimal effort.

So now let's write some tests. This blog has a built in administrative system. After you authenticate, a link bar is displayed with the various administrative tasks. A simple set of specifications, might look like this:

  1. When authenticating with valid credentials, the configuration menu link should be present.
  2. When authenticating with invalid credentials, the configuration menu link should not be present.

Let's start by creating a new test assembly. I called mine NotMyself.Blog.Specifications. Simply create a new Class Library and call it what ever you want. Next add references to nmock, nunit.core, nunit.framework and ThoughtWorks.Selenium.Core located in the selenium-dotnet-client-driver-1.0 folder in the Selenium Remote Control distribution.

References

I am not sure if there is a direct dependency on nmock or nunit for that mater. ThoughtWorks.Selenium.Core.dll is the meat & potatoes here. In a future post, I'll try getting up and running with MSTest or MBUnit.

To execute against the Selenium Server, we need to do some set up. The following base class demonstrates what is needed.

using System;
using System.Text;
using NUnit.Framework;
using Selenium;

namespace NotMyself.Blog.Specifications
{
public class SeleniumTestContext
{
protected ISelenium browser;
protected StringBuilder verificationErrors;

[SetUp]
public void SetupTest()
{
browser = new DefaultSelenium("localhost", 4444, "*iexplore", "http://iamnotmyself.com/");
browser.Start();
verificationErrors = new StringBuilder();

Context();
BecauseOf();
}

public virtual void Context() { }
public virtual void BecauseOf() { }
[TearDown]
public void TeardownTest()
{
try
{
browser.Stop();
}
catch (Exception)
{
// Ignore errors if unable to close the browser
}
Assert.AreEqual("", verificationErrors.ToString());
}
}
}

The above class sets up a couple fields and then news up a DefaultSelenium object. This object takes four constructor parameters; the URL hosting the Selenium Server, the port the server is running on, a string that represents the browser we want the tests run in (in this case IE, but we could use "*chrome" to use FireFox) and finally the root URL of the site we are testing.

Next up let's create a context for our authentication tests.

namespace NotMyself.Blog.Specifications
{
internal class AuthenticationContext : SeleniumTestContext
{
protected string authenticationUrl = "/notreallythe/pathtomy/page.aspx";
protected string badPassword = "reallynotmypassword";
protected string goodPassword = "notreallymypassword";
protected string userName = "notreallymyusername";
}
}

This class simply allow me to share some information across multiple test classes. Finally we are ready to write our tests.

using NUnit.Framework;

namespace NotMyself.Blog.Specifications
{
[TestFixture]
public class When_Authenticating_With_Valid_Credentials : AuthenticationContext
{
public override void BecauseOf()
{
browser.Open(authenticationUrl);
browser.Type("LoginBox_username", userName);
browser.Type("LoginBox_password", goodPassword);
browser.Click("LoginBox_doSignIn");
browser.WaitForPageToLoad("30000");
}

[Test]
public void The_Configuration_Menu_Link_Should_Be_Present()
{
Assert.IsTrue(browser.IsElementPresent("_ctl6_hyperLinkEditConfig"));
}
}

[TestFixture]
public class When_Authenticating_With_Invalid_Credentials : AuthenticationContext
{
public override void BecauseOf()
{
browser.Open(authenticationUrl);
browser.Type("LoginBox_username", userName);
browser.Type("LoginBox_password", badPassword);
browser.Click("LoginBox_doSignIn");
browser.WaitForPageToLoad("30000");
}

[Test]
public void The_Configuration_Menu_Link_Should_Not_Be_Present()
{
Assert.IsFalse(browser.IsElementPresent("_ctl6_hyperLinkEditConfig"));
}
}
}

These tests simply issue commands as if it were interacting directly with the browser telling it to open a URL, type some text into form fields, click a button. Validation works the same way, I interrogate the browser to see if specific elements exist.

Finally, all we have to do is fire up the Selenium Server by running the batch script, load up our test assembly into our favorite test runner and watch the tests execute. If you are running the Selenium Server locally you can sit back and watch the browser fire up and the tests execute right before your eyes. Very cool.

TestResults


 
Categories: Development | Tools | Unit Testing

How did they go from version 1.0 of Entity Framework directly to 4.0?

Anyway, here is a nice overview of the new model first story that Microsoft has baked into the new EF in Visual Studio 2010.

After having watched this I have upgraded my impression of EF from “Complete Garbage” to “Not Entirely Horrifying”.

The RAD editor gives me pause as that is a sure sign of generating garbage behind the scenes. Is it human readable/modifiable?

The original EDMX format was incredibly brittle and very anti-source control system friendly. Have they made improvements to that?

I’ll have to play with it this weekend and see what it is like to actually build a simple app with it.

It is nice to see that MS is listening and at least attempting to play catch up with nHibernate. Would be interesting to do a feature by feature comparison between the two.


 
Categories: Random | Tools

Work on the Olympia Software Craftsmanship Workshop is coming along nicely. We announced the workshop on May 5th and have 20 people signed up already. If you are interested in attending, secure your seat ASAP. Only 15 seats left.

So what progress has been made on the materials? The amazing Trevor has been working hard on our customer personae. Not only has he created a great set of user stories, for our fake customer but he has also gone off and created a whole online presence as well. If you are planning to attend, be sure to get familiar with our customer, the more we understand their business the better crafted our solution will be.

Our workshop is focused on taking an existing application and applying principals and techniques of quality software development to make the application more maintainable and easier to add new functionality to.

This requires that we have an existing application. So this last weekend I began working on version 1 of SUFORS, the State UFO Reporting System. Version 1 of SUFORS is intended to be built using the MSDN recommended style of development. So I have attempted to lean on Visual Studio to do most of the heavy lifting for me.

For example, lets examine the Citizen Detail page. In this page I have used the Visual Studio designer to create and configure three SqlDataSources that feed data to a GridView, DataList and DetailsView. The SqlDataSources use a set of CRUD stored procedures to interact with the database. Combined this gives us a nicely crafted page consisting of the Citizen's personal information, a list of any internal "Concern" flags and a tabular view of all the Reports submitted by that Citizen.

The page also has some preconfigured actions. The table of reports obviously links off to a Report Detail page. The menu content area is populated with options to Edit the current Citizen, Add a new Report or simply Cancel out of this page and return form where ever you came from.

So as you can see SUFORS is not your average, sample application. It will be fully functional. It would be awesome of all the attendees would download the current version and become familiar with it. Also keep your eyes on the source control repository for updates as we add new features over the next couple weeks.

The other members of the team (Chris, Justin, Jeff, Robin, Anne & Shanah) are planning to meet at this weekends ALT.NET Seattle meeting to work out some more details. I'll post again afterwards to keep you up to date on any new material or changes.

Looking forward to seeing you all there and having a great time at the workshop.


 
Categories: Events | Local

A few friends and I from ALT.NET Seattle are putting on a software workshop right here in Olympia. Chris did a great job of describing it, so I will quote him:

Some of us folks from ALT.NET Seattle have been working on putting together a workshop for developers in Olympia, WA, focusing on Software Craftsmanship – which, to us, means caring about our craft and applying the principles we know work to what we are doing. The workshop is inspired by some of the discussions started in the much despised, “Why So Mean” session at the recent Seattle ALT.NET conference, as well as discussions in the follow up (and less controversial) “ALT.NET Pedagogy” session, as well as what @briandonahue has been doing in Philadelphia with the “Foundation Series.”

I am hoping this will raise the bar a little bit and get more people walking the walk. My view has always been that we all have to work together, so better to get everyone up to speed on what’s working and what’s not, and for as many people to be passionate and excited about the work they are doing as possible.

And here is the official announcement:

You’re at work and you catch yourself writing another 100 line method that you can’t test and really can’t even understand. You scour the Internet for ideas but there are so many ideas. Some say don’t test, others says don’t test anything, still others say test every keystroke! You just let your head drop to your desk with a solid thud. You think to yourself, “Is this really the best I can do?”

The Olympia Software Craftsmanship Workshop is one day workshop, developed with the intention of increasing the level of awareness of practices and skills that can improve our software.

Any developer interested in improving and learning new skills is welcome. If you can bring a laptop, please do. We will provide the software you need. If you can’t bring a laptop, don’t worry, you can pair up with someone who has one.

 

What: Olympia Software Craftsmanship Workshop

Where: Olympia Center, 222 Columbia St NW, Olympia, WA 98501

When: Saturday June 6, 2009.  10 am to 4 pm

How much does it cost? $25.00 to cover the cost of the facility and lunch. Seating is limited to the first 35 people to both register and submit a payment.

How do I sign up? Go to www.olympiasoftwarecraftsmanship.org

The workshop is hosted by members of the South Sound.NET users group and Alt.Net Seattle who want to help others build better software.

For more information: http://github.com/altnetseattle/olympia_software_craftsmanship_workshop/tree/master


 
Categories: Development | Events | Local

For whatever sadistic reason, I signed up to give not one, but two, presentations at the upcoming Portland Code Camp. I have also made a commitment to Chris Bilson to come up to Tacoma to present on nHibernate in support of the Lunch Time Speakers Group. So in an effort to kill two birds with one stone, I sat down today and whipped up a outline of what I intend to present. Your thoughts, comments, suggestions & ridicule are welcome.

Introduction to ORM with nHibernate

What is ORM?

  • Object/Relational Impedance Mismatch
  • Pros
  • Cons

The Basics

  • What Do I Need To Get Started?
  • Mapping Part I: Class Map XML
  • Configuration Part I: How Do I Connect to My Database?
  • nHibernate Config file
  • web.config or app.config
  • ISession
  • ISessionFactory
  • Configuration
  • ITransaction
  • Unit of Work Pattern

A Better Way

  • Mapping Part II: ClassMap<T> For the Win!
  • Mapping Part III: AutoMapping Using Conventions
  • Overriding for Special Cases
  • Configuration Part II: The Fluent Configuration API

Querying

  • Hibernate Query Language (HQL): Just Say No
  • Criteria API
  • The New Hotness: Linq to nHibernate

Tricks of the Trade

  • Generating Schema  From The Object Model
  • Updating Schema When The Objects Change
  • Integration Tests That Validate Your Mappings
  • Using SQLLite To Make BDD Style Tests Lightening Fast

Resources

  • nhforge.org
  • fluentnhibernate.org
  • summerofnhibernate.com
  • nhibernate in action from Manning

 
Categories:

Earlier today, I blogged about a Kobayashi Maru situation I found myself in with the code base which must not be named. I was stuck making the choice between completely destabilizing our code base at the end of a sprint while trying to track down all the possible side effects of fixing the root cause of my problem or putting yet another little hack into our code.

Over lunch, I was describing the situation to Terry, one of our other developers. We came to the conclusion that we needed to go with the hack method to meet our obligations to the Scrum Master, but we should get the root cause of the issue in the backlog so we could resolve it later.

But this means that our hack would be in place in a fairly unobvious place and in 6 months when we get the item into the sprint backlog, we might fix the issue but forget to remove the hack.

Typically this is solved by adding a "TODO:" in the comments right by your hack to remind you to remove it in the future. Our code base is littered with them.

ToDoWTF

Notice the one from 2005. :-( And these are only the comments that happen to have "TODO:" in them. Obviously, we need a better way to remind ourselves to go back and take care of housekeeping tasks when we change the system.

Then Terry said, "Wouldn't it be awesome if we had a test that would fail if this condition changes?" and the light went off. We talked about it some more and as soon as I got back to the office, I created a new utility project called TestTools.HackToDos. I then wrote two specification style tests.

The first test demonstrates the low level call that causes the issue:

[TestClass]
public class When_Cleaning_A_DataTable_With_Null_Dates : GridViewHacksContext
{
protected override void BecauseOf()
{
Tools.Instance().CleanData(dataWithNulls);
}

[TestMethod]
public void The_Nulls_Will_Be_Converted_To_Invalid_Dates()
{
dataWithNulls.Rows[0].Field(0).ShouldEqual(DateTime.MinValue);
}
}

The second test demonstrates what I would like to happen:

[TestClass]
public class When_Binding_GridView_To_DataView_With_Invalid_Dates : GridViewHacksContext
{
protected override void BecauseOf()
{
Tools.Instance().CleanData(dataWithNulls);
grid.BindData(dataWithNulls.DefaultView, layoutManager.Columns);
}

[TestMethod]
public void The_Invaid_Date_Should_Be_Hacked_Out()
{
Assert.IsTrue(String.IsNullOrEmpty(grid.Rows[0].Cells[0].Text));
}
}

Running these tests resulted in the first test passing and the second failing. I then introduced my "hack fix" as a part of my extension methods to GridView:

private static void hackOutBadDates(GridView grid)
{
foreach (var row in grid.GridDataRows())
{
foreach (TableCell cell in row.Cells)
{
if (cell.Text.Contains(@"01/01/0001"))
cell.Text = null;
}
}
}

Now both tests pass. And my lovely jQuery awesome grid now displays null dates correctly.

yagniYAY

Now I can safely check this code in and feel like I performed my boy scout duty today without feeling dirty. In 6 months when someone on the team gets the sprint item to fix our goofy handling of null values in data tables, my first test is either going to fail or even fail to compile. That dev will go look at the test and find himself staring at this comment block:

/// 
/// TODO: this spec demonstrates a low level flaw in our dataaccess layer where
/// DateTime columns in a DataTable are set to a value of DateTime.MinValue
/// after every read. When we attempt to bind a Grid View to the resulting DataTable
/// null dates are displayed as "01/01/0001" which DateTime.Parse throws as invalid.
/// I have added a hack to our grid view extension methods that fixes this problem.
/// If these tests fails, it might be because we fixed the low level issue and
/// the hack should be removed along with these tests.
///

And there you have ToDos that are enforced by unit tests.


 
Categories: Development | Unit Testing

YAGNI, "you aren't gonna need it" (should maybe have a sub-principal of "will prolly come back around to bite you in the ass later"), is a principal that gets tossed around a lot to keep gold plating developers like me in check. I just love traveling down bunny trails adding "wouldn't it be cool if..." features to the code I am working on. I recognize this this fault in myself and routinely stop to ask myself, "why am I doing this?" or "how does this relate to the task at hand?" maybe even a "what effects could this have in other areas of the system?" on occasions where I am feeling extra saucy.

I wish someone had asked those questions of the person who wrote this code that I discovered deep in the bowls of "the code base that must not be named".

public void CleanData(DataRow row, int upperLimit)
{
if ((row == null))
{
return;
}

//Look at each field in this row
for (int i = 0; i <= upperLimit; i++)
{
//If this field is null, change the value of the field to some type of empty value
if ((row.ItemArray.GetValue(i)) == DBNull.Value)
{
// Handle all possible types of data in a datatable
switch (row.Table.Columns[i].DataType.Name)
{
case "Boolean":
row[i] = false;
break;

case "Byte":
row[i] = (byte) 0;
break;

case "Byte[]":
row[i] = 0;
break;

case "DateTime":
row[i] = DateTime.MinValue;
break;

case "Decimal":
row[i] = (decimal) 0;
break;

case "Double":
row[i] = (double) 0;
break;

case "Int16":
case "Int32":
case "Int64":
row[i] = Conversions.ToInteger(0);
break;

case "Long":
row[i] = Conversions.ToLong(0);
break;

case "Short":
row[i] = (short) 0;
break;

case "Single":
row[i] = (float) 0;
break;

case "String":
row[i] = "";
break;

//If a type shows up that is not handled, throw a meaningful exception
default:
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture,
Resources.InvalidConversionDataType,
row.Table.Columns[i].DataType.Name));
}
}
 

Now at first glance, this doesn't seem that bad. A very nice example of gold plating. I can hear the developer now saying to him or herself, "wouldn't it be cool if we never had to check for DBNull? Seriously that would be jalapeno hot!"

I wonder if the developer was thinking about this possible unintended consequence that I am currently working to resolve.

yagnidoh

So, now I have nonsense dates being rendered out to my page. Trying to address this issue at the source, I commented out the line that sets dates to a min value in the clean data method to see what happens.

yagniuberdoh

Well that is interesting. To make it perfectly obvious _StaffMember is a hashtable. And the value of it's Staff_Lockout_Datetime key is and empty string. And this error is being caused by me switching a low level data clean up method to not change a null value to a invalid date.

So how is this hashtable created? Once again, deep in the bowls of the code base is a method called ToHashtable that takes a datarow and returns a hashtable. The interesting block of code is below.

 

For i As Integer = 0 To tableRow.Table.Columns.Count - 1

If tableRow.IsNull(i) Then

'Convert nulls to 0 or "" before putting in hashtable
Select Case tableRow.Table.Columns(i).DataType.Name

Case "Int64", "Int32", "Int16", "Decimal", "Double", "Single"

'Numeric data types
If convertDBNullIntToZero Then
ht.Add(tableRow.Table.Columns(i).ColumnName, 0)
Else
ht.Add(tableRow.Table.Columns(i).ColumnName, "")
End If

Case Else

'String, DateTime data types
ht.Add(tableRow.Table.Columns(i).ColumnName, "")

End Select

Else
'blah blah blah
End If
Next

 

So once again we have some gold plating here attempting to prevent other developers from having to check for null values. The interesting thing is why are we checking for nulls on a row that has already been though the clean process when the dataset was retrieved from the database? It seems to me this block of code has never been hit before today. Maybe our gold plate-ers are not comparing notes on all the filigree they are adorning our objects with.

The icing to this cake is the line of code where it all blows up. Look at it. What are they really trying to do?

If CDate(_StaffMember("Staff_Lockout_Datetime")) <> CDate(Nothing) Then

All they really want to know is if the hash table value is null. Exactly what our gold plate-ers have so desperately been trying to hide from us.

So I am left with two choices:

  1. Attempt to locate all the areas in the entire application where this gold plating has caused assumptions and correct them to let null dates make their way out the UI and hope like hell I don't introduce more bizarre side effects.
  2. Come up with some goofy databinding or prerender hack to work around the invalid dates.

Both options leave a bad taste in my mouth and a strong desire to drown my sorrows with a nice Irish whiskey.


 
Categories: Development | Fundamentals