RSS Feed

Tuesday, August 19, 2008

Tarantino Gets Noticed!

This is my second blog post today - a first for me!  I just noticed that Gabriel Schenker did a really nice write up on Tarantino Database Migrations.  As with my blogging, I kind of assumed Headspring would be the only user of Tarantino when I open-sourced the project on Google code.  It's very flattering to see someone like Gabriel take the time out of his day to document the project.

As Jeffrey Palermo mentioned, we're always looking for contributors.  In particular, an Oracle guru that could add Oracle support would be very welcome :).  However, if we don't get a contributor, I plan to add Oracle support before the end of the year to support my current project.

Happy Migrating!

NAnt and Setup Projects (*.vdproj)

If you're like me, you're lazy. And last night, while on my couch watching the Olympics, I attempted to do a simple thing - compile a solution containing a setup project (.vdproj) from NAnt. After all, when you're distributing a Windows Forms application to a non-technical audience, it's natural to want an installer to bootstrap to the .NET framework, copy the application to the program files directory, and create an icon on the desktop and start menu. To enhance efficiency through automation, it's also natural to want to build the software on a build server instead of manually on a developer workstation. Let's just say it took longer than a few heats of the 100m butterfly to complete this simple task. Hopefully I can decrease that learning curve for you, my fellow developer.

My first thought was, "I'll use msbuild to compile the solution". It's completely logical, but unfortunately impossible. vdproj files can only be compiled by Visual Studio. After about an hour of scouring the Internet in denial and throwing up in my bathroom, I accepted this *enormous* limitation. Apparently this issue has been known by Microsoft since at least 2004, but they haven't had time to address it. Most likely this time was instead spent pursuing the Microsoft dream. By the way, in the Microsoft dream a non-technical website administrator drags their entire SQL Server database onto the ASP.NET "design surface" and selects the publish option from the build menu.

The next problem that arises is: how do I call Visual Studio from NAnt? What executable and command-line arguments do I use? How do I dynamically determine where Visual Studio is installed? Below is some NAnt code that answers these questions:

hive="LocalMachine" />

echo message="IDE Directory is ${ide.dir}" />

commandline="src\XYZ.sln /Clean"/>

commandline="src\XYZ.sln /Rebuild Release"/>

There are a couple of ways of skinning this cat, but reading the Visual Studio 2008 path out of the registry actually turns out to be the simplest solution. I hope this helps somebody else out some day.

Thursday, August 14, 2008

Ready, Set, Panic!!!

I saw a TV commercial recently that reminded me of what it's like for developers learning advanced object-oriented development techniques. The commercial showed a golfer standing in front of a golf ball, club in hand. Before he swings, he thinks about all of the tips his friends have given him about golf:

1. Pretend you're sitting sideways on a horse
2. Pretend your arms are limp spaghetti noodles
3. Pretend you're standing in two feet of water
4. Pretend you're wearing a tractor tire around your waist

He's thinking about so many things that instead of hitting the ball, he releases the club in his backswing and nails his caddy - after all, he forgot to grip the club. I couldn't find the clip on YouTube, but I found something very similar to give you an idea:

I had a similar experience when learning to water-ski on one ski. I didn't get on top of the water until I realized the only thing I needed to remember was to push hard with my back foot. That was it - when the boat engine roared, I pushed with my back foot. Viola!

When I began working for Jeffrey Palermo, I struggled to find a common theme to guide my development decision making. The list of rules to follow when writing maintainable, object-oriented software is immense:

1. Don't repeat yourself (DRY)
2. Liskov Substitution Principle (LSP)
3. Single Responsibility Principle (SRP)
4. Scoping
5. Design patterns
6. Loose coupling
7. Strong cohesion
8. Small classes
9. Limited dependence on infrastructure
10. And on, and on

For developers dedicated to excellence (but unfamiliar with advanced OOP), the list above can basically prevent them from ever writing any code. In my case, what will Jeffrey think of the code I commit? How do I *know* I'm not writing the legacy code that will torture my team in the future? Is there a simple rule I could follow (like pushing with my back leg) that I can focus on to be successful?

Fortunately, I found just such a rule to address all of the concerns listed above. It is... drum roll... 100% Unit Test Coverage. Specifically:

1. Unit test every meaningful input combination
2. In Onion Architecture terms, test the behavior of only one domain object or service at a time
3. Test all delegation from one class to another
4. Keep your tests small and readable


By testing all delegation logic, you're almost forced to define an interface for each of your services so you can mock them when unit testing the classes that depend on them.

By testing every meaning input combination, you're forced to break up code into small, simple classes. Methods with high cyclomatic complexity will create too many input combintations. A class with 16 input combinations can often be broken up into two classes with four input combinations each. You just cut the number of test cases in half (4 + 4 = 8, 4 * 4 = 16).

By unit testing your classes, you prevent any dependencies on infrastructure. For example, you can't include code like DateTime.Now directly in your classes. Otherwise, you'll need to reset your system clock to produce a predictable unit test result - yuck.

You'll quickly find yourself learning design patterns because design patterns allow you to break large logical structures into small, individually testable classes.

The mistakes you do make will be small and easy to correct. After all, your unit test suite will catch any refactoring mistakes you make.

The next time you're feeling overwhelmed keeping up with the Palermos, Millers, and the like, challenge yourself to achieve 100% Unit Test Coverage. If you're like me, you'll find it rarely leads you astray.

Friday, August 1, 2008

Conventionalism over Confucianism

Since the .NET 1.0 Beta was released in 2001, I've been firmly in the .NET camp. However, there is (at least) one thing that the Ruby-on-Rails guys really nailed - Convention over Configuration.

How should I organize my solution? What should I name my views? What should I name my product category table this time (tblProductCategory, ProductCategory, or product_category)? How should I test my data access layer? In my opinion, the best answer to these and the thousands of other trivial decisions we make as developers every day is "You tell me" or "I'll tell you", but let's be consistent.

During my time as a developer, I have made two observations about (non-Headspring :) ) developers. First, most developers feel entitled to largely contribute to these kinds of decisions or outright make them for themselves (and thus not be consistent with the rest of the team). Second, in pursuing their agendas, they feel justified in spending hours arguing the relative merits of their trivially different positions.

On the surface, this may seem like a plus. "Isn't it great that our developers are so passionate about pursuing perfection?" In practice, though, all this philosophizing about casing, underscores, solution organization, and other small issues comes at a price. That time is not spent thinking about software licensing, golf-club fitting, apartment locating, and Sarbanes-Oxley compliance (my last several projects). In short, it's not spent thinking about how to address the difficult business problems we were hired to alleviate through technology.

This is where clearly defined and rigorously practiced technical leadership is worth its weight in gold. Like in any discipline, a good leader relies on his or her own experience and seeks the input of other team members. The leader than aggregates all of this information, makes a decision, communicates the decision, and ensures compliance (through carrots and sticks). While developers tend to fear strong technical leadership, good leadership makes everybody more comfortable in their role by providing clear expectations. It also greatly increases team effectiveness (by eliminating wasteful discussions) and the likelihood of delivering software that truly meets the needs of the business.

This technical leadership is particularly important in the land of .NET. Let's face it - the development techniques Microsoft promotes in its sales demos, certified training curricula, and Patterns and Practices website do not generally constitute solid software engineering practice. For example, with the exception of Scott Guthrie and Scott Hanselman, I have yet to find anybody in Microsoft even talking about test-driven development.

To this end, Jeffrey Palermo has been working hard to harden the definition of the Onion Architecture. For at least our Headspring team, this architecture will provide guidance to better enable our technical leaders to move quickly and deliver excellence.

Wednesday, July 30, 2008

The Holy Grail - Application Development without Developers

If you've made it this far, I can tell you that the title is tongue-in-cheek. No throwing things at me or unsubscribing (thus cutting my readership in half).

Over the course of my career, I've seen attempts on various projects to eliminate the need for ongoing developer involvement in system maintenance. The argument goes something like this: If we could just build a flexible business rules engine, we wouldn't have to call the developers every time we need to update our FILL IN THE BLANK.

Don't get me wrong... there is definitely a time and a place for application configurability. It's just that business owners (egged on by developers looking for a good challenge) tend to over-extend the concept. For example, they may foster the creation of a new micro-language for defining pricing rules. Something like:

IF ($PRICE$ > 100) $PRICE$ * .90 --> $PRICE$ ELSE $PRICE$

Given that I personally know both people who read my blog, I know you could implement the parser to apply this business rule. And why not? Now my business owners can be in complete control of their pricing rules! We're not just talking a few canned rules... No, I mean autonomous, unbridled, master-of-your-own-universe power!

But there are a few catches. What happens when my business owner misses a closed parentheses? Well, it's back to the drawing board to write a user-friendly syntax checker (a.k.a. compiler). But then, they forget the symbol for manufacturer cost and complain (which is, of course, $MFG_COST$). Well, it's probably time for documentation (language specification) and macro-builder (IDE). The next complaint you get is "My pricing rules are getting really hard to enhance without messing them up." Well, this time (again because I know who my readers are) you realize you'll need to implement a unit testing framework and educate your business owners on Test Driven Development.

By now, however, the gig is up. You don't know how to implement a unit testing framework for your new language, POOP (Pricing Open Operation Protocol). However, you've now spent 20% of your career developing it, its compiler, it's language specification, and its IDE. You're highly invested - it's no time to abandon POOP now!

You forge on... You begin gathering pricing requirements from your business owner (if only you could just program all day), implementing them, and demonstrating them for acceptance. It's just that you're life is harder than it used to be. You used to have a powerful, expressive language (C#), complete documentation (MSDN), whiz-bang development tools (Visual Studio & Resharper), and unit testing framework (NUnit). Now you've just got POOP.

Friday, July 18, 2008

Welcome to Headspring!

In what has become a growing trend, we've recently brought on two outstanding new team members: Blake Caraway and Duane DeRouen.

Blake comes to us from Callaway Golf Interactive where he led teams to implement distributed e-commerce systems. Blake is a technology thought leader and has experience working with clients to define what they really need (as opposed to what they initially think they need).

Duane joined us officially after playing an instrumental role at our largest client. His expertise in project and account management will be vital to our company's continuing success.

On a personal note, my biggest motivation in being on the leadership team of a small company has always been to have the opportunity to work with the very best people. Our two newest hires exemplify that excellence in their work, and I can't wait to spend more time in the trenches with them.

Saturday, July 12, 2008

A little help with the .NET WinForms TreeView

So here's the situation: you're developing a .NET WinForms application that needs a TreeView. Obviously, there are a lot of tree controls out there from Infragistics, DevExpress, etc. but you may find that the .NET 3.5 TreeView is sufficient. As I discovered this week, there are likely two issues you'll face when you use the TreeView.

First, when the tree loses focus, the selected node no longer appears highlighted. Maintaining the highlight can be useful if the TreeView is used in conjunction with other controls to help a user navigate or enter data. In these cases, the highlighting can help provide context to the user about the current state of the application.

Second, there is no ideal event for handling what would seem to be the most basic TreeView event - a user selecting a node. How is this possible? Sure, there's the AfterSelect and NodeMouseClick events, but they're both lacking in their own way. The AfterSelect event is close but it isn't fired a second time when you click on the same node twice. The NodeMouseClick event would seem like a good choice, but it isn't fired when the user navigates to a node using the keyboard (for example using the up and down arrows).

Here's a little code to address both issues:

Issue #1:

In your form constructor, attach a handler to the BeforeSelect and AfterSelect events of the TreeView (trv):

trv.BeforeSelect += trv_OnBeforeSelect;
trv.AfterSelect += trv_OnAfterSelect;

In the BeforeSelect event handler, add the following code:

private void trv_OnBeforeSelect(object sender, TreeViewCancelEventArgs e)
if (trv.SelectedNode != null)
trv.SelectedNode.BackColor = SystemColors.Control;
trv.SelectedNode.ForeColor = SystemColors.ControlText;

I've used the Control and ControlText colors because I've set the background color of the TreeView to Control. I think by default the background color is SystemColors.Window.

Next, add the following code to the AfterSelect event handler:

private void trv_OnAfterSelect(object sender, TreeViewEventArgs e)
e.Node.BackColor = SystemColors.Highlight;
e.Node.ForeColor = SystemColors.HighlightText;

// Handle the Node Selection Here...

That's it! Every time a node becomes selected, it's background and font color is set to the highlight color (typically blue background with white text). Every time a node is deselected (just before another node is selected) its color scheme is returned to the default.

Issue #2

To solve the second issue, hook up the following two event handlers in your form constructor:

trv.AfterSelect += trv_OnAfterSelect;
trv.NodeMouseClick += trv_OnNodeMouseClick;

Now, enter the following code in the corresponding event handlers:

private void trv_OnAfterSelect(object sender, TreeViewEventArgs e)
// Handle the node selection

private void trv_OnNodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
if (trv.SelectedNode == e.Node)
trv_OnAfterSelect(sender, new TreeViewEventArgs(e.Node));

Obviously, the "magic" for this one happens in the second handler. Here, we simply check to see if an already selected node has been clicked. If it has, we delegate to the handler for the AfterSelect event passing in the node that was clicked on.

Hope this helps!

Everything starts small...

Although I realize those reading constitute a (very) small group, welcome to my first blog post. Reaching even the most impressive destinations always requires a small first step - I hope this post will serve as that step. As I stated in the blog's description, my immediate goal in creating this blog is to disseminate valuable insight that will ultimately help Headspring better serve our clients by delivering the most value possible within our clients' budgets. Since this is a goal common to all IT organizations, others may find the information valuable also. However, my first allegiance is to the guys (sorry, no female consultants yet) who get up every morning to build outstanding software for our clients and by so doing grow our company's reputation and future prospects.

A sincere thank you to Jeffrey Palermo (or for those likely reading, just Jeffrey) for his continued mentorship. He's taught me far more in the past two years about software development than I learned in the preceding ten.