About Me

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

 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 [1] | | # 
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 Sharp | 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 Sharp | 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 [21] | | # 
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 Sharp )

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 Sharp | 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 Sharp )
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 Sharp | 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 [6] | | # 
 Friday, June 16, 2006
Friday, June 16, 2006 6:27:34 AM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C Sharp )

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 [8] | | # 
Thursday, June 15, 2006 11:42:11 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C Sharp )

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> validVotes; private IList<IPerson> incompleteVoters; private int voteNumber; public PollingStation() { invalidVotes = new List<Vote>(); validVotes = new List<Vote>(); incompleteVoters = new List<IPerson>(); } public void RegisterVoteFor(IPerson person,ICandidate candidate) { if (person.IsValid) { Vote vote = new Vote(++voteNumber,person, candidate); if (vote.IsValid) { validVotes.Add(vote); } else { invalidVotes.Add(vote); } } else { incompleteVoters.Add(person); } } public IList<Vote> InvalidVotes { get { return invalidVotes; } } public IList<Vote> ValidVotes { get { return validVotes; } } public IList<IPerson> IncompleteVoters { get { return incompleteVoters; } } }

Here is the test that I wrote to drive out the usage of the PollingStation class:

 

[Test] public void ShouldRegisterPolls() { ICandidate liberalCandidate = new Candidate("Lib", "Lib", "LibAddress", 30, Country.CANADA, Gender.MALE, Party.LIBERAL); ICandidate conservativeCandidate = new Candidate("Lib", "Lib", "LibAddress", 30, Country.CANADA, Gender.MALE, Party.CONSERVATIVE); ICandidate ndpCandidate = new Candidate("Lib", "Lib", "LibAddress", 30, Country.CANADA, Gender.MALE, Party.NDP); PollingStation station = new PollingStation(); IPerson tooYoungToVote = new Person("DF", "DF", "dfd", 17, Country.CANADA, Gender.MALE); IPerson tooOldToVote = new Person("DF", "DF", "dfd", 78, Country.CANADA, Gender.MALE); IPerson livesInDifferentCountry = new Person("DF", "DF", "dfd", 18, Country.USA, Gender.MALE); IPerson incompleteInfo = new Person("", "DF", "dfd", 35, Country.CANADA, Gender.MALE); IPerson liberalVoter = new Person("fd", "DF", "dfd", 35, Country.CANADA, Gender.MALE); IPerson conservativeVoter = new Person("fd", "DF", "dfd", 35, Country.CANADA, Gender.MALE); IPerson ndpVoter = new Person("fd", "DF", "dfd", 35, Country.CANADA, Gender.MALE); station.RegisterVoteFor(tooYoungToVote,liberalCandidate); station.RegisterVoteFor(tooOldToVote,liberalCandidate); station.RegisterVoteFor(livesInDifferentCountry,liberalCandidate); station.RegisterVoteFor(incompleteInfo,liberalCandidate); station.RegisterVoteFor(liberalVoter,liberalCandidate); station.RegisterVoteFor(conservativeVoter,conservativeCandidate); station.RegisterVoteFor(ndpVoter,ndpCandidate); Assert.AreEqual(1,station.IncompleteVoters.Count); Assert.AreEqual(3,station.InvalidVotes.Count); Assert.AreEqual(3,station.ValidVotes.Count); OutputStats<IPerson>("Incomplete Voters", station.IncompleteVoters); OutputStats<Vote>("Invalid Votes", station.InvalidVotes); }

Are you wondering what is going on in the OutputStats<T> method. This was just something I put in so you could visualise the validation errors. When this test is run the following will be output to the console window:

 

Incomplete Voters
	First name is required

Invalid Votes
	Must be between 18 - 75 to vote

	Must be between 18 - 75 to vote

	Must live in same country as Candidate

As is common lately, the source code for this completed project is here. And once again, comments are always encouraged and appreciated.

JP

kick it on dotnetkicks.com
Comments [6] | | # 
 Thursday, June 15, 2006
Thursday, June 15, 2006 2:03:53 PM (Mountain Standard Time, UTC-07:00) ( Agile | Tools )

As one of my readers kindly reminded me. I mentioned in the CC.Net video that I would make the CC.Net configuration section for the project demo available.

Here it is:

<cruisecontrol>
 <project name="AdventureWorks">
    <workingDirectory>C:\root\development\citools\cruise\checkouts\adventureworks</workingDirectory>
    <artifactDirectory>C:\root\development\citools\cruise\builds\adventureworks\artifacts</artifactDirectory>
    <webURL>http://localhost/ccnet</webURL>
    <modificationDelaySeconds>10</modificationDelaySeconds>
    <publishExceptions>true</publishExceptions>
    <triggers>
      <intervalTrigger seconds="60" />
    </triggers>
    <state type="state" directory="C:\root\development\citools\cruise\builds\adventureworks\state" />
    <sourcecontrol type="svn">
  <trunkUrl>file:///C:/root/development/svnrepo/playground/adventureworks</trunkUrl>
  <workingDirectory>C:\root\development\citools\cruise\checkouts\adventureworks</workingDirectory>
 </sourcecontrol>
 <tasks>
      <nant>
        <executable>c:\root\development\citools\nant\bin\nant.exe</executable>
        <baseDirectory>C:\root\development\citools\cruise\builds\adventureworks</baseDirectory>      
        <buildFile>cruise.build</buildFile>
        <targetList>
          <target>all</target>
        </targetList>
        <buildTimeoutSeconds>300</buildTimeoutSeconds>
      </nant>
    </tasks>
    <publishers>
      <merge>
        <files>
          <file>C:\root\development\citools\cruise\checkouts\adventureworks\build\*Test-Result.xml</file>
        </files>
      </merge>
      <xmllogger />
    </publishers>
 </project> 
</cruisecontrol>

Of course, you will need to ensure that you replace any occurrence of C:\root\development with a location that you want to use on your own machine.

Comments [0] | | # 
 Wednesday, June 14, 2006
Wednesday, June 14, 2006 2:47:23 PM (Mountain Standard Time, UTC-07:00) ( Agile | Presentations )

It seems like quite a few people had trouble watching the videos for the last post that I made. Based on some good feedback I have decided to make it available for download as a flash file so that people can watch it at their leisure. The download file is a 50MB zip file that extracts to a swf (flash) file.

If you have any problems accessing the files please let me know.

 

  • Download the flash video here
  • I will post the google link once it is verified.
Comments [3] | | # 
 Thursday, June 08, 2006
Thursday, June 08, 2006 6:39:48 PM (Mountain Standard Time, UTC-07:00) ( Agile | ScreenCasts | Tools )

Last time we left off adding in the compilation of the web project to our build process. If you remember back to when we introduced the database we brought in the concept of template files and replacement tokens that could be used to allow for multiple developers on a project with disparate machine configurations to build using the same build file without any changes required. What we want to do now is go the final step and take our standalone build file that is currently being used by individual developers (whether or not they are on a team), and use it to centralize the build process. We are going to set up an environment that a multi developer team can use to introduce a CI process into their environment. CI (for those of you that don’t know) stands for Continuous Integration. Let me stress something very important here. CI is a process, not a tool.  If you want to read a concise definition of CI, check out Martin Fowlers article on the subject. That being said, there are a lot of tools that can aid you in introducing CI into your developer environment. We have already been taking advantage of a couple of these tools:

  • NAnt
  • NUnit

The new tool that we are going to introduce today is CruiseControl.Net. CC.Net is basically an automated build server. You would typically set it up so that at regular intervals it would poll the source code repository and see if there are any changes, if there are it would:

  • Update it’s local copy of the source code from the latest version in the repository.
  • Perform a build against it’s local code base
  • Run all unit tests, acceptance tests etc
  • Generate status reports on the health of the build

Obviously, this is a very high level description of some of the things CC .Net can do. 

This blog post could turn out to be huge, so to save my wrists I am going to try something a little bit different. I am posting a screencast that demonstrates the entire process required to:

  • Place a project under source control using Subversion
  • Installing CC.Net
  • Configuring CC.Net to build a project.

The video is available here. Enjoy. (warning – it is close to 1hr, commercial free!!)

kick it on dotnetkicks.com
Comments [7] | | # 
 Wednesday, June 07, 2006
Wednesday, June 07, 2006 4:04:19 PM (Mountain Standard Time, UTC-07:00) ( Agile | Presentations )

This is a note out for all of the people who have been following along in the NAnt starter series, that tomorrow I will be posting one of the final entries in this series. This episode will be all about getting a Continuous Build environment set up with CruiseControl .Net. Topics that are going to be covered are:

  • Installing Cruise Control .Net
  • Setting up the build box for project building
  • Creating the repository
  • Configuring the build box to build the project
  • Integration with CC.Net

That is a high level overview. As you can imagine, it is a lot of information, too much for me to write about (in a practical amount of time). This is why I am going to do a screencast on my computer that will be made available for everyone to watch. One thing you will want to do is read my Applied Test Driven Development For Web ApplicationsPart1 post and download the sample code as that is what you will need to follow along with the screen cast. I am choosing to use that code base as it will be the code base that will be build upon in the Applied Test Driven Development series, where we will build out a web application (against the adventureworks database) using TDD techniques.

After watching the video you will have a great starting point from which to start practically using CC.Net in your own environment. To save yourself some time I suggest going to download CC.Net from here. You don’t need to install it yet, as I will walk through the install process tomorrow!!

Comments [1] | | # 
Wednesday, June 07, 2006 3:36:14 PM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | C Sharp )

As cool as some of the new features in ASP.Net are, there are some simple interfaces that can open a door to a boatload of functionality for your web applications. I am talking specifically about the IHttpModule and IHttpHandler interfaces. Lots of developers are aware of the interesting problems that you can solve (cleanly) by taking advantage of these interfaces. Lots, however, are still in the mindset that to add new pieces of functionality that an .aspx / .ascx file has to be involved in the picture somewhere. This is just not the case. I am not going to rehash information that is already out there for consumption. Instead I will direct you to the site of James Kovacs, who has just published a great writeup on using an IHttpModule implementation for dealing with Site Availability issues.

If you are not familiar with these interfaces, read the article (along with his article on the ImpostorHttpModule), and start thinking of ways you can use these interfaces in your application. Some examples that I have used in the past are:

  • IHttpHandler implementation that watermarks all images in the application with a company logo
  • IHttpHandler implementation for doing 2 step transform/view implementation without the need for an aspx page
  • Pre 2.0, IHttpHandler for securing non asp.net releated web resources
  • IHttpModule implementation for creating strongly typed payload objects and attaching them to the executing request
  • IHttpModule implementation for custom authorization
  • IHttpHandler implementation for retrieving images from a database

Just think of the things you could do!!

kick it on dotnetkicks.com
Comments [3] | | # 
Wednesday, June 07, 2006 10:27:50 AM (Mountain Standard Time, UTC-07:00) ( Tools )

How many times are you working on your local copy of the source code and you want to quickly blow away your working copy and get a fresh set of code from your source code repository? Chances are that if you are an ASP.Net developer, there are many times when the inetinfo or ASP.Net processes lock the contents of one of your development folders so you are prevented from deleting all of the files/folders with ease. So what do you normally do? I bet you start bringing up the task manager and killing processes until the folder is able to be deleted. Your time is precious, don’t waste it anymore. Unlocker is the utility that you need to install. It runs in the tray and offers many quick ways to unlock files/folders that may have processes that may still have a lock on them. You can follow these steps (taken from the unlocker site) to unlock a file/folder:

    1. Simply right click the folder or file and select Unlocker




    2. If the folder or file is locked, a window listing of lockers will appear




    3. Simply click Unlock All and you are done!

     

It actually gets better though. If you try to delete a folder that has a lock on it, unlocker will automatically pop up and allow you to perform an unlock or a kill process. This short video should demonstrate it well!! Enjoy.

kick it on dotnetkicks.com
Comments [0] | | # 
 Monday, June 05, 2006
Monday, June 05, 2006 11:38:47 AM (Mountain Standard Time, UTC-07:00) ( Tools )

For those of you who love to run firefox but have to work in environments where you are developing for IE, don’t fret. The IE Tab plugin is a great way for you to have your cake and eat it too. After installing this plugin you can open a new tab using CTRL-T and navigate to a site (okay so far nothing is new). Let's say that the site can only render/function correctly is IE (Microsoft Update for example). If I know this, I can right click on the tab and get access to a new context menu item:

ContextMenu

If I switch the rendering engine. The new tab will now use IE to render the page!! No more switching between firefox and IE!! Better yet, instead of having to manually switch rendering engines everytime I visit an IE only site. I can change the options for the IE Tab plugin and give it a list of pages that should always render using IE if visited. If I open a new tab and navigate to one of these IE only sites, firefox will automatically switch the rendering engine for me!

Comments [3] | | # 
 Saturday, June 03, 2006
Saturday, June 03, 2006 7:46:31 AM (Mountain Standard Time, UTC-07:00) ( Tools )

If you are a command line junkie like me, I strongly suggest you check out Bayden Systems SlickRun. It is a wicked floating command prompt that you can customise with things called MagicWords that allow you to open programs/perform tasks by simply typing in the magic word. I thought I would give a simple example of how to go about detaching a database using SlickRun. If I go to the setup for SlickRun and hit ALT-N (new magicword) I will be prompted with the new magic word dialog:

NewMagicWord

The following screenshot shows the settings that I require to detach a db from the slickrun prompt:

DetachDB

Notice that I am making use of the osql.exe (the command line utility for SQL Server). I am also making use of the parameters field to specify which parameters to send to the OSQL.exe program. I am using the -E argument to specify integrated windows authentication, and the -Q option to specify that I just want to execute a query from the command line. The query I want to execute is the sp_detach_db stored procedure, which requires the name of the database that I want to detach. I want to be able to use this MagicWord to detach any database, I do that by using the $I$ parameter. This is a placeholder for a user provided value. If I save this magicword,bring up SlickRun and type in the word detachdb I will be prompted with a dialog:

Parameter

If I enter in the name of the database I want to detach and hit the enter button, a command prompt will flash, detach the db and the command prompt will disappear.

 

You can use the same technique to write other magicwords that can save you a ton of mousing/keyboard time!!

 

Comments [2] | | # 
 Friday, June 02, 2006
Friday, June 02, 2006 10:45:24 AM (Mountain Standard Time, UTC-07:00) ( .Net 2.0 | Agile | C Sharp | Patterns | VS2005 )

I have been promising for a long time to start a series that details the creation of a project similar to the one that I presented on my first set of DNRTv episodes. Here is the beginning of that promise!! The goals of this series is to develop a highly testable web application that demonstrates a lot of the principles that can be utilised when developing a web (or any) application using Test Driven Development. I have chosen to base the examples around the new AdventureWorks database. Why AdventureWorks you may ask? Since it is the successor to Northwind, you are going to see (or already have) many examples/demos that utilise it as a DB. It stands to reason that a lot of the techniques and approaches that I am going to show you, will be counter to what is in the mainstream MS world right now. This is not a bad thing, it is always good to open your eyes to new ways to accomplish tasks!!

In this episode, I am just going to start by discussing solution structure for the project as well as the building of the database. This is by no means meant to be an introduction to NAnt, if you want to see how NAnt can be utilised as build tool for your projects then read my NAnt Start Series. Download this zip file and you will be able to start off at the same point that I am starting at. Drop the zip file in a folder you typically do your development and unzip it to that location:

Unzipping

 

Once you have extracted the contents of the build file there should now be a directory named adventureworks.

UnzippedFolder

The first thing you will need to do is go into the adventureworks directory (from this point referred to as the trunk) and copy the local.properties.xml.template file to a file named local.properties.xml (don’t delete the local.properties.xml.template file):

LocalProperties

With that taken care of, you will need to go in and edit the local.properties.xml file (not the template) and change any settings that may be specific to your machine:

<?xml version="1.0"?>
<properties>
 <property name="sqlToolsFolder" value="C:\Program Files\Microsoft SQL Server\90\Tools\Binn"/>
 <property name="osql.ConnectionString" value="-E"/>
 <property name="initial.catalog" value="AdventureWorks"/>
 <property name="config.ConnectionString" value="data source=(local);Integrated Security=SSPI;Initial Catalog=${initial.catalog}"/> 
 <property name="database.path" value="C:\root\development\databases" />
 <property name="osql.exe"  value="${sqlToolsFolder}\osql.exe" />
</properties>

Pay special attention to the database.path property. You can change the value to point to a different directory on your machine. Make sure that the folder exists, as the build process does not create this folder for you (it could, but I chose not to). Another setting that might vary on your machine is the osql.ConnectionString property. This is basically the connection parameters that you would need to specify if you used OSQL from the command line. For me, I use integrated windows authentication so I can just use the -E switch. You will have to experiment with your settings (you might even need to specify a server name etc).

Once you have changed the properties you can open up a command prompt pointing to your trunk directory. From the command line run the command “build run”. If all of your settings are configured properly (and you have a local instance of IIS), you should see a blank web page pop up in your browser:

DefaultASPX

Last but not least, once you have closed down the browser, you can run the following command from the command line “build builddb”. This will copy the adventureworks database files located in the [trunk]\sql\original directory and place them in the directory that you specified in the “database.path” property of your local configuration file. It will also run a sp_attach_db command and it will name the database using the name you provided in the “initial.catalog” property of your local configuration file.

I have explicitly chosen not to build the DB from scripts, why? I had a hard time finding any original SQL scripts for the AVWorks. If anyone feels like taking the time to create script files that we can use (as well as the accompanying seed data) please let me know.

The main build targets that we will be using during the course of these walkthroughs are “build test” and “build run”.

Let’s take a quick look at the initial solution structure (double click on the AdventureWorks.sln file, this is a VS2005 projects):

InitialSolution

So far we have a Web project, a Presentation project, and a Presentation.Test project. Pretty standard fare. Right now the 2 classes that are in each of the Presentation, and Presentation.Test project are just there so the “build test” target in the build file will execute properly. We will replace both of those classes with meaningful classes next week.

Ok, we are ready to start. Take a look around (there’s nothing much to see right now), read my NAnt Starter Series if you have’nt already. And most important, submit requests for what you would like to see in this project. Keep in mind that I am going to try and use it as a vehicle to teach both TDD and good development practices (design patterns, refactoring etc, OO). Next week I will start by building a screen similar to the one that I created for DNRTv, once I have gotten completely through that example we will have a fairly good ground from which to branch out from. I have already talked to a handful of people and have a good idea of what they would like to see demonstrated. If you have’nt got your request in, now is the time to do it. If you can’t comment on this blog post email me directly at bitwisejp@gmail.com.

Here are some ideas to get you thinking:

  • Manageable Databinding
  • Passing information between pages
  • Master/Detail pages
  • Managing master pages better
  • Ajax
  • Layered Architecture
  • Validation

 

Let the coding begin (almost!!).

kick it on dotnetkicks.com
Comments [5] | | # 
 Thursday, June 01, 2006
Thursday, June 01, 2006 10:29:14 PM (Mountain Standard Time, UTC-07:00) ( Agile )

For readers of this blog you are no doubt aware that I am a practitioner of TDD and I have a passion for at least demonstrating its benefits to other developers. I had a great conversation with Kyle Baley and Wade Grandoni the other day, and I stressed the fact that although I believe heavily in the value of TDD, I also realize that it is just another tool that developers can “choose” to add to their arsenal. Would I personally develop not using TDD, probably not. Do I know that before TDD came along that there were many successful projects delivered on-time and on-budget, absolutely!

That being said, there is a reason why many developers have a hard time believing the benefits of TDD. One of the biggest issues which is often a stumbling block for many developers new/attempting TDD is the fact that it does represent a significant paradigm shift into the software development process. “You want me to write a test for a method that doesn’t exist yet on a class that doesn’t exist yet??” In my opinion, this statement alone represents the reason why I believe that the shift is an even bigger one than the one many of us faced years ago – The shift from procedural coding to OO programming.

I am sure that there are few of us today who could argue against practical reasons for utilizing OO as a vehicle to compose applications. The same holds true for TDD. At first it can be something that looks so different from what you are used to that you do one of two things:

  • Shrug it off completely as a waste of time
  • Look into the questions popping up in your mind

It is the second group that can still continue to have a hard time with the process. Why? Again, remember back to when you were learning to code/think in objects? Chances are you had the help of a few good books, and mentors who had run the Object race, whom you gleaned a lot of good information/best practices from. Because TDD is still a relatively new practice for the .Net community, there is a definite shortage of experts who people can turn to for personal coaching. Now I say shortage, there are a lot of TDD practitioners and gurus out there, but not nearly as many as plain old OO gurus. Why am I mentioning this? Often in the first couple of weeks of attempting TDD on anything but a trivial project, people who are trying to do it on their own get frustrated, and sometimes it is at this point that they dismiss TDD as a waste of time and “impractical for enterprise development”. Unfortunately, this frustration can often be a result of the fact that correctly applying TDD means having a handle on some plain old fashioned clean object thinking. A seasoned TDD developer can help walk you down the path of interface based programming. They can extol the values of dependency injection and layered architecture. All the while tying these principles back to how they relate to the TDD software development process.

Lastly, the biggest reason I think people have a hard time buying into TDD is the only time they get to see it in action is by the “experts’ who can only use it to demonstrate a “small” piece of a larger application. I admit, I definitely fall into this category. Unfortunately what they can’t see is how TDD can literally be applied to build out the functionality of enormous large scale enterprise applications. Why? They can’t join you on your project on a daily basis. They can’t see how just because you are using TDD that the SDLC hasn’t disappeared. They can’t see that in an agile environment a large part of the test code that you write is a direct result of hourly interaction with the business users, who are there helping the developers carve out the functionality. They can’t see the fact that even though you are using TDD that other types of testing are not forgotten.

I am not a purist. I believe TDD is a great vehicle for delivering apps into the hands of users quicker. Do I think that a developer who doesn’t use TDD is a less skilled developer. Absolutely not. One thing you can’t be in this industry is dogmatic. Everyone is entitled to their own opinion. My personal opinion – I would not develop software without using a TDD approach.

Comments [6] | | #