Training

Nothin But .Net Developer Bootcamp

Navigation

Search

Categories

On this page

Video Publishing Formats Redux
Video Publishing Formats
Behaviour Driven Development
One Refactoring Missed
On growth,humility, and students and mentors of Test Driven Development
Applied Test Driven Development For Web Applications - Part 1 (Video)
Thinking About Starting A User Group?
Another Good Question
Applied Test Driven Development For Web Applications Update
The Dark Side Of Declaritive Databinding
ReSharper Updates
Coding to interfaces
Handling Dynamic Rules - A Precursor
Validation In The Domain Layer - Take Two
Sample CC.Net Configuration Section
Automating Your Builds With NAnt - Part 8 Videos
Automating Your Builds With NAnt - Part 8 (Enter CruiseControl)
Automating Your Builds With NAnt - Part 8 (Screenblog) tomorrow
The often forgotten, but extremely powerful IHttpModule and IHttpHandler interfaces
Unlocking Files With Ease
IE Tab In Firefox
Use SlickRun To Detach a Database
Applied Test Driven Development For Web Applications - Part 1
One Of The Reasons TDD Can Be A Hard Sell

Archive

Blogroll

 Agile Developer Venkat's Blog
 Ayende @ Blog
 B#
 Barry Gervin's Software Architecture Perspectives
 Boy Meets World
 Brad Abrams
 Canadian Developers
 Christopher Steen
 Claritude Software News
 Clemens Vasters: Enterprise Development and Alien Abductions
 Coding Horror
 Coding in an Igloo
 Dare Obasanjo aka Carnage4Life
 Darrell Norton's Blog [MVP]
 David Hayden [MVP C#]
 Don Box's Spoutlet
 Eric Gunnerson's C# Compendium
 EZWeb guy: Jeffrey Palermo [C# MVP]
 Fear and Loathing
 Generalities & Details: Adventures in the High-tech Underbelly
 Greg Young [MVP]
 Greg's Cool [Insert Clever Name] of the Day
 IanG on Tap
 Ingo Rammer's Weblog
 ISerializable - Roy Osherove's Blog
 James Kovacs' Weblog
 Jason Haley
 Jean-Luc David
 Jeremy D. Miller -- The Shade Tree Developer
 JetBrains .NET Tools Blog
 Jimmy Nilsson's weblog
 John Bristowe's Weblog
 John Papa [MVP C#]
 Jon Skeet's Coding Blog
 JonGalloway.ToString()
 Jump the Fence or Walk Around
 Lambda the Ultimate - Programming Languages Weblog
 Larkware News
 Lutz Roeder
 Marquee de Sells: Chris's insight outlet
 Martin Fowler's Bliki
 Mike Nichols - SonOfNun Technology
 MSDN Magazine - .NET Matters
 MSDN Magazine - All Articles
 OdeToCode Blogs
 Onion Blog
 Planet TW
 Raymond Lewallen [MVP]
 Rockford Lhotka
 RodMan's Corner
 Roger Johansson's blog
 Sahil Malik - blah.winsmarts.com
 Sam Gentile's Blog
 Scott Bellware [MVP]
 Scott Hanselman's Computer Zen
 ScottGu's Blog
 secretGeek
 Service Station, by Aaron Skonnard
 Signum sine tinnitu--by Guy Kawasaki
 Stephen Toub
 Steve Eichert's Blog
 Steven Rockarts
 The Blog Ride
 The Coding Hillbilly
 The Daily WTF
 TheServerSide.net: News
 Tim Gifford
 Vance Morrison's Weblog
 you've been HAACKED

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

RSS 2.0 | Atom 1.0 | CDF

Send mail to the author(s) E-mail

Total Posts: 337
This Year: 62
This Month: 13
This Week: 3
Comments: 889

 Thursday, June 29, 2006
Thursday, June 29, 2006 8:50:43 PM (Mountain Standard Time, UTC-07:00) ( ScreenCasts )

I originally said that I was going to use a flash format and a torrent file as the media that would be made available to both watch/download the screencast material. I have never used a 3rd party swf viewer (aside from the flash player browser client). Eduardo Laranjeira kindly pointed me to the Swiff player from GlobFX. This is a free player that will allow you to play swf files that you have saved on your local machine, without the need for a browser based player.

This will give everyone the best of both worlds. The swf file will already be on the server available for people to watch on demand through the blog. There will also be an accompanying torrent file that people can use to download (and hopefully seed) the actual swf file to keep on their local machine.

Thanks to everyone who provided feedback and aided me in coming to this decision.

JP out!!

Comments [0] | | # 
Thursday, June 29, 2006 10:03:26 AM (Mountain Standard Time, UTC-07:00) ( ScreenCasts )

After a lot of thought, I have decided that from now on I am going to publish the videos on this site in two formats:

  • A torrent file that will contain the full flash movie and accompanying source code. You could then use a standalone flash player like Swiff to watch the movie on your local machine.

The torrent for the Applied Test Driven Development – Part 1 (Video) can be found here. I have already received some kind offers from people who would like to seed the files also. If you are able to that would be greatly appreciated.

Comments [9] | | # 
Thursday, June 29, 2006 8:42:37 AM (Mountain Standard Time, UTC-07:00) ( Agile )

With the recent buzz (in the .Net world) around behaviour driven development (mostly due to the release of NSpec). I thought I would take the time to make a quick point. BDD is nothing new to people who have already been doing TDD properly. One of the interesting side effects of even just changing the first word in the *DD term is the switch that the mind makes to realizing that TDD done properly or BDD is not about testing. TDD was never meant to be about testing the system, Test Driven Development or the lesser used term Test Driven Design is a pure exercise is designing your production code. Instead of UML class/sequence diagrams you are writing code that “specifies” how your components “behave”.  Notice the emphasis I have placed on the words specifies and behave. The whole test nomenclature can actually be quite a stumbling block for people who are wanting to do TDD effectively.

If you have taken a look at NSpec you will see that they are completely shedding the testing nomenclature. This subtle change alone can have a dramatic effect on people new to the whole “design by code approach”. Why? It enforces the concept that you are not “testing”, you are designing. If you take a look at a quick piece of code demonstrating NSpec in action:

[Context] public class Example { [Specification] public void NewMoneyShouldHaveZeroAmount() { Specify.That(new Money().Amount).Equals(0.00m); } }

Contrast this with a ‘classic’ NUnit approach 

[TestFixture] public class Example2 { [Test] public void TestNewMoney() { Assert.Equals(0.00m, new Money().Amount); } }

Functionally these two pieces of code are equivalent. Notice , however, that the use of the specification friendly terminology provided by NSpec does make intent of the code a bit easier to read (in my opinion).

NSpec as a framework looks promising, I’m not sure if it is ready for prime time yet, but again it is just a framework to aid in the ‘practice’ of BDD.  I think that BDD is the next natural step to enable people who may be struggling with TDD to finally realize that it is not about testing at all, it is about design.

Comments [1] | | # 
 Wednesday, June 28, 2006
Wednesday, June 28, 2006 10:53:32 AM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C# | Patterns | ScreenCasts )

For those of you who are following along with my Applied TDD series there is one refactoring I forgot to do yesterday:

            using (mockery.Ordered())

            {

                Expect.Call(mockTask.GetAllContacts()).Return(mockResults);

                mockView.Contacts = mockResults;

            }

Notice the bolded code. It used to read mockView.Employees. Halfway through the session I decided to first tackle displaying a list of contacts and not employees.

 

Comments [0] | | # 
Wednesday, June 28, 2006 6:38:53 AM (Mountain Standard Time, UTC-07:00) ( Agile )

As a consultant who is often sent in to mentor teams of developers on Agile practices, it is always interesting to see the reaction that a lot of developers have to the practice of Test Driven Development. The reaction that I almost always see (initially) is one of uncomfortability and apprehension. Looking back almost 3 years to when I started practicing test driven development, I have complete empathy for people in that situation. In my personal opinion, when you undertake the task of getting to grips with TDD you have to ask some really hard questions about “what you think you know”. I have found that having a solid OO background is paramount in utilizing TDD effectively on software projects (assuming the OO paradigm is in effect). This is often a time when many developers have to stop and really question their true solid knowledge of fundamental OO concepts. Often times, developers are quite surprised at how much they still have to learn about good object composition and responsibility assignment.

I have seen two different kinds of reactions to this realization. People can choose to humble themselves and realize “hey, I’m willing to admit that although I thought I had OO concepts down pat, I obviously don’t and want to make a change”. These people are “highly coachable”. They are willing to relinquish any assumptions they have about their knowledge of object oriented concepts and essentially relearn a lot of the basics in order to make themselves more effective developers. Of course, this is a process that can happen quite naturally when they are being coached by someone who is trying to teach them  TDD. The other set of people are the ones who are not willing to admit that they may not know as much as they think. They will initially fight the coaching every step of the way because “you can’t teach me anything new”. I have definitely run into my share of these people over the years. Even then, I do not like to put these people into an “uncoachable” category. I believe that once you have gained people’s trust and they realize that you are actually there to add value to their project/skillset, even people who seem “uncoachable” often open up to new ideas. It just takes time.

I like to think of learning TDD as equivalent to learning to snowboard. Lots of snowboarders who have been involved in the sport for a while often encourage new learners to take at least one lesson from a seasoned snowboarder. Half of the new riders will attempt to learn to snowboard on their own. Will they get it? Yes. Will it take longer than if they had picked up tips and tricks from an experienced rider? Yes. Is there a possibility they will develop bad technique? More than likely. Learning TDD on your own is actually very similar. There is no better way to learn TDD than to pair with someone who has been involved in the process for a while. They will be able to pass down techniques and tricks that you can immediately utilize to improve the quality of the tests that you write. They will be able to teach you about the value of using mock object and dependency injection to write more loosely coupled code. They will be able to allow you to identify how to test objects in isolation and how not to test too much at a time.

This brings me to talking about humility for the coach. It does not matter how great I think TDD or other agile concepts are. Often times, teams I go into work with are going to be experiencing these concepts for the first time. I cannot go into these environments with a “Holier than thou” attitude and expect them to be receptive to what I have to show them. Unfortunately, I often have to deal with other issues being the “senior” guy sent in to train these development teams. Anyone who knows me, is aware of how young I look (something that I definitely got hassled for when appearing on DNRTv). It definitely is a cause of surprise when I am sent into meet with new clients and I am being presented as the senior resource and the first thought that pops into the clients heads are “Is he even out of school!!”. Of course, any assumptions about my age are quickly put to rest once people realize I have been married 10 years and have 4 children (the oldest being 9 years old). Once they get over that bombshell!! I can get to the task I was sent in to do. Again, mentors and tech leads, I have to stress this point loud and clear

  • Just because we ‘may’ have more experience and knowledge than the people we are coaching, we are in no way better than that person in any way shape or form.

People might be saying, “well JP, this is just common sense”. I wish it were true. Unfortunately I see this every day, and whole sets of people are being alienated because they are being made to feel inferior as a developer; and worse, as a person. One of the biggest problems a lot of people have when trying to work with people who are coaching them on TDD principles is the fact that the coach really does not have the patience to teach in the first place. Why is patience paramount? 80% of the time spent teaching TDD will actually be time spent unravelling years of bad habits that need to be broken to become effective at TDD.  Often times, these habits are things that the coach also had to break when starting down the TDD path. Which is why it is essential for mentors and coaches to “Remember where you were when you started down this path”. TDD is a paradigm shift for developers, it takes time (just like good OO skills take time and practice to hone) to get:

  • A – Comfortable with the shift
  • B – Proficient with the application of TDD

In conclusion I would like to finish by saying that people can have great success adopting TDD when the right person/people are there to aid them in the process. It takes humility on both parties involved to ensure that the transition is as smooth as it can be. There is a lot of buzz in the industry around TDD and agile concepts right now, and I personally think that is a good thing. There are a handful of good TDD practitioners out there in the blogsphere / presentation circuit who are extremely pumped about spreading the “good news” about TDD. With all that said, every developer individually needs to determine whether TDD is something that works for them. Like anything else in life/software, you need to give it an honest educated shot before discounting it completely. My last piece of advice regarding TDD is this. Anything new in life/software always makes us feel a little uncomfortable. It is our responsibility to either ignore something new, or give it an “educated” shot, before discounting it completely. Don’t discount TDD until you have had the opportunity to see/use it effectively. It has personally changed the way I develop software, and I could honestly say that I couldn't go back to not using it.

If you ever need someone to come in and coach your team / give a presentation on TDD don’t hesitate to contact me. It would be an honour.

Comments [5] | | # 
 Tuesday, June 27, 2006
Tuesday, June 27, 2006 7:56:24 AM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C# | Patterns | ScreenCasts )

I have just finished recording the second session for the ATDD series. The video is approximately 37minutes in length. In this session all that I focus on is getting a presenter and accompanying view working to display a list of Contacts in the AdventureWorks database. Topics that are introduced are:

  • Constructor based dependency injection
  • Interface based programming
  • RhinoMocks for creating mock objects

The completed code and movie are in this torrent.

Any feedback/comments would be greatly appreciated.

Comments [20] | | # 
Tuesday, June 27, 2006 7:50:03 AM (Mountain Standard Time, UTC-07:00) ( Presentations )
If you, or anyone you know, are interested in staring up a user group. The Igloo Coder is documenting his recipe for success in the process that he and his band of accomplices have followed to start a relatively new .Net user group in the city of Edmonton, Alberta. A really good read. Having experienced working with this group, I have great expectations for what they are going to be able to accomplish over the next couple of years.
Comments [0] | | # 
 Sunday, June 25, 2006
Saturday, June 24, 2006 11:09:23 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C# )

Geoff Stockham asked a good question on my "Dark Side Of Declaritive Databinding" post. My comments for that post got all messed up so I am reposting the question for everyone to view, along with the answer:

Q:JP, I've just been flicking through the Wrox ASP.NET MVP Hacks book, and one of the sections is about inheriting from the built-in data sources (such as ObjectDataSuurce) to create more specific domain-based data sources. This set me to thinking that this may be a way to get a "best of both worlds" approach of testability and ease of use. I haven't looked into it yet, but wondered if this might be the way you were thinking?

A: Once you start watching the series that I will be posting on applied test driven development, you will see why I have not found a need to take advantage of controls such as the object data source control. I am not discounting it as a viable solution to build apps with; it is just not the solution I go with. A decent MVP implementation coupled with test driven development, usually leads me down a path that diverges quite far from the solution offered by the object data source and the like.

Comments [0] | | # 
 Saturday, June 24, 2006
Saturday, June 24, 2006 10:33:33 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C# | Patterns )

Hey everyone. I know a lot of people have been waiting patiently for this series, and I don’t want to disappoint. I was sitting down to write entry number 2 and I realized that a lot of the feel and flow can get lost when I write a test, write some code etc, and then write up what I did. I really want to give people a feel for how the process actually works. To this end, I am going to be doing the rest of the series as a set of videos (with accompanying code) that people can follow along and watch. This will give people a much better idea of how TDD actually works, and over the course of the next couple of months, you will get to see the construction of a fairly non-trivial application.

I have to once again apologize for the delay, as I have been extremely busy as of late. I will not be doing any posting whatsoever during the first 3 weeks of July, as my family and I will be heading out for a big vacation!!

I hope to get the first video out by the end of Monday.

Thanks

Comments [3] | | # 
 Friday, June 23, 2006
Friday, June 23, 2006 9:41:09 AM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C# )
Most people who have talked/worked with me know that I am not the biggest fan of the demoware databinding techniques. When choosing to implement databinding in your application you have to decide what you will use as a data source. Of the many sources of data that can be bound to, the most common are

 

-DataSets

-XML

      -Custom Objects

 

I am going to (eventually) focus in particular on the use of the Custom object scenario. I will, however, start by using datasets as for the purpose of contrasting it to my approach. In my first attempt at databinding I will utilize some of the new controls made available in ASP.Net 2.0, namely the new Data Source Controls. Here is the markup required to configure the SqlDataSource control as well as an accompanying gridview to display the information.

 

 

<asp:SqlDataSource     ID="customersDataSource"

      runat="server"

         ConnectionString="<%$ ConnectionStrings:DatabaseConnection %>"

         SelectCommand="SELECT * FROM Customers" />

   <asp:GridView ID="customersGridView" runat="server" DataSourceID="customersDataSource"

            AutoGenerateColumns="false">

            <Columns>

                <asp:BoundField DataField="CompanyName" HeaderText="CompanyName"/>

                <asp:BoundField DataField="ContactName" HeaderText="ContactName"/>

                <asp:BoundField DataField="ContactTitle" HeaderText="ContactTitle"/>

                <asp:BoundField DataField="Address" HeaderText="Address"/>

                <asp:BoundField DataField="City" HeaderText="City"/>

                <asp:BoundField DataField="Region" HeaderText="Region"/>

                <asp:BoundField DataField="PostalCode" HeaderText="PostalCode"/>

                <asp:BoundField DataField="Country" HeaderText="Country"/>

                <asp:BoundField DataField="Phone" HeaderText="Phone"/>

                <asp:BoundField DataField="Fax" HeaderText="Fax"/>  

            </Columns>

        </asp:GridView>

 

And here is the app in action:

 

ScreenShot1

On the surface this all looks great. I’ve developed a fully data driven web page in under 2 minutes and didn’t have to type a single line of code. What could be wrong with that?

 

First, the use of the SqlDataSource control requires that the view have initimate knowledge of the database. The view is responsible for determining where to pull the data from as well as how to display that data. And if it were not for the fact that the connection string was stored in a configuration file, then it would also be responsible for providing a connection string used to connect to the database. This is just plain old poor separation of responsibility.

 

Second and no less important. One of the biggest problems with this method of databinding is the fact that you have to run the application in order to verify that the databinding will work. I’ll prove this by making a small change to the db schema. I’m going to change the name of the “Customers” table to “Customer”. I’ve made the change and rebuilt the db (using Nant of course!!).

 

 

Now I’ll run the app.

 

invalidobject

 

Ouch. And to add insult to injury; the only reason I found this error was by running the app and navigating to the page in question. Not efficient.

 

This is all too common a scenario I experience when going in to mentor teams of developers who are strong proponents of a data-driven approach to application development. One small change can cause ripple effects which are often not realized until the application is run. This is a very slow process and is not conducive to rapid, confident development of application functionality. In future installments I will talk about ways to handle this issue with a bit more style and grace, using a TDD perspective!!

kick it on dotnetkicks.com
Comments [2] | | # 
Friday, June 23, 2006 9:06:06 AM (Mountain Standard Time, UTC-07:00) ( Tools )

In the event that you are a ReSharper 2.0 user. Make sure you stay posted to the following url : http://jetbrains.net/confluence/display/ReSharper/Download to ensure that you can download the latest updates to the program. The main download link for the release product is currently at build 249. The latest version is actually 253 which you can download from the link above.

Develop with pleasure!!

Comments [3] | | # 
 Monday, June 19, 2006
Monday, June 19, 2006 9:33:55 AM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C# | Patterns )

I had an interesting comment to a previous post I made about validation rules:

I'm actually leaning toward limiting the use of interfaces... and here's why.

If your interface defines every aspect of the concrete class, then what's the benefit? I'm guessing you'll say mocking, which is a valid concern. While mocking is a useful testing technique, you can still effectively test the behaviour of your classes.

Interfaces aren't objects, so they do not get the benefits of System.object overrides, such as Equals() or ToString(). I'm all in favor of using interfaces where they are defined well and WILL be reused, but I'd stick with a base class until refactoring proves otherwise.

A colleague of mine suggests to use interfaces for behavior only. He further suggests that defining properties inside of interfaces is a full-on Code Smell.

I'm not 100% sure I agree with him on that, but I do believe that interfaces should focus on behavior, not on non-functional aspects like Name or Id.

All an interface is, is a contract that defines the expected behaviours/attributes an object is supposed to implement (remember, implementing may not necessarily mean defining a body for the method/property itself. I definitely disagree with the statement that interfaces should contain only methods. Although lots of the framework classes leave a lot of room to the imagination, I could name a handful of clean interfaces in the framework that make use of a interfaces ability to contain properties,methods, and events.

I want to stress a point here, in the .Net world we have gotten hung up on the term interface. Remember that this term is overloaded. There is the concept of an interface, but there is also a concept in C# of an interface language construct. You can program to an interface without needing to actually use an interface. This is what people often achieve using a supertype. The fact that you can program to an interface using both an "interface" construct and a "class" construct is irrelevant. The benefit of either approach is to make use of polymorphism by programming to an interface/supertype so that code in the system is not (as much as possible) tied to concrete implementations. Coding to an interface/supertype allows the client code consuming the objects to not care about the object that it is working with, only that it supports a certain 'interface'.

I personally err to the side of using interface constructs to drive out the initial implementations, and then will refactor to a supertype in the event that it is necessary. And even then, I think people often jump to the use of inheritance way to quickly.

Rich interfaces are almost a necessity when you are creating component based systems utilizing the separated interface pattern. In these scenarios you may not want you client to have any knowledge whatsoever of the implementation code you are putting in place. Interface constructs are a great clean way to separate the client code from the actual server implementations (think remoting).

This whole question about interfaces vs abstract classes leads me to leave you with 2 OO/design thoughts to ponder:

  • Favour object composition over concrete inheritance
  • Code to interfaces (interface construct/abstract classes) not implementations 
Comments [2] | | # 
 Friday, June 16, 2006
Friday, June 16, 2006 6:27:34 AM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C# )

I had a great question from Andy MacDonald about my previous post on validation in the domain layer:

Q: Is there anyway that the rule delegates can be stored in a database/xml file as this would provide a really powerful way of implementing ever shifting business rules about age and so forth without having to recompile any of the layers in the application (as well as supporting context rules)?

While I am not going to dive into the question today, I am going to give Andy and others some thoughts to chew on (which should actually enable them to proceed without waiting for part 2 of this post!):

  • A couple of questions you need to ask yourself before answering this question are as follows:
    • “How often does a given rule change?”
    • “Is the end user going to be provided a mechanism to dynamically alter a given rule”?

I am asking these question because I want you to realize that if a rule does not change very often, and the user has not requested a UI that will allow them to manipulate the rule, the effort involved in making the rule more dynamic may not be worth the effort. If you already have an automated build in place, one that allows you to deploy a new version of the app by just typing in the name of a target at the command line. Then the effort involved to “change” a rule every once in a while is next to nothing. Now remember, this deploy on the fly model also works for Windows applications, if you are using a deployment model that allows for automatic updating of the clients (ex. ClickOnce / Updater components). If this is the case, changing a rule involves a couple of steps:

  • Update any tests that utilize the rule directly
  • Update the rule
  • Run the tests
  • Deploy the app

I am suggesting this for infrequent rule changes as it is still a viable option. Being a programmer, and a lazy one at that, makes me try to look for the simplest solution first.

Of course, there are lots of situations where rules can change daily, and different installations of the system utilize slight variations on rules. In these situations, you need to isolate the rules that change frequently from the ones that don’t. For these “dynamic” rules, you can take advantage of the IBusinessRule<T> interface and create implementations that are parameterized with information from external sources. In the example that Andy talks about with the age example, a dynamic rule could be created to take in the minimum and maximum age of people allowed to vote:

 

 

public class ValidVotingAgeRule : IBusinessRule<Vote> { private int minimumAge; private int maximumAge; public ValidVotingAgeRule(int minimumAge, int maximumAge) { this.minimumAge = minimumAge; this.maximumAge = maximumAge; } public bool IsSatisfiedBy(Vote item) { return item.voter.Age >= minimumAge && item.voter.Age <= maximumAge; } public string Name { get { return "Valid Voting Age"; } } public string Description { get { return string.Format("Must be between {0} - {1} to vote", minimumAge, maximumAge); } } }

 

Again, I’ve said it before (maybe not on this blog) and I’ll say it again. I love interfaces. Here I have created a dynamic rule called ValidVotingRule, you construct it using a minimumAge and maximumAge (which could easily come from the database. Notice how even the description is now parameterized based on the min and max age!! Notice also, that it implements the IBusinessRule<Vote> interface, which means that it could be added to any BusinessRule<Vote> instance, which gets passed into the constructor of a Vote class!!

Hopefully this gives Andy and others, some other things to think about!!

kick it on dotnetkicks.com
Comments [7] | | # 
Thursday, June 15, 2006 11:42:11 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C# )

It has been quite a while since I posted the first part of this scenario. I left off in a pretty good place, but now I need to revisit and solve the validation problems that I posed in the first entry:

  • Must be between the age of 18 – 75 to vote (yes there is an upper limit!!)
  • Must live in the country the candidate is running for

As well as the rules for voting, upon submitting a vote the person voting has to supply all of the required voter information:

  • FirstName
  • LastName
  • Age
  • Address
  • Gender
  • CountryOfResidence

We left off with having a Person domain object be able to perform validation. We now need to expand the scope to the vote class. A vote consists of both a Candidate and a Person. With the framework that is already in place, it becomes trivial to add the necessary validation for a Vote Class.

public sealed class Rules { private Rules() { } public static IBusinessRule<Vote> Age { get { return new BusinessRule<Vote>("Age", "Must be between 18 - 75 to vote", delegate(Vote vote) { return vote.voter.Age >= 18 && vote.voter.Age <= 75; }); } } public static IBusinessRule<Vote> Country { get { return new BusinessRule<Vote>("Country", "Must live in same country as Candidate", delegate(Vote vote) { return vote.voter.CountryOfResidence.Equals(vote.candidate.CountryOfResidence); }); } } public static IBusinessRuleSet Default { get { return new BusinessRuleSet<Vote>(Age,Country); } } }

This Rules class lives as a nested class inside of the Vote class. You will notice that the validation is fairly trivial. One thing that I have done is decrease the strong typing of the IBusinessRuleSet interface. Why? I want to have a layer supertype for all of my domain object that contains an IsValid property, and that will also invoke the appropriate BrokenBy method on the rule set. I accomplish this with minimum change required to the actual BusinessRuleSet class by changing the interface of IBusinessRuleSet<T> to the following:

 

public interface IBusinessRuleSet { IBusinessRuleSet BrokenBy(IDomainObject item); bool Contains(IRule rule); int Count { get; } IList<string> Messages { get; } bool IsEmpty { get;} }

With that change in place it means I now require a layer supertype for all of my domain objects:

 

public class DomainObject : IDomainObject { private IBusinessRuleSet rules; public DomainObject(IBusinessRuleSet rules) { this.rules = rules; } public IBusinessRuleSet Validate() { return rules.BrokenBy(this); } public bool IsValid { get { return Validate().IsEmpty; } } }

Notice how all DomainObjects will be constructed with a set of rules against which validation will be executed (great for testing, as well as loosening validation depending on the context). The layer supertype also takes care of performing the validation against itself. Even though it looks like I have lost some strong typing, this is not the case, as the main implementer of the IBusinessRuleSet interface is the BusinessRuleSet<T> class. It is still a generic class, and look at how it now implements the BrokenBy method:

 

public IBusinessRuleSet BrokenBy(IDomainObject item) { IList<IBusinessRule<T>> brokenRules = new List<IBusinessRule<T>>(); foreach (IBusinessRule<T> rule in rules) { if (! rule.IsSatisfiedBy((T) item)) { brokenRules.Add(rule); } } return new BusinessRuleSet<T>(brokenRules); }

Notice, that the BrokenBy method still ensures that the type of “item” is the type that it expects to be able to work with. It does this by performing a cast using the type T that it was constructed to hold rules for. Tests that exercise this method for specific types of objects will fail if the object passed into the BrokenBy call is not of type T.

So by making a small change to the interface we have now allowed for any new domain object  to now inherit from a layer supertype and have and its disposal a Validate and IsValid methods. Here is the first test that I wrote when it came to validating the rules for a vote:

  

[Test] public void ShouldVerifyVoterLivesInSameCountryAsCandidate() { IPerson person = new Person("JP", "Boodhoo", "Test", 20, Country.CANADA, Gender.MALE); Candidate candidate = new Candidate("JP", "Boodhoo", "Test", 20, Country.CANADA, Gender.MALE, Party.CONSERVATIVE); IPerson notInSameCountryAsCandidate = new Person("JP", "Boodhoo", "Test", 20, Country.USA, Gender.MALE); Vote vote = new Vote(person, candidate); Assert.IsTrue(vote.IsValid); vote = new Vote(notInSameCountryAsCandidate, candidate); Assert.IsFalse(vote.IsValid); }

As you can see, small focused tests can help drive out lots of functionality. Last but not least is the introduction of a PollingStation class, that makes use of all of the code we have put into place:

 

 

public class PollingStation { private IList<Vote> invalidVotes; private IList<Vote