How to constrain mocks for use with Complex Types

19. January 2012

Here are some tests to illustrate how to leverage RhinoMocks constraints. Notice that it is easier to get a passing test on failing code with a stub. The Strict mock will enforce the expectations at the time of the call, where the stub will only throw an exception on an AssertWasCalled. Due to this I would recommend that you explicitly do your setup and use strict mocks, or make sure to have the discipline to test those assertions.

 

With the method Matches() ,you can use any predicate or method call that returns a boolean. You cannot however use a lambda with a method body aka () =>{}. This will not compile.

[TestClass]

public class Tests

{

[TestMethod]
        public void Should_Allow_Constraint()
        {
            //Arrange
            var mock = MockRepository.GenerateStrictMock<ITestExerciser>();
            mock.Expect(x => x.DoSomething(Arg<List<ITest>>.Matches(c => c.First() is Test))).Return("TestPass");
            var tester = new Tester(mock);
            //Act
            var result = tester.DoIt();

            //Assert
            mock.VerifyAllExpectations();
            Assert.AreEqual("TestPass",result);
        }

        [TestMethod]
        public void Should_Enforce_Constraint_On_Strict_Mock()
        {
            //Arrange
            var mock = MockRepository.GenerateStrictMock<ITestExerciser>();
            mock.Expect(x => x.DoSomething(Arg<List<ITest>>.Matches(c => c.Any(t=> t is Test)))).Return("TestPass");
            var tester = new Tester(mock);
            //Act
            var result = tester.DoItWrong();

            //Assert
            mock.VerifyAllExpectations();
            Assert.AreEqual("TestPass", result);
        }

        [TestMethod]
        public void Should_Allow_Manual_Enforce_Constraint_On_Stub()
        {
            //Arrange
            var mock = MockRepository.GenerateStub<ITestExerciser>();
            mock.Expect(x => x.DoSomething(Arg<List<ITest>>.Matches(c => TestSomething(c)))).Return("TestPass");
            var tester = new Tester(mock);
            //Act
            var result = tester.DoItWrong();

            //Assert
            mock.AssertWasCalled(x => x.DoSomething(Arg<List<ITest>>.Matches(c => c.Any(t => t is Test))));
            Assert.AreEqual("TestPass", result);
        }

        private bool TestSomething(List<ITest> tests)
        {
            return true;
        }
    }

    public class Tester
    {
        private ITestExerciser _testExerciser;

        public Tester(ITestExerciser testExerciser)
        {
            _testExerciser = testExerciser;
        }

        public object DoIt()
        {
            return _testExerciser.DoSomething(new List<ITest>() {new Test()});
        }

        public object DoItWrong()
        {
            return _testExerciser.DoSomething(new List<ITest>() { new TestBase() });
        }
    }

    public class TestExerciser : ITestExerciser
    {
        public object DoSomething(List<ITest> args)
        {
            return null;
        }
    }

    public interface ITestExerciser
    {
        object DoSomething(List<ITest> args);
    }

    public class Test : TestBase
    {
       
    }

    public class TestBase : ITest
    {
        public int Id { get; set; }
    }

    public interface ITest
    {
        int Id { get; set; }
    }

C#, C# Helpful Functions, Testing, Unit Testing, RhinoMocks

Composing Complex Queries with LINQ to Entities

30. April 2011

We have all had those times where we have had to build chains on complex where statements, with several OR / AND operations. These make LINQ queries look really complex and most of the time need to be reused in several places. To clean this up and give us the ability to compose complex queries on the fly from say a UI filter or something similar give the following a try.

public class Test
    {
        public void Testing()
        {
            Expression<Func<Product, bool>> isRed = c1 => c1.Color == "Red";

            Expression<Func<Product, bool>> isCheap = c2 => c2.StandardCost < 10.0m;

            Expression<Func<Product, bool>> isClothing = c3 => c3.Class == "Clothing";

            Expression<Func<Product, bool>> isAcceptable = Utility.BuildOrElse(isRed, isCheap, isClothing);

            IQueryable<Product> products = null;
            var query = products.Where(isAcceptable);
        }

    }

    public class ParameterRebinder : ExpressionVisitor
    {

        private readonly Dictionary<ParameterExpression, ParameterExpression> map;



        public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
        {

            this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();

        }



        public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
        {

            return new ParameterRebinder(map).Visit(exp);

        }



        protected override Expression VisitParameter(ParameterExpression p)
        {

            ParameterExpression replacement;

            if (map.TryGetValue(p, out replacement))
            {

                p = replacement;

            }

            return base.VisitParameter(p);

        }

    }

    public static class Utility
    {

        public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
        {

            // build parameter map (from parameters of second to parameters of first)

            var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);



            // replace parameters in the second lambda expression with parameters from the first

            var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);



            // apply composition of lambda expression bodies to parameters from the first expression 

            return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);

        }



        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {

            return first.Compose(second, Expression.And);

        }



        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {

            return first.Compose(second, Expression.Or);

        }

        public static Expression<Func<T, bool>> OrElse<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
        {

            return first.Compose(second, Expression.Or);

        }

        public static Expression<Func<T, bool>> BuildAnd<T>(params Expression<Func<T, bool>>[] conditions)
        {
            return conditions.Aggregate<Expression<Func<T, bool>>, Expression<Func<T, bool>>>(null, (current, expression) => current == null ? expression : current.And(expression));
        }

        public static Expression<Func<T, bool>> BuildOr<T>(params Expression<Func<T, bool>>[] conditions)
        {
            return conditions.Aggregate<Expression<Func<T, bool>>, Expression<Func<T, bool>>>(null, (current, expression) => current == null ? expression : current.Or(expression));
        }

        public static Expression<Func<T, bool>> BuildOrElse<T>(params Expression<Func<T, bool>>[] conditions)
        {
            return conditions.Aggregate<Expression<Func<T, bool>>, Expression<Func<T, bool>>>(null, (current, expression) => current == null ? expression : current.OrElse(expression));
        }

    }

Adapted and added to from

http://blogs.msdn.com/b/meek/archive/2008/05/02/linq-to-entities-combining-predicates.aspx

Entity Framework, Data Access, C#, C# Helpful Functions, Productivity

Separating POCO and Context in EF 4.0

16. August 2010

I found that I like the streamlined process of working with Entity Framework. The auto generation of domain class is nice when dealing with Existing databases. I dislike having to put domain classes in Infrastructure or putting data base context in Core.

Using the POCO Entities T4 templates you can separate these.

Download here

Add a new Entity Data Model and Generate from the data base.

image

Then right click the background of the model and add a generated code item.

image

Select the POCO Objects

image 

This will create Two .tt files. One is the POCO Classes and one is the Context. We are going to use the onion architecture for this example. We want to move the context to infrastructure so that our model and POCO classes and model are in core.

image

and

image

To separate the context from the Domain we will need to edit the context template. You do not want to edit the classes generated because this will just get wiped out.

image

image

The edit we have to make is to simply add the namespace of the Domain objects to the using statements, and the path of the EDMX file to the input. I am still hunting a way to keep from hard coding a absolute path to the EDMX but until then this will have to work.

 

Enjoy.

C#, Data Access, Design Patterns, Entity Framework

WCF Serialization of Cyclic References

2. March 2010

 

When serializing object to a client through WCF you often have reference objects that are needing to be serialized. This becomes a problem if the 
reference parent and reference child are both of the same type. This causes
WCF to barf over cyclic references. There are two fixes. If you are using
.NET 3.5 or previous you can do this (Thanks to Chabster):

namespace MetroServer.Infrastructure
{
    [AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method)]
    public class CyclicReferencesAwareAttribute : Attribute, IContractBehavior,                                                  IOperationBehavior
    {
        private readonly bool _on;

        public CyclicReferencesAwareAttribute(bool on)
        {
            _on = on;
        }

        public bool On
        {
            get { return (_on); }
        }

        #region IOperationBehavior Members

        void IOperationBehavior.AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        void IOperationBehavior.ApplyClientBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation)
        {
            CyclicReferencesAwareContractBehavior.ReplaceDataContractSerializerOperationBehavior(operationDescription, On);
        }

        void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation)
        {
            CyclicReferencesAwareContractBehavior.ReplaceDataContractSerializerOperationBehavior(operationDescription, On);
        }

        void IOperationBehavior.Validate(OperationDescription operationDescription)
        {
        }

        #endregion

        #region IContractBehavior Members

        void IContractBehavior.AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
        {
        }

        void IContractBehavior.ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
        {
            CyclicReferencesAwareContractBehavior.ReplaceDataContractSerializerOperationBehaviors(contractDescription, On);
        }

        void IContractBehavior.ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatchRuntime)
        {
            CyclicReferencesAwareContractBehavior.ReplaceDataContractSerializerOperationBehaviors(contractDescription, On);
        }

        void IContractBehavior.Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {
        }

        #endregion
    }

    public class CyclicReferencesAwareContractBehavior : IContractBehavior
    {
        private const Int32 maxItemsInObjectGraph = 0xFFFF;
        private const bool ignoreExtensionDataObject = false;

        private bool _on;

        public CyclicReferencesAwareContractBehavior(bool on)
        {
            _on = on;
        }

        #region IContractBehavior Members

        public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
        }

        public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
        {
            ReplaceDataContractSerializerOperationBehaviors(contractDescription, _on);
        }

        public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
        {
            ReplaceDataContractSerializerOperationBehaviors(contractDescription, _on);
        }

        internal static void ReplaceDataContractSerializerOperationBehaviors(ContractDescription contractDescription, bool on)
        {
            foreach (var operation in contractDescription.Operations)
            {
                ReplaceDataContractSerializerOperationBehavior(operation, on);
            }
        }

        internal static void ReplaceDataContractSerializerOperationBehavior(OperationDescription operation, bool on)
        {
            if (operation.Behaviors.Remove(typeof(DataContractSerializerOperationBehavior)) || operation.Behaviors.Remove(typeof(ApplyCyclicDataContractSerializerOperationBehavior)))
            {
                operation.Behaviors.Add(new ApplyCyclicDataContractSerializerOperationBehavior(operation, maxItemsInObjectGraph, ignoreExtensionDataObject, on));
            }
        }

        public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
        {
        }

        #endregion
    }

    internal class ApplyCyclicDataContractSerializerOperationBehavior : DataContractSerializerOperationBehavior
    {
        private readonly Int32 _maxItemsInObjectGraph;
        private readonly bool _ignoreExtensionDataObject;
        private readonly bool _preserveObjectReferences;

        public ApplyCyclicDataContractSerializerOperationBehavior(OperationDescription operationDescription, Int32 maxItemsInObjectGraph, bool ignoreExtensionDataObject, bool preserveObjectReferences)
            : base(operationDescription)
        {
            _maxItemsInObjectGraph = maxItemsInObjectGraph;
            _ignoreExtensionDataObject = ignoreExtensionDataObject;
            _preserveObjectReferences = preserveObjectReferences;
        }

        public override XmlObjectSerializer CreateSerializer(Type type, String name, String ns, IList<Type> knownTypes)
        {
            return (new DataContractSerializer(type, name, ns, knownTypes, _maxItemsInObjectGraph, _ignoreExtensionDataObject, _preserveObjectReferences, null /*dataContractSurrogate*/));
        }

        public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList<Type> knownTypes)
        {
            return (new DataContractSerializer(type, name, ns, knownTypes, _maxItemsInObjectGraph, _ignoreExtensionDataObject, _preserveObjectReferences, null /*dataContractSurrogate*/));
        }

    }

Usage:

[OperationContract]
[CyclicReferenceAware(true)]
Object MyMethod(int number); 

Or if you use .NET 3.5 SP1 you can do this:

[DataContract(IsReference = true)]
public class MyClass
  {
        [DataMember]
        public string MyProperty{ get; set;}
  }

I think you will agree .NET 3.5 SP1 is better.

.NET, C#

LINQ, Lambda and the Learning Curve

3. January 2010

Been away for a while working on a 107,000 hour project. It isn?t done, but I am making time to blog and do my technical mentorship, because I have come to realize that there will always be high priority projects. You have to take the time to train and mentor during those projects because of that. Now on to the show.

I know that LINQ has received a massive welcome from the community and I have to say that it is a deserved on. On the whole it is a great addition to the language. I however don?t like one part of it. Verbose LINQ. I realize that it is more SQL like and that it is perceived to  shorten the learning curve, but I disagree. Lambdas are where the true power of LINQ sit and using verbose to me seems to focus you to learn LINQ one way so that you can re-learn it another.

I am going to focus on the Lambda side of LINQ simply out of preference. Keep an eye out here for the verbose VS. lambda death match, but that is a post for another time.

Lambda statements are actually fairly simple once you break them up.

SomeList.Where(c=>c.Id == someInt);

The above is the lambda conversion of this code block

foreach (Item item in SomeList)
{
    If(item.Id == soemInt)
        SomeOtherList.Add(item);
}

Lets break down the lambda so that this is a bit more clear.

c =>

This statement is declaring that the item in the list we are looking at is going to be held in the local variable named ?c?. This is no different than naming the variable in a for each loop ?c?. You can name your lambda variables more intuitively and I would encourage you to do so. Something like this.

SomeList.Where(menuItem => MenuItem.Id == someInt);

Once the object is declared you have the ability to use all of the members of that object. That is how we are able to use the ?Id? property to check something for a Boolean property. Selecting based on some Boolean expression is the most common use for Lambdas but not the only one.

List<SubMenu> submenus = SomeList.Select(menuItem => new SubMenu() 
                                                   {
                                                         ParentMenuId = menuItem.Id 
                                                   });

In this example we have created a submenu item from all the menu items in the list. We did this through the power of LINQ to let use change the output type of the selection at will. This is very usefull when you are creating items from other items. The code block that would represent is:

List<SubMenu> SubMenus = new List<SubMenu>();

foreach(MenuItem item in SomeList)
{
    SubMenu subMenu = new SubMenu();
    subMenu.ParentMenuId = item.Id;
    SomeOtherList.Add(subMenu);
}

To me this power is amazing. I have the ability to replace entire loops with a single line. The hit to readability is a concern but lambdas lend themselves to so many applications, and are key to LINQ so it should be part of the core toolset of a developer. If you use some sense and name your lambda variables intuitively you should get a lot of great millage out of LINQ without losing your readability.

C#, C# Helpful Functions, .NET

Comments versus Well written code

16. September 2009

So the conversation started today about a guy leaving our team and needing to knowledge transfer his part of the code base to the other team members. The lead programmer on the project told him to stop working on new development and start commenting his code so that the people coming in after him would understand what he had been doing.

Personally the first thing I do when opening a code base that I am not familiar with is to press CTRL-M, CTRL-O and start looking around. ( CTRL-M, CTRL-O is the default visual studio short cut for minimize all outlining. You get to see method declarations, and that is about it.) This will collapse blocks of comments so that they are not intrusive. I never re-expand them. The idea that you need comments for understanding code to me is a big red flag for bad code. I feel well named variables are much more intuitive to learning a new code base than using comments.

I have never sat down to learn an entire code base at one sitting. I am normally working on a small part or a bug fix and need to find something that is very specific. To that end a well named class/method/property is much more helpful with you use the ?Edit->Find? code parser than having to sort through and search all the comments for the set of information that you need.

Also, I am sure that almost everyone has opened a piece of code that had a form1, or class1 class right? Those names that MS graces us with are not supposed to stay named that. Here is the way you avoid this.

Step 1: Go to add class

Step 2: DON?T CLICK OK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Step 3: Look down at the bottom of the dialog and type in something intuitive.

image

Step 4: Go drink something with an umbrella and retire to the happy place of understandable class name land.

To prove my point.

   1:  //This is a class that handles 
   2:  //calculating tax for sales in 
   3:  //several states
   4:  public class class1
   5:  {
   6:          //Calc sales total for a couple states
   7:          //AR - tax 9.5%
   8:          //NM - tax 5.5%
   9:          //TX - tax 8.5%    
  10:          public decimal calc(decimal a, string n)
  11:         {
  12:               //The quick red fox jumped over the lazy brown dog.
  13:               //The quick red fox jumped over the lazy brown dog.
  14:               //The quick red fox jumped over the lazy brown dog.
  15:               //The quick red fox jumped over the lazy brown dog.
  16:               switch(n)
  17:               {
  18:                     case "AR":
  19:                            {
  20:                                  return  a * 1.095;
  21:                             }
  22:                             break;
  23:                      case "TX":
  24:                              {
  25:                                  return a * 1.0875;
  26:                              }
  27:                              break;
  28:                      case "NM":
  29:                             {
  30:                                  return a * 1.055;
  31:                              }
  32:                              break;
  33:                }    
  34:         }
  35:  }

versus my way

   1:  public class MultiStateSalesTaxCalculator
   2:  {
   3:          public decimal ARKANSAS_STATE_SALES_TAX = 0.095;
   4:          public decimal TEXAS_STATE_SALES_TAX = 0.095;
   5:          public decimal NEW_MEXICO_STATE_SALES_TAX = 0.095;
   6:   
   7:          public decimal CalculateSalesTotalWithTaxByState(decimal SubTotal, string stateAbreveation)
   8:         {
   9:               switch(stateAbreveation)
  10:               {
  11:                     case "AR":
  12:                            {
  13:                                  return  SubTotal + ( SubTotal * ARKANSAS_STATE_SALES_TAX)  ;
  14:                             }
  15:                             break;
  16:                      case "TX":
  17:                             {
  18:                                  return SubTotal + ( SubTotal * TEXAS_STATE_SALES_TAX);
  19:                              }
  20:                              break;
  21:                      case "NM":
  22:                             {
  23:                                  return SubTotal + ( SubTotal * NEW_MEXICO_STATE_SALES_TAX);
  24:                              }
  25:                              break;
  26:                }    
  27:         }
  28:  }

.NET, C#, Design Patterns

Generics ? What you should know?

11. September 2009

I have had some interesting conversations over the last week or so about generics. It was brought up out of a MCTS study group and then in the internal DNUG that I lead. so let me break it down.

Without Generics -

I have to setup collections of objects manual and for each type that I want to use. To add, sort, filter, or aggregate this collection takes a lot of code and time. Some things like ArrayList return objects which means all that casting or reflection over head to get into the objects I need.

With Generics -

I have to setup a collection and give it the input types. It handles sorting, filtering, adding, and aggregates through the use of generic Action<T>, Func<T>, or Predicate<T>. I can write sorts and filters and make them generic so that I don?t have to copy/paste change type.

Generics are not the end all and be all but they help a great deal when you are trying not to repeat yourself. I have found that when using generics that the compiler actually spits out the methods with the implemented types in them, which means that generics while great are syntactic sugar, and I have a sweet tooth.

With Linq being based on the use of IEnumerable<T> and the new parallel extensions to .NET 4.0 being able to spread the workload of Action<T> and Task<T> across multiple processors I would tell everyone. Start learning generics. It is easy to use once you wrap your head around it. Like if I wanted to add two numbers of different types I could write this:

public float Add(int one, decimal two)
{
       float item = new float();
       item = float.Parse(one.ToString()) + float.Parse(two.ToString());
       return item;
}

public float Add(decimal one, decimal two)
{
       float item = new float();
       item = float.Parse(one.ToString()) + float.Parse(two.ToString());
       return item;
}

public float Add(int one, int two)
{
       float item = new float();
       item = float.Parse(one.ToString()) + float.Parse(two.ToString());
       return item;
}

public float Add(double one, double two)
{
       float item = new float();
       item = float.Parse(one.ToString()) + float.Parse(two.ToString());
       return item;
}

public float Add(int one, double two)
{
       float item = new float();
       item = float.Parse(one.ToString()) + float.Parse(two.ToString());
       return item;
}

public float Add(double one, decimal two)
{
       float item = new float();
       item = float.Parse(one.ToString()) + float.Parse(two.ToString());
       return item;
}

or I could write this:

public float Add<T, T2>(T one, T2 two)
{
      return float.Parse(one.ToString()) + float.Parse(two.ToString());
}

Which would you prefer?

 

Enjoy, and remember.

Code Like you have to support it.

.NET, C#, Design Patterns

Test Driven Development ? Not for the faint of heart.

10. September 2009

I started coding in C# about a year ago and almost immediately found that once I had completed a project I wanted to go back and streamline and improve it. When time allowed I started trying to do this and found that the code was very hard to verify functionality. I also found that some of my design choices were pretty novice, due to that the code was very hard to enhance. 
I got introduced to the idea of test driven development by a good friend Rob Tennyson. He presented on the topic at the Tyson Foods internal .NET user group. This peaked my interest for two reasons. One, It would allow for avoiding the novice mistakes in design and class layout. Two, it would allow for my code to have automated verification of functionality.
I set out to work TDD into my everyday process and hit several brick walls.
1. You end up making things public for testing that should not be otherwise, or putting test code into the finished product (neither is a workable solution in my book). I am using NUnit and I didn't want to have a reference to a testing package in my production code. Adding a dependency to the production code that other developers will have to deal with was not my idea of a stable codebase.
2. Being a beginner in TDD as well as C# I didn't know what I didn't know so by that lack of code and language knowledge I repeated some novice mistakes in design. Not as many as before but still a few. Some would argue that I gained knowledge and that is why I see those bottlenecks and design issues more clearly and to that my only reply is "yeah prolly".
3. Abstraction is a premium but sometimes too much work. I write a lot of small applications, an editor here, a website there. While I do work to abstract a lot of my code and provide interfaces in the right places for a small application putting in the level of seams needed for proper TDD would be building an elevator in an outhouse.
4. I found it increasingly difficult to find answers in my hunt for TDD utopia. I read several books on the subject and found that I was more often than not provided with contradictory rules to apply, or methods to use. Microsoft's "Test-Driven Development in Microsoft .NET" by James W. Newkirk and Alexei A. Vorontsov gave great baseline examples and presented the basics of TDD very well, however it fails to provide good solid base for TDD in the real world. The application that they base a lot of their examples around ignores some fairly large aspects of the TDD mindset like separation of integration testing and design testing.

With the miles behind me and a TDD utopia still nowhere in sight I have found several good ideas.

1. Kent Beck's TDD by Example is a great resource for TDD on the intermediate to advanced level.

2. Not everything needs to be designed using TDD, some things are just too trivial.

3. TDD is a design pattern, and it should be used as such. If you want automated testing use automated tests, but if you want TDD programs before one line of code is written have a test list and priority assigned to them.

I am working on a TDD project currently with Jay Smith and Rob Tennyson to write a checkers application using only TDD and having no UI or Data Layer. Building Logic first, then the UI, and finally adding a data layer to detail how to handle those real world integration concerns.

Just Remember Code like you have to support it.

C#, .NET, Productivity, Unit Testing, Design Patterns