Fear and Loathing
Gonzo blogging from the Annie Leibovitz of the software development world.
-
More 2007 Technical Refresh links
Just a quickie this morning. Seems people find it difficult to locate download links. Maybe I’m just Google-gifted or something. Here are the software development kit links for the Office 2007 technical refresh:
There’s no update to the SharePoint Server (MOSS) SDK yet as the last link is still from May 22nd but I’ll post an update once it goes online.
-
Gentlemen, start yer downloads...
And ladies too. The bits for Office 2007 Beta 2 Technical Refresh are out in the wild. Here are the links for the SharePointy stuff:
- Windows SharePoint Services 3.0
- Windows SharePoint Services 3.0 (x64)
- SharePoint Server
- SharePoint Server (x64)
- SharePoint Designer
Enjoy!
-
Ken Schwaber introduction to Scrum video on Google Tech Talks
Ken Schwaber is the co-founder of the Agile process called Scrum (which BTW is not an acronym) recently gave a talk which has been put online via a serivce called Google Tech Talk.
It’s an hour long presentation but gives you an excellent introduction to Scrum (if you’re not already familar with it) including the interesting history behind it. If you don’t know what Scrum is and are interested (or haven’t heard Ken talk as he’s a great speaker IMHO), you can check it out here.
Nothing like getting the facts straight from the horses mouth (so to speak).
-
Microsoft Office SharePoint Server 2007 Beta 2 Technical Refresh - Thursday
Wow, that’s a big blog title to say three times fast (or one time slowly).
Anyways, after the public beta release of MOSS back during the TechEd days, you can grab the latest bits for what Microsoft calls a “Technical Refresh” as of tommorow morning (Thursday, 9AM PST). It’s not another full-fledged beta, it’s an update to it and corrects various issues, adds some new things, and “refreshes” your beta 2 install here and there (including cosmetic changes).
The news is out on the various websites with some reviews and additional info about the release:
The update is available for the entire Office 2007 stack, but of course I’m a biased blogger and this entry only talks about Office SharePoint Server (MOSS) and Windows SharePoint Services v3.
Like I said, it’s a technical refresh but it does improve things. At the same time however, it might break other things. For example, some of the BDC entries might be “off” and require reconfiguration. There are other areas that have changed that might break things you have in place. While this is a technical refresh, Microsoft is providing an upgrade path from Beta 2 to release so installing this is optional, but recommended. Why? It’s more stable and there are more features and generally it’s creeping closer and closer to a release candidate flavour.
Now for the zinger. As has been mentioned around the blog-o-sphere, installing the TR is not going to be a “ClickOnce” type scenario. There are some vital steps you have to take, otherwise you may invalidate the install or (worse case) corrupt your data. Of course always backup your data before you try this. Also, when/if you do download the bits and start your install remember…
RTFM
Yes, I know. We as developers, architects, and internet gurus laugh at the mere thought of documentation however if you have to read one doc (besides your kids report card) in your life, make it this one. If you don’t, you’ll be travelling a path I cannot follow (or help you as will most other people).
The two key facts to highlight for your install that I want to mention here (besides backup and RTFM) are:
- Shut down the Search Services before you upgrade
- Install all the Beta 2 products and language packs before you upgrade
As I mentioned, there’s the potential to corrupt data during the upgrade if the Search Service is still running. So go into your Services in your Administration screen and shut it down. There, now wasn’t that easy?
You know the saying “Once you go black…”. Same thing here. Once you install B2TR you won’t be able to install any additional products or language packs. So make sure you have everything installed in your VPC, Server, etc. before you upgrade.
Also if you’re upgrading a Beta 2 standard installation, there’s a workaround required so again, crack open that README and just do it.
In a nutshell (and this is by no means a replacement for the documentation) here’s the sequence you’ll go through to upgrade from Beta 2 to Beta 2 TR:
- Turn off WSS Search and Disable OSS Search
- Install the update to Windows Workflow Foundation (.NET 3.0)
- Install the WSS patch
- Install the MOSS patch (if upgrade MOSS)
- Restart forms services and workflows
- Restart the Search Services
Watch the blogs for detailed instructions, gotchas, workarounds, screenshots, etc. from the various SharePoint bloggers (including myself). If you do run into problems of course just yell. We’re always here to listen and try to help (or make crazy fish jokes like the one about the walrus, the nurse, and the prostitute, your choice).
-
Getting ready for B2TR and SharePoint Comparisons
A bit of a mish-mash this morning as the caffeine hits the veins and all of my cylinders start firing.
First there’s a quick post about the upcoming Beta 2 Technical Refresh for Office 2007 (which includes MOSS/Windows SharePoint Services) from the SharePoint team. It’s basically a RTFM post and it is important. As Lawrence pointed out in his own post, the upgrade is not just simply a double-click of an EXE. There are some steps you have to manually do before and after the install to ensure a fully upgraded version. So keep an eye out for these and I’ll post more info when the update is released to the wild.
The second thing is a nice summary that MS put together on the differences between 2003 and the various flavours of 2007. It’s in the form of an excel spreadsheet and really sums up what’s changed. Something to keep handy when you’re scrambling to explain what the differences are to those high-priced execs. You can download it here.
-
Exposing business objects to the UI
I've been working the past few months with the Composite UI Application Block (CAB) and the Smart Client Software Factory (SCSF). They're all great but the documentation throws me for a loop sometimes.
In an entry called "Map Business Entities into User Interface Elements" it suggests creating a mapper class and using it to convert some business object into a UI one. This makes sense however the implementation and references cause my head to hurt.
In a typical MVP pattern, you have the Model (your business object), the View (the UI), and the Presenter (a go-between guy). The presenter knows about both the view and the model. It needs to inform the model to update based on messages recieved from the view, and tell the view about changes in the model. Neither the model or the view have any knowledge of each other.
Introduce the mapper which knows about the Model and the View. This is the other side of the equation so when given a business object, the mapper will spit out a drop down list, a grid control, or whatever UI element is appropriate to display something from the business layer (say a list of customers).
In the example Microsoft provides via the guidance package, the view has a method that accepts a business object which then calls the mapper to translate it into a ListViewItem. The view then updates its UI control (a ListView control) by adding list items to it created by the mapper.
However this means that you're exposing you business objects to the user interface, which creates a coupling between the UI and the business layer (at least from a deployment perspective). If you don't do it this way you have to have the presenter (which should know about domain objects so that's ok) update the view but what is it going to update it with? Certainly not a ListViewItem which will make the presenter dependent on the windows form control assemblies.
Without creating a intermediate object (like a CustomerDTO with nothing but getters/setters) are we really bound to have the UI reference the business layer and is the documentation here really a best practice for exposing business objects to the UI? How do you guys do it?
-
Hello <<NAME>>
As the Ricky Bobby of the SharePoint world (too bad Matt, it’s sticking now even if nobody gets it) I receive a lot of weird emails.
And then there was this:
Hi <<NAME>>,
My name is [REMOVED], and I'm a recruiter with [REMOVED].
I came across your resume in our system, and I thought I'd try to touch base because I wanted to talk with you in regards to a high profile project that I'm working on in [REMOVED] that seems to fit fairly well with your skill set.
I'd love to get a better understanding of your career ambitions and availability. Is there a number I can reach you at, and a 10 minute time slot that you could open up for me? If it's more convenient, please don't hesitate to contact me directly. You can reach me via email or at [REMOVED].
Thanks very much <<NAME>> -- I'm looking forward to speaking with you!
Cheers
(Note: the [REMOVED] part is information about who sent it with phone numbers and such. I’ve blanked it out to protect the village idiot who sent me this in the first place.)
My geek-to-be promptly told me to send this message back to the firm:
Hi <<NAME>>,
Thank you for your personal interest in my career, however at this time I am currently working for a company that is better versed in using mail merge techniques.
Thanks very much <<NAME>>
Bil Simser
Brilliant.
-
Titles and Reflections
Last nights webcast went pretty well with the NYC SharePoint User Group (say that three times fast). There was a great turnout (over 60 peeps including Scot Hillier, Box Fox and other SharePoint luminites) and there were some good questions and hopefully equally good answers. Compressing the BDC into a 20 minute session is like fitting Rosie O'donnell into a tutu. Ugly. However it went pretty good and I hope everyone got introduced to what's a very cool part of MOSS 2007.
Shout outs to the entire group and especially Matt from CorasWorks and his minions for making everything work smoothly. Matt introduced me as the Ricky Bobby of the SharePoint world. While that may be true (although I probably share that distinction with Todd Bleeker) I always thought of myself more as the Weird Al Yankovic of the SharePoint world. Anyways, I believe they captured the web cast and will hopefully be putting it online for all to cry over.
Finally (off-topic), I had an errand to do today and wandered outside to get there. The weather here in Calgary is still short-sleeve'ish so it was a nice walk. I noticed I passed by 3 statues commemorating dead people. All people who died in the service of their country. Now I'm all for honoring people and such, but when are we going to see statues of people who died of natural causes rather than those who went down in a flaming plane?
One can dream.
-
NYC SharePoint User Group Presentation on BDC Tommorow
It’s a hot time in the cool city tommorow. Well, it’ll be hot here in Calgary and I don’t know the weather in New York but anyways I’ll be doing a webcast for the NYC SharePoint User Group tommorow (Wednesday). The webcast is on the BDC and while I only have a half-hour to present, we’ll run through some samples in the BDC, how to create and use Content Types defined in the BDC and a little coding sample calling the BDC services to programmitically “make stuff happen”.
If you’re signed up then great (they tell me there’s about 60 people coming already), otherwise see if you can get in by visiting the NYC SharePoint User Group Portal here. The meeting starts at 5:30pm EST at the MS office in New York. This is the first in their “MVP Series” that they’re presenting so hopefully I won’t screw it up too badly for you guys that follow ;)
This is a Live Meeting presenation and I’m not sure if they record the demo or if I’ll be able to, but hopefully we can put it online for anyone else to suck down and kick back with after the fact. After all, they only have so many sandwiches they can muster up at the user group meeting.
See you then!
-
TDD validation... NetTiers Style
Let’s face it. At the end of the day, even the most purist of us object-oriented bigots know the real truth. Objects need data to work. Yes, behaviour defines an object and all that OOD popycock but I mean, a Customer domain object still needs a name, telephone number, and address in order to be of any value in an Enterprise system right? Sure there are “business rules” we want to write but all the unit tests in the world are not going to get around the fact that objects need data and sometimes that data needs to be saved (or retrieved, or both).
The problem we all face, sooner or later, is how do I get data from some datasource (for the sake of the argument here, let’s say a database) into (and out of) my object? There are really two ways to go about it and for the purpose of this article, let’s avoid the O/R mapping ramble. So that leaves us plucking data from properties exposed in a business object and shuffling it off to parts unknown to be stored somewhere. Service objects and Repositories and Mappers and Translators and all kinds of other things having intimate knowledge of the types and properties of domain objects. On the flipside of this, there’s a pattern called ActiveRecord that follows the principle that an object would communicate with an outside service and publish it’s properties for persistence (or the other way round loading data from a data source). Neither of these situations is really pleasant but it’s a bear we deal with when we have to shut down machines and expect that information to be there tommorow.
The latest version of a set of CodeSmith templates called NetTiers provides us with an interesting way to look at our domain (and getting it to/from a database). CodeSmith is a code generation tool and using the NetTiers templates, it creates a n-tier set of classes (about 90 of them from a simple database) that allow you to do cool stuff like this:
DataRepository.MyObjectProvider.Save(MyObject);
This is all neatly wrapped up in a transaction (if the database supports it and/or you configure it to use transactions) and all dynamically generated based on tables and columns in a database. It’s all very slick and NetTiers can create an entire app (minus the front-end) for you in less than 10 seconds. So what’s this got to do with TDD?
Imagine we’re starting an application and we’re going to be building it using TDD. We have some requirements and we’re ready to start writing tests. Given a requirement that a Customer name can not exceed 50 characters we might write a test like this:
namespace NetTiersTDD.UnitTests
{
[TestFixture]
public class CustomerFixture
{
[Test]
[ExpectedException(typeof(ApplicationException))]
public void CustomerNameShouldNotExceed50Characters()
{
Customer customer = new Customer();
customer.Name = "X".PadLeft(51);
}
}
}
This is fine and a good start. So now we create our business entity to support the test:
namespace NetTiersTDD.Entities
{
public class Customer
{
private string _name;
public string Name
{
set { _name = value; }
}
}
}
Great. Our unit test compiles but out test fails (which is good, remember Red-Green-Refactor). Now let’s make the test pass in our business entity:
namespace NetTiersTDD.Entities
{
public class Customer
{
private string _name;
public string Name
{
set
{
if(value.Length > 50)
throw new ApplicationException();
_name = value;
}
}
}
}
Fantastic. So this can be typical when doing something like these checks. There are other checks you might do and the general idea is around failing fast so you would throw an exception when some validation fails on your business entity (you don’t want to find out your domain object is invalid several layers or operations down the stack).
Fast forward about 3 days and you find yourself slugging through requirements like this (and others) and your classes start buffing up and out. More domain logic, lots of tests, goodness. However, you might notice something happening with some of your tests. Take a look at our Customer test now:
namespace NetTiersTDD.UnitTests
{
[TestFixture]
public class CustomerFixture
{
[Test]
[ExpectedException(typeof(ApplicationException))]
public void CustomerNameShouldNotExceed50Characters()
{
Customer customer = new Customer();
customer.Name = "X".PadLeft(51);
}
[Test]
[ExpectedException(typeof(ApplicationException))]
public void CustomerAddressShouldNotExceed255Characters()
{
Customer customer = new Customer();
customer.Address = "X".PadLeft(256);
}
[Test]
[ExpectedException(typeof(ApplicationException))]
public void CustomerAgeShouldNotExceed65()
{
Customer customer = new Customer();
customer.Age = 66;
}
}
}
(note: I’m using ApplicationException here but you would probably have a specific exception for different validations)
Lots of exceptions being thrown because well, it’s a business rule violation. By design, we don’t want to make our domain object invalid by any means so we throw an exception when setting a property that’s invalid. This will immediately let us know something is wrong and, if we had a UI, we could inform the user of the error (maybe with a Message Box telling him that a field is too long or required or whatever). This is fine and dandy but makes me queasy. I mean, exceptions are expensive. Imagine I had an import routine that brought in crappy (un-validated) data from an Excel spreadsheet and created 1,000 domain objects in a collection. That’s a heck of a lot of exceptions.
An alternative is to post-validate an object. That’s a valid approach. Let whatever information come into the system (from a user or that crappy spreadsheet) and validate the object after the fact. Then I can do something like check an IsValid property (or the return value from a method called Validate()) and act accordingly. I’m still not letting my domain object get out of control because the unit of work hasn’t completed until I validate the object so we’re good to go. This is okay but now we need a Validate method, some way to retrieve the validity of our business object, some way to set the rules for various properties, and other “helper” methods. Some astute readers will jump up and say “I know, let’s decorate properties with attributes and use reflection in a standard method to validate a setter”. Cool and nice out-of-the-box thinking and certainly something you could do (and something that might start to drift into AOP territory but that’s a whole ‘nuther can o’ worms that I won’t get into either).
So other than reflection, I now have to write a bevy of code to handle validation, invalid state, modify changes to properties (or maybe respond to them) and lots of other little niggly bits. If I was being paid by the line then maybe I want to do this. And hey, if I build a framework we can use it everywhere in the organization so it’s an investment. Yes, this is again a valid thing to do but my motto is don’t write something that can be created by a tool for you (and works). Using the validation framework generated from NetTiers, we can get all this (and more) for a pretty insignificant cost. On top of that, we have a DAL written for us that we don’t have to worry about and can use later when we need to persist our business entities (and what application doesn’t do that?).
Again Bil, what the heck does this have to do with TDD?
Like I said, NetTiers (via CodeSmith) will generate billions of lines of code for you with the single click of a button. Buried in that code are some base classes that NetTiers will use with your business entities (gen’d from your tables based on it’s columns and constraints) and buried deeper down than that are some pretty cool utilities and classes that you can use to write less code (but get more accomplished). I’m all for something that works and let’s me write less code to get more done and that’s what I can get from NetTiers.
Let’s go back to our Customer class and try some NetTeirsTDD. First thing is you need NetTiers to generate you it’s artifacts. This involves creating a database and a table. Yeah, I know. TDD. Database. The TDD guys are saying “Oh man, he’s got it all wrong”. Just walk with me on this okay?
Create a new database and add a simple table to it. Here’s the one I used:
The table is called Ernie with ID and Title columns. The name and columns really don’t matter so you can call it Temp, Balloon, Mayonaise, or Wurstie for what it’s worth. Just call it something that won’t be one of your business objects because hey, we’re doing TDD and we don’t create business objects until we need them right? The temp table (and resulting generated code) is so you have a starting point (and a framework to leverage, which is what we’re getting to).
Now run CodeSmith using the NetTiers templates. In the latest version (2.0) of the template, you’ll need to set a few things:
- Point it at your datasource via the ChooseSourceDatabase property
- Set IncludeUnitTest to True (this will create a unit test project)
- Set LaunchVisualStudio to True
- Set GenerateWebLibrary and GenerateWebSite to False
- Set ViewReport to False (or leave it on if you want, your choice)
Once those options are set hit Generate. In about 10 seconds you’ll have about 60 classes, 4 projects, and the basis for your starter solution.
Finally let’s get into some TDD. Go to the opened instance of Visual Studio with the solution that was created for you. The unit test project that you created will already have references to the various other projects (including a raft of unit tests to test persistence of your Ernie class). Let’s go back and start our Customer test again, except we’ll do things a little differently.
First let’s modify the test that we originally wrote. Instead of expecting an exception, we’ll use an IsValid boolean property:
namespace NetTiersTDD.UnitTests
{
[TestFixture]
public class CustomerFixture
{
[Test]
public void CustomerNameShouldNotExceed50Characters()
{
Customer customer = new Customer();
customer.Name = "X".PadLeft(51);
Assert.AreEqual(false, customer.IsValid);
}
}
}
Looks harmless and something we might do. IsValid will return true or false if the customer object is valid (and in this test, we want IsValid to return false because we expect it to be that way after setting the name with too many characters). Now here’s where the magic comes in. Create your Customer class but inherit from a class called EntityBase (a class that’s part of the framework NetTiers created). To get this code setup to compile, EntityBase requires a few abstract methods to be implemented. They don’t have to do anything (for now) so you have a couple of options (like create a StubEntityBase and implement the methods in that). So let’s do that make our Customer class work. Create a class called StubEntityBase with these members implemented like so:
public class StubEntityBase : EntityBase
{
public override void CancelChanges()
{
throw new Exception("The method or operation is not implemented.");
}
public override string TableName
{
get { throw new Exception("The method or operation is not implemented."); }
}
public override int ID
{
get
{
throw new Exception("The method or operation is not implemented.");
}
set
{
throw new Exception("The method or operation is not implemented.");
}
}
public override string Title
{
get
{
throw new Exception("The method or operation is not implemented.");
}
set
{
throw new Exception("The method or operation is not implemented.");
}
}
public override string EntityTrackingKey
{
get
{
throw new Exception("The method or operation is not implemented.");
}
set
{
throw new Exception("The method or operation is not implemented.");
}
}
public override object ParentCollection
{
get
{
throw new Exception("The method or operation is not implemented.");
}
set
{
throw new Exception("The method or operation is not implemented.");
}
}
public override string[] TableColumns
{
get { throw new Exception("The method or operation is not implemented."); }
}
}
Now inherit Customer from StubEntityBase instead of EntityBase.
public class Customer : StubEntityBase
{
private string _name;
public string Name
{
set
{
_name = value;
}
get
{
return _name;
}
}
}
Great, run the unit test and it fails. IsValid returns true because we haven’t put any validation checking in our business object yet. Now it’s time to make it pass. Change the Customer class to show this:
public class Customer : StubEntityBase
{
protected override void AddValidationRules()
{
ValidationRules.AddRule(
Validation.CommonRules.StringMaxLength,
new Validation.CommonRules.MaxLengthRuleArgs("Name", 50));
}
private string _name;
public string Name
{
set
{
_name = value;
OnPropertyChanged("Name");
}
get
{
return _name;
}
}
}
We’re doing two things in the business class to make our test pass. First, we’re overriding a method called AddValidationRules. This gets called (lazy loaded) when a validation check is done (for example when you call IsValid). The ValidationRules is a list of rule objects (again, classes in the NetTiers framework) that you can setup. The CommonRules contains things like length checks, required fields, not greater than, etc. You can also get into designing your own rules but that’s for another blog. So we tell it to check the property named “Name” and make sure it doesn’t exceed 50 characters. If it does, it adds a BrokenRule object to another list.
Then we add a call to the setter for name to trigger an event called “OnPropertyChanged” and pass the name of the property we’re setting. This will do a validation check against the property by invoking any rules that match the property name (you can have multiple rules per property).
Finally when the IsValid property is called on the business entity, it checks the ValidationRules list, finds a list of BrokenRules (rules that failed validation when the OnPropertyChanged event was called) and returns true of the count is not 0.
Cool huh? Lots of business validation stuff going on but none of the plumbing we had to write to get it. There are some other neat side effects that you can get from this framework. For example, back in our unit test we can just ask the object what the error(s) are and print them out:
[Test]
public void CustomerNameShouldNotExceed50Characters()
{
Customer customer = new Customer();
customer.Name = "X".PadLeft(51);
if (!customer.IsValid)
Console.WriteLine(customer.Error);
Assert.AreEqual(false, customer.IsValid);
}
This prints out:
------ Test started: Assembly: NetTiersTDD.UnitTests.dll ------
Name can not exceed 50 characters
1 passed, 0 failed, 0 skipped, took 0.56 seconds.
Very useful when writing out the errors to the screen or a log (rather than having to figure out what the error was, then compose a message for it).
Let’s go back to what was originally generated with that first cut off the database. By default, NetTiers generates a report showing you all the craziness it did. This includes a plethora of classes like ListBase, EntityFactory, BrokenRule, ValidationRules, EntityCache, EntityPropertyComparer, and a bunch of other classes. These classes actually have nothing to do with data persistance but form an object framework that we can use (like above) to validate our business objects.
These are all generated by the tool but are used by business entities. For example, ListBase is a generic list (just like List<T>) but supports searching, filtering, sorting, and databinding. Feel free to load up business entities into it and bind it to a GridView for some fun. EntityCache is a class that you can use to add entities to a cache manager. The manager is actually driven by Enterprise Libraries (which the NetTiers code is built on top of) but it lets you add your own business entities to a cache and find them later. This can be handy for in-memory Repositories or just quick and dirty tests where you need to retrieve known objects (but don’t want to create singletons or something). There’s lots of great classes and helpers that are generated for you and all it takes is a single table to get going (which you can delete later and all the code for it will wash away) so explore the business entity project that gets created and check it out (there’s also full documentation on all the classes and methods that you can create using something like Sandcastle).
Finally, at some point you will (or probably) have to save your business entities data in a database. Again, this is where it gets simple (but it’s a bit of a manual process). Let’s say you’ve written up your object with various rules (not just length checking stuff but real business tests) and need to save it. You take a look at what the business object has and decide on a structure. Just a simple structure since all you really need to do is CRUD. Create the table and regen the DAL using CodeSmith and NetTiers (saving your business validations before you do this). Now just drop the business validations in the new genrated object that will derive from MyObjectBase and you’re good to go.
Let me clarify the steps I described above:
- Write your unit tests and create whatever business classes that come out of your tests (adding your business classes to the Entities project NetTiers generated)
- Identify what properties you need to persist from your business class and create a simple table with the same name as the class to hold them
- Rename your business class to a placeholder (like MyBusinessObject.txt)
- Generate the DAL from the database
- The Entities project will contain one business class for each table created. This class is split into two parts. MyBusinessObject and MyBusinessObjectBase. MyBusinessObject.cs is never regenerated so you’re free to modify it with your business logic and validations (plus any properties that are not stored in the db). MyBusinessObjectBase is a generated file that will get recreated each time the code gen runs (and update accordingly if you add/remove columns in the database)
For example I create a Customer class that will hold all my customer info. I decide that I’m going to persist the FirstName, LastName, and Age properties. I create a table named Customer to hold these (putting whatever data length and range validations I want on them). Then I rename Customer.cs to a placeholder like Customer.txt. I regen the DAL using NetTiers. I then take the generated Customer class (that will not get overwritten) and drop in the contents of Customer.txt (the part that does my business rules validations).
You’ll probably do two things with the generated business class. First is to override the AddValidationRules method and add any non-data related rules. Second is to write any business domain rules methods and properties that are not stored in the database (like calculated values). Again this class is not overwritten when you regenerate your code, but the generated code will stay in sync with your database adding new properities and modifying data integrity rules along the way (say if you change the length of a field).
The cool thing is that things like the length validations (on properties that are persisted) will already be done for you based on your settings in the database. Go ahead and check out the MyBusinessObjectBase.generated.cs file and you’ll see it’s already written out the AddValidationRules method based on columns in the database (remember to call the base method if you add your own rules in the business class).
Okay, this approach isn’t perfect. It’s not true TDD as in only writing what’s needed. However what does System.Object give you? A bit fat nothing except a unique GetHashCode method and a couple of other useless things. Why not build objects on top of something that has a little extra for you (without having to write it yourself). You do have to make some tradeoffs and for some, it’s too painful to do this. First, you have to bite the bullet that you have a 1:1 relationship of object to table. That’s just the way the NetTiers templates work. Second, you have to have a table (initially and eventually) to generate the code that will do all the data validation but then most business entities have to wind up stored somehow. This technique just helps it along.
You do also have to build your system on top of Enterprise Libraries and some people are not willing to make that leap just yet. Also, some TDD purists will say that you shouldn’t be dependent on this kind of framework but only write what you need when you need it. I agree but this (IMHO) helps. Look at Rocky Lhotka and his CSLA.NET framework. It’s a highly successful business object framework that you could do TDD from. This isn’t that much different from it (other than the fact you need a database to start from). Maybe I’m wrong and this approach is all wrong, but you need to decide that, not some book or blog entry on the interweb.
Finally though, as I mentioned, after all this is said and done I can have my business objects persist with a few lines of code and leverage a validation framework to boot. To me, that’s worth the cost of a one-to-one relationship of table to object and some trade-offs if it means that I can work faster with my business domain and validate it quickly and easily. YMMV.
NOTE: On reading this over now and thinking about it a little more, you might start with a table called Stub. Add an integer ID field and nothing else to it (CodeSmith and NetTiers need at least one column to create something from). Generate the framework from it and base your business objects off the Stub base class (StubBase) rather than creating your own stub like described above. It’ll work in the interim until you have a table of your own for your business class and in the case where you don’t have a table for a business object, you could use this one. Just a thought anyways.
ADDITIONAL NOTE: Thinking even more about the stub idea, you could probably toss away the Data project and Data.SqlClient project and just be left with the Entities project with a business object framework to leverage, but then that’s really no fun is it?
FINAL NOTE: Okay, took me about 4 hours to put this entry together so hope it tweaks your brain and encourages discussion in the community. Maybe I’m completely off my rocker and just talking out of my butt, or maybe not. Anyways, this is a technique I’m using on a current (Enterprise) project and it’s coming along nicely. A combination of using the Composite Application UI Block, NetTiers, Domain Driven Design, and more Unit Tests than you can shake a stick at and I’m pretty confident the project will be a success in many ways.