#altnetseattle - REST Services

Below are the notes I made in the REST Architecture Session I helped kick off with Andrew.

  • RSS, ATOM, and such needed for better discovery.  i.e. there still is a need for some type of discovery.
  • Difficult is modeling behaviors in a RESTful way.  ??  Invoking some type of state against an object.  For instance in the case of a POST vs. a GET.  The GET is easy, comes back as is, but what about a POST, which often changes some state or something.
  • Challenge is doing multiple workflows with stateful workflows.  How does batch work.  Maybe model the batch as a resource.
  • Frameworks aren?t particularly part of REST, REST is REST.  But point argued that REST is modeled, or part of modeling a state machine of some sort? ?
  • Nothing is 100% reliable w/ REST ? comparisons drawn with TCP/IP.  Sufficient probability is made however for the communications, but the idea of a possible failure has to be built into the usage model of REST.
  • Ruby on Rails / RESTfully, and others used.  What were their issues, what do they do.  ATOM feeds, object serialized, using LINQ to XML w/ this.  No state machine libraries.
  • Idempotent areas around REST and single change POST changes are inherent in the architecture.
  • REST ? one of the constrained languages is for the interaction w/ the system.  Limiting what can be done on the resources.  - disagreement, there is no agreed upon REST verbs.
  • Sam Ruby ? RESTful services.  Expanded the verbs within REST/HTTP pushes you off the web.  Of the existing verbs POST leaves the most up for debate.
  • Robert Reem used Factory to deal with the POST to handle the new state.  The POST identifying what it just did by the return.
  • Different states are put into POST, so that new prospective verbs, without creating verbs for REST/HTTP can be used to advantage without breaking universal clients.
  • Biggest issue with REST services is their lack of state, yet it is also one of their biggest strengths.  What happens is that the client takes up the often onerous task of handling all state, state machines, and other extraneous resource management.  All the GETs, POSTs, DELETEs, INSERTs get all pushed into abstraction.  My 2 cents is that this in a way ends up pushing a huge proprietary burden onto the REST services often removing the point of REST to be simple and to the point.
  • WADL does provide discovery and some state control (sort of?)
  • Statement made, "WADL" isn't needed.  The JSON, XML, or other client side returned data handles this.

I then applied the law of 2 feet rule for myself and headed to finish up these notes, post to the Wiki, and figure out what I was going to do next.  For the original Wiki entry check it out here.

I will be adding more to this post with a subsequent post.  Please do feel free to post your thoughts and ideas about this, as I am sure everyone in the session will have more for elaboration.
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 4/11/2010 at 2:07 PM
Tags: ,
Categories: Events | Discussion Points or Ideas | Design Patterns
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

SOLID Thoughts

SOLID came up again in discussion.  What is SOLID?  Well, glad you asked, because I am going to elaborate on the SOLID Principles a bit.

Initial Concept
S Single Responsibility Principle
O Open/Closed Principle
L Liskov Substitution Principle
I Interface Segregation Principle
D Dependency Inversion/Injection Principle

The Single Responsibility Principle (SRP) is stated that every object should have a single responsibility and should be entirely encapsulated by the class.  This helps keep cohesion.  Here is a short example, starting with a basic class.

public class Car
{
    decimal Gas;
    int Doors;
    int Speed;
    decimal RampJumpSpeed;
}

Now I will refactor a little bit to make it a bit more SRP friendly.

public class Car
{
    decimal Gas;
    int Speed;
}
 
public class DuneBuggy : Car
{
    decimal RampJumpSpeed;
}
 
public class EconomyCar : Car
{
    int Doors;
}

What we end up with, instead of one class, is an abstract class and two classes that have their respective methods or properties to keep the responsibilities were they need to be.

The Open Closed Principle (OCP) is one of my favorites, which states simply, that you should be able to extend a classes behavior without modifying it.  There are a couple of ways one can extend a class, by inheritance, composition, or by proxy implementation. 

The Liskov Substitution Principle (LSP) states that a derived class must be substitutable for their base classes.

The Dependency Inversion Principle (DIP) states that one should depend on abstractions and not on concrete implementations.

Finally, the Interface Segregation Principle (ISP) states that fine grain interfaces should be client specific.

So hope that helps with kicking off a basic understanding of SOLID Principles.  I will be following this entry up with some new bits in the near future related to good software design and practice.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 4/6/2010 at 6:17 PM
Tags: , , , , ,
Categories: Design Patterns
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Test Driven Development Built Name Generator Part 1

This is going to be a multi-part series on building a straight forward database driven name generator.  I’ve tried the random name generator thing and it generally isn’t so great.  I’d tried in the past this idea with the database table of census names and it works great.  So this is part 1.  I’ll post these entries consecutively over the next few days so stay tuned.

First I started a new clean solution and added a test project.  I figured I wasn’t even going to add the actual assembly project yet, just jump right in and start writing a test, get red, and go to the next step.

I added a test file and wrote the following test.

   1:  [TestMethod]
   2:  public void VerifyFullNameObjectInstantiatesWithNames()
   3:  {
   4:      FullName fullName = new FullName();
   5:      Assert.IsTrue(fullName.FirstName.Length == 0);
   6:      Assert.IsTrue(fullName.LastName.Length == 0);
   7:  }

After that I used ReSharper Alt+Enter Shortcut plus a little additional keying in myself to flesh out the skeletal class and get a green light.  I ended up with the class below.

   1:  public class FullName
   2:  {
   3:      public string FirstName { get; set; }
   4:      public string LastName { get; set; }
   5:  }

Next I wanted to enforce a contract so I could create a factory to build my FullName objects with.  With that change the interface and class I had now looked like this.

   1:  public interface IFullName
   2:  {
   3:      string FirstName { get; set; }
   4:      string LastName { get; set; }
   5:  }
   6:   
   7:  public class FullName : IFullName
   8:  {
   9:      public FullName()
  10:      {
  11:          FirstName = string.Empty;
  12:          LastName = string.Empty;
  13:      }
  14:   
  15:      public string FirstName { get; set; }
  16:      public string LastName { get; set; }
  17:  }

That gave me a green light on my first test.  After that I built a test for the factory that could build the names.

   1:  [TestMethod]
   2:  public void VerifyFullNameObjectReturnsFromFactory()
   3:  {
   4:      IFullName name = NameFactory.Build();
   5:      Assert.IsTrue(name.FirstName.Length > 0);
   6:      Assert.IsTrue(name.LastName.Length > 0);
   7:  }

I then took the NameFactory object and fleshed it out so I could build, run the test, and get green lighted.  Below is the NameFactory Class.

   1:  public class NameFactory
   2:  {   
   3:      public static IFullName Build()
   4:      {
   5:          return new FullName { FirstName = "TestFirst", LastName = "TestLast" };
   6:      }
   7:  }

So now I have a green light on the name factory.  But even though I have a green light, it doesn’t exactly do what it needs to do, which is get some good unique and random names.  Next step, write a test for getting back some random names.

   1:  [TestMethod]
   2:  public void VerifyFullNameIsRandom()
   3:  {
   4:      IFullName nameOne = NameFactory.Build();
   5:      IFullName nameTwo = NameFactory.Build();
   6:   
   7:      Assert.AreNotEqual(nameOne.FirstName, nameTwo.FirstName);
   8:      Assert.AreNotEqual(nameOne.LastName, nameTwo.LastName);
   9:  }

After creating this test, I have to dive a little deeper.  First I grabbed the census names for first and last names off of the Internet.  After that I added two projects to my overall Visual Studio Solution.  One is a database project and one is Windows App to use to manipulate the text file data and get it into our database.

Next I created the Generator Database a table to store the names that are stored in the files.

The SQL create script is shown below.

   1:  IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Names]') AND type in (N'U'))
   2:  BEGIN
   3:  CREATE TABLE [dbo].[Names](
   4:      [NameId] [uniqueidentifier] NOT NULL,
   5:      [Name] [nvarchar](50) NOT NULL,
   6:      [Type] [smallint] NOT NULL,
   7:   CONSTRAINT [PK_Names] PRIMARY KEY CLUSTERED 
   8:  (
   9:      [NameId] ASC
  10:  )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
  11:  ) ON [PRIMARY]
  12:  END

I also added an extended property to outline how I intended to use the “Type” column.

   1:  IF NOT EXISTS (SELECT * FROM ::fn_listextendedproperty(N'MS_Description' , N'SCHEMA',N'dbo', N'TABLE',N'Names', N'COLUMN',N'Type'))
   2:  EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'1 = Male, 2 = Female, 3 = Last Name' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'Names', @level2type=N'COLUMN',@level2name=N'Type'

My intention is for the “Type” column to have a 1 for the male first name, a 2 for a female first name, and a 3 for the last name.

I’ve covered creating the initial tests and objects to use.  Also the database table that is needed and the create scripts have been provided.  Next steps are to build a quick app to get the names imported into the database table.  Stay tuned and that will be posted tomorrow.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: adron
Posted on: 2/4/2009 at 7:20 AM
Tags: , , , , ,
Categories: How-To, Samples, and Such | Design Patterns | My Projects
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (2) | Post RSSRSS comment feed

Software, Success and Ranting

I've been extra active reading blog entries lately and have come upon a few that have really got me kind of wired.

Software Development Dogmata - Good Practices Gone Bad

The first one is this article by Daniel Pietraru (who I do not know) over on little tutorials "Software development dogmata - good practices gone bad".  There are few major issues I have with this slight skewing of facts.  Overall, excellent article, but there are some issues.

First is the "Agile != Flexible".  Read the manifesto, there is no such thing as Agile that isn't flexible.  The birth of agile that is mentioned is rather skewed too.  If you truly want to learn about Agile, and you have a motivation to have good, happy, satisfied employees that are highly productive, look up the motivations behind Agile.  Otherwise, don't.

Daniel then goes on to negate the benefits of a short development cycle.  Iteration based development has proven so effective almost every major process out there these days takes some form of this.  As for the statement he makes "you cannot demo a car engine until it is fully built" is patently wrong.  You CAN demo a car engine and that is the entire point behind computer models used solely to design engines, and cars in general, in a very LEAN or AGILE manner.  So you can deny it, but I believe these methodologies, the focus on individuals, individual motivation, individual enablement, and other such characteristics of lean, agile, and others is exactly why Toyota has stomped the competition is is basically the world leader in automotive manufacturing and quality.

One really can't deny Toyota's success, and it is the prime cut of what agile is.

Pair programming, he has a slightly decent point on this topic.  I too find myself torn about the usefulness of pair programming.  It does, however have positive effects, but I don't buy into the eXtreme Agile approach to the whole pairing with one keyboard and one mouse.  Working together, communicating, and effectively integrating code into the main continuous integration serves just fine.  But, I can't really knock it either as I haven't truly tried hard core pair programming.

He goes on to slander design patterns, TDD, UML, and a few other things that most developers are fully aware is very helpful in software development.  Not sure why he hates so much of successful software.  I ponder, what does he like about successful software?

In Daniel's defense, he does have some valid topics, just the article is angry and seems to be centered incorrectly and lash out in ways that don't do the points he makes justice.  He does point to a very effective proven use of Agile methodologies, on a massive scale, for a company that turns a little it of profit now.  Google - so read the WHOLE ARTICLE of Stevey's (this guy works for Google and I've read his material several times) and don't be so frustrated with Agile, there ARE good and bad versions.  But I digress, on to the next.

Naming Conventions:  Are They Really That Important?

I stumbled on this entry, I don't know when, but somehow it reflected several conversations I've had recently.  I like naming conventions, when enforced by ReSharper, Intellisense, or something of that sort.  But to remember all, and then have new developers go about learning them all in today's development environment is...

...well...

...an utter waste of time.  Naming conventions are in no way important like they used to be.

Source Control is not a feature you can postpone to vNext

I just thought as I have many times, Microsoft doesn't seem to get source control.  Ayende @ Rahien (the awesome software simian) goes on a slight rant about the absurdity of their solutions so far.

Why are the Microsoft Office file formats so complicated? (And some workarounds)

It also seems that with my new effort to build awesome Office interfaces, tools, and solid back end architecture for these systems I've found the insanity of Microsoft's Office file formats.  I never realized, but Joel Spolsky, who I've read a lot of lately, worked on the Excel team at one point.  He points out that there a more than a few pages (349 in one PDF) of documentation solely about the file formats of Office.

A Field Guide to Developers

Joel also did a great write up in the year 2006 about how to get a keep top developers happy and productive.  Things like private offices, cool toys, a good physical work space, and one of the most important topics being the social existence of programmers.  It points out the importance of having great colleagues, independence and autonomy, how they're treated, and that there are no politics of the feeling type.  As he states in the entry, "And this is the kind of environment you have to create to attract programmers. When a programmer complains about “politics,” they mean—very precisely—any situation in which personal considerations outweigh technical considerations. Nothing is more infuriating than when a developer is told to use a certain programming language, not the best one for the task at hand, because the boss likes it. Nothing is more maddening than when people are promoted because of their ability to network rather than being promoted strictly on merit. Nothing is more aggravating to a developer than being forced to do something that is technically inferior because someone higher than them in the organization, or someone better-connected, insists on it.".  This, no politics philosophy, is absolutely 100% true!

Of only it was more common!

Top Five (Wrong) Reasons you Don't Have Testers

...and an article on why a company, that intends to build good and reliable software should always have software testers.  Again, by Joel Spolsky.

I also dug up another very interesting experiment that the company 37signals undertook.  4 day work weeks.

Workplace Experiments

Amazingly, they got the same out of a 4 day work week as a 5 day work week.  Oddly enough people work much more diligently and effectively when they're able to get a solid weekend of separation from work.  This obviously wouldn't work with every occupation, like for instance McDonalds would probably get minimal amount of use out of 4 day work weeks, but software developers are not McDonalds employees.

Another great article in a similar vein is Increasing sustainable pace.  One of the comments is a classic combination of my railroading interests and software development, "Working more hours may not be the best solution. In the long run, working smarter always wins over working for longer periods. John Henry was the best rail spike driver in his day, and he died proving it. Power tools today let anyone work faster than John ever did.".  I firmly believe that smart workers will produce far more than a bunch of overworked code monkeys.  In my experience this has also been proven time and time again.  This blog entry led me to a few searches, which then led me to some other articles.

That has been my reading for the day.  It's been a ton but I just got on a blog reading kick and figured I'd write up what I've read as of late.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 8/18/2008 at 9:03 PM
Categories: Design Patterns | Rants | Discussion Points or Ideas | Agile, Theory, and Process Stuff
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Setting Sail with the Smuggling Pattern :: Part 1

Maybe because I'm often entertained by the geekiest of things, I've started usage of the Smuggling Pattern named after a fellow software architect Matt Davis's terminology of smuggling data into and out of Excel.  It is something that I've lately needed to do on a regular basis, get data into and out of Excel without Excel, or at least the evil COM Interop Model, really knowing what is going on.  In other words, I want total programmatic control over data so I can trust it versus Excel mangling my poor data up.  This is what the Smuggling Pattern is going to do for me, and it is doing it well.

Now you might think, "WTF!"  But just to clarify, the Smuggling Pattern is really the Builder Pattern that we architects know and love with a cooler more fun more pirate like name!  So with that, here's some of that code, and the TDD process I undertook to get this sucker built to set sail.

First I created a C# Class Project and created the following file folder structure and files.

Once I completed that I jumped right into testing.  Of course with ReSharper it makes life so much friggin simpler, in addition to TDD making life simpler.  I do still admit, that if you're not practiced at TDD, then doing tests in whatever order you are comfortable with still keeps you at peak performance.  But eventually you should work toward TDD and toss in a great tool like ReSharper.  The difference in speed and quality is almost like getting 2 of the 3 engineering axioms instead of just 1 (i.e. speed, quality, & cost).

The first tests I started on where the individual builder tests, or in my case the Smuggler Object.  I always create a check for null just to make sure that I named the file correctly, kind of a double check, and it gives me the attribute, category, and other parts that I can copy to the other tests easily.

using Production.Smugglers.Builders;
using NUnit.Framework;

namespace Production.Tests
{
    [TestFixture]
    public class SmugglerTests
    {
        [Test, Category("Builder Tests")]
        public void TestsSmugglerIsNotNull()
        {
            var smuggler = new Smuggler();
            Assert.IsNotNull(smuggler);
        }
    }
}

This test I ran and it proved that the smuggler does instantiate appropriately, albeit not doing a single useful thing yet.  Next test...

[Test, Category("Builder Tests")]
public void TestsSmugglerOrderCompletionResult()
{
    var smuggler = new Smuggler();
    smuggler.CompleteOrder();
    SmuggledClassForTest smuggled = smuggler.GetSmuggledSwag();
    Assert.AreEqual(smuggled.StuffTestValue, Resources.ValueForTestingSmugglerSmuggled);
}

Now this test, if you view the picture, didn't color code so well.  ReSharper points out that the instantiated class smuggler doesn't have a CompleteOrder or GetSmuggledSwag method.

image 2

Move the curser (and new character marker over the red method) and hit Alt+Enter (IntelliJ Keymapping) and select the Create method 'Smuggler.CompleteOrder'.

Now we have no more red, and the class Smuggler now has the method CompleteOrder.  The same code that is displayed in the image is directly below it so it can be copied and pasted easily.  Also note, I went ahead and added the IBuilder interface to the class since it will need to meet the contractual obligations of the builder interface.

namespace Production.Smugglers.Builders
{
    public class Smuggler : IBuilder
    {
        public void CompleteOrder()
        {
            throw new NotImplementedException();
        }
    }
}

I then wrote the following additional test, below is the additional test and the ones I already completed in total.

[TestFixture]
public class SmugglerTests
{
    [Test, Category("Builder Tests")]
    public void TestsSmugglerIsNotNull()
    {
        var smuggler = new Smuggler();
        Assert.IsNotNull(smuggler);
    }

    [Test, Category("Builder Tests")]
    public void TestsSmugglerSmuggledIsNotNull()
    {
        Smuggler smuggler = new Smuggler();
        smuggler.CompleteOrder();
        SmuggledClassForTest smuggled = smuggler.GetSmuggledSwag();
        Assert.IsNotNull(smuggled);
    }

    [Test, Category("Builder Tests")]
    public void TestsSmugglerOrderCompletionResult()
    {
        Smuggler smuggler = new Smuggler();
        smuggler.CompleteOrder();
        SmuggledClassForTest smuggled = smuggler.GetSmuggledSwag();
        Assert.AreEqual(smuggled.StuffTestValue, Properties.Resources.ValueForTestingSmugglerSmuggled);
    }
}

After that I went ahead and fleshed out the following classes to get the smuggler tests to green light.  First I stuck a resource variable in for my "test variable value".  One could do this another million ways but I figured this quick n' easy.

This resource file is located in the Properties of the project.

Find the resources by clicking the tab...

Then finished the interface (for now of course).

namespace Production.Smugglers.Builders
{
    public interface IBuilder
    {
        void CompleteOrder();
        SmuggledClassForTest GetSmuggledSwag();
    }
}

Then finished the Smuggler Class (i.e. Builder).

namespace Production.Smugglers.Builders
{
    public class Smuggler : IBuilder
    {
        private readonly SmuggledClassForTest smuggledClassForTest = new SmuggledClassForTest();

        public void CompleteOrder()
        {
            smuggledClassForTest.StuffTestValue = Resources.ValueForTestingSmugglerSmuggled;
        }

        public SmuggledClassForTest GetSmuggledSwag()
        {
            return smuggledClassForTest;
        }
    }
}

Then the little SmuggledClassForTests class, which is basically the product of the builder.

namespace Production.Smugglers.Smuggled
{
    public class SmuggledClassForTest
    {
        public string StuffTestValue { get; set; }
    }
}

Note the namespaces, I make a point to follow the standard of maintaining folder and namespace integrity.  I promise keeping the integrity makes getting to and finding code way faster than getting those things out of sync.

I then ran the tests again...

...green lights!

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Enterprise Library by Part

Sometimes I want to use the enterprise library, but just not all 200+ MB of the thing.  So I go about piecing together the pieces I want, by project, into the main solution.  This can be troublesome as all the pieces don't just drop in simply.

First Bump in the Road :: GlobalAssemblyInfo.cs

The first problem I've run into this time around was the GlobalAssemblyInfo.cs file wasn't available.  After fiddling around a minute I realized this needed to be added to the solution at a global level.  The way to do this is to right click and add existing file to the actual Solution.  Unfortunately I had statically added a copy of this file to my projects I was adding and simply re-added those projects with the appropriate file mapping again.  Note to self, "If adding individual blocks from the enterprise library make sure to add the GlobalAssemblyInfo.cs file first and then the individual blocks".

Second Bump ::  The "Common" Project

The common project is used in pretty much every single project in the enterprise library solution.  For some reason when I added all my projects, the common reference went away in numerous projects.  So this was a case of just adding the reference back to several of the projects.  Maybe I shouldn't add them this way, but regardless, it gets the job done.

So far I'm now up and running, but just wanted to present a searchable note about these bumps I've hit.  Once these things are resolved the library blocks are flawless.

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 7/20/2008 at 12:48 PM
Categories: My Projects | How-To, Samples, and Such | Design Patterns | Transit Engine
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Stand Up, SCRUM, or Some Other Name - Pt. 3 - Super Day

Yesterday was rough going, mainly just because there was so many topics to cover.  Today I hope to nail a ton more functional code segments, requirements, and get some unit tests in my work.

Yesterday

  • Finished clarification of the task list and working to find the priorities for this iteration.
  • Met to clarify design goals and functional requirements for new features.

Today

  • Core focus will be on functional requirements and getting the respective unit tests, preferably via TDD for the interface based controller and presenter code.  I'll be happy with test after for the UI elements since they're all COM Interop.  i.e.,  today is code day.

Tomorrow

  • Continue focus on functional specifications and respective tests.

Road Blocks & Risks

  • Continued - Time constraints have all but eliminated efforts to research or implement a proof around the PIAB, limiting our exception handling, logging, and other cross cutting concerns we need to have in place.
  • Continued - The IoC and DI architecture points have not been clarified.  The more UI work we do without these pieces in place the more tightly coupled, untested, and unworkable refactor efforts will be in the future.
  • Continued - Significant risks include; lack of significant code coverage from unit tests, unclear way for testing the upper layers of Excel/UI functionality.
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

TDD, Architecture and Testing Code in Isolation :: Part 2

Navigate back to Part 1 of this series of entries.

The next steps I undertook are some of my various clean ups.  Create respective test classes for each of the pieces of the database that will have respective entities, methods, or objects to test.

I like to keep code clean, easy to read, and were it needs to be.  I hate code bloat, misplaced code sections, and above all I can't stand arbitrary pieces of using statements, random misuses of methods (such as ToString()) and other such things.  Luckily for me JetBrains Software created ReSharper.  So before going to far headlong into the tests I always run a few "Cleanup Code..." functions on my newly created files.

I usually just leave the cleanup code settings on full and click run.

The code already, with just the crude skeleton goes from this...

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:  using MbUnit.Framework;
   6:   
   7:  namespace DataAccessLayer.Unit.mbUnitTests
   8:  {
   9:      [TestFixture]
  10:      public class Users
  11:      {
  12:          [Test]
  13:          public void Test()
  14:          {
  15:              //
  16:              // TODO: Add test logic here
  17:              //
  18:          }
  19:      }
  20:  }

...to this...

using MbUnit.Framework;
   1:  namespace DataAccessLayer.Unit.mbUnitTests
   2:  {
   3:      [TestFixture]
   4:      public class Users
   5:      {
   6:          [Test]
   7:          public void Test()
   8:          {
   9:              //
  10:              // TODO: Add test logic here
  11:              //
  12:          }
  13:      }
  14:  }

Reason number eight gazillion that ReSharper RULEZ!  I almost forgot too, I need to have my Rhino Mock Library References.  If you don't have the Rhino Mock Library you can download it.  Generally I just put a folder in the solution, stick the DLL in it, and then browse to make a reference.

Now that we have clean test fixtures I'm going to run some green lights.  Green light tests that is, which is not in true TDD fashion.  The reason though is because this layer will be tests against a generated layer (the LINQ to SQL).  The generated layer doesn't really require a red light green light process, so I'm just going to write the bare minimum of green light tests against the layer.  Then when we go to the next layer, which WILL need to be red light green light I'll already have this layer tested appropriately. 

Before going any further and I forget another reference I'm grabbing the DAL Layer assembly.

Now that I've managed to not forget the references, which I've been working on doing, and I have the appropriate items in place.  The next step NOW is to get those green lights.  Off to the reckless abandon of TDD.  The first tests I write are simple, no frills, just to get and test the TsrUser and TmtUser Entities.

   1:  using System;
   2:  using MbUnit.Framework;
   3:  using Rhino.Mocks;
   4:   
   5:  namespace DataAccessLayer.Unit.mbUnitTests
   6:  {
   7:      [TestFixture]
   8:      public class Users
   9:      {
  10:          [Test]
  11:          public void TestTsrUserEntity()
  12:          {
  13:              Guid newUserId = Guid.NewGuid();
  14:              TsrUser tsrUser = MockRepository.GenerateStub<TsrUser>();
  15:              tsrUser.UserId = newUserId;
  16:              Assert.AreEqual(tsrUser.UserId, newUserId);
  17:          }
  18:   
  19:          [Test]
  20:          public void TestTmtUserEntity()
  21:          {
  22:              Guid newUserId = Guid.NewGuid();
  23:              TmtUser tmtUser = MockRepository.GenerateStub<TmtUser>();
  24:              tmtUser.UserId = newUserId;
  25:              Assert.AreEqual(tmtUser.UserId, newUserId);
  26:          }
  27:      }
  28:  }

Next, hit up the User Lists derived from the views.  This is where the mocking gets truly interesting.  The above tests, while they help, really don't do much of anything.  Next what I need is a way to mock out the DataContext Class, which doesn't have an interface.  This is a slight issue, but just requires a little manual coding to get a good mock going.  Since I knew I'd be using this for multiple testing projects I've created a completely new project to reference.  Since I'm not always creative I'm naming it "UnitTest" and then will name the files respectively.

I also found a bit of code specifically for mocking the DataContext over at Andrew Tokeley's Blog on Mocking LINQ to SQL DataContext.  I've snagged it and have altered it for the particular project.  Make sure to give dibs to Andrew!  Below are the modified interfaces and the respective classes.  Make sure to add a reference to the DAL for the project too.  Then add the files listed below in the screen shot.

IDataContextWrapper Interface

   1:  using System;
   2:  using System.Collections.Generic;
   3:   
   4:  namespace UnitTest.Interfaces
   5:  {
   6:      public interface IDataContextWrapper : IDisposable
   7:      {
   8:          List<T> Table<T>() where T : class;
   9:          void DeleteAllOnSubmit<T>(IEnumerable<T> entities) where T : class;
  10:          void DeleteOnSubmit<T>(T entity) where T : class;
  11:          void InsertOnSubmit<T>(T entity) where T : class;
  12:          void SubmitChanges();
  13:      }
  14:  }

IMockDatabase Interface

   1:  using System;
   2:  using System.Collections;
   3:  using System.Collections.Generic;
   4:   
   5:  namespace UnitTest.Interfaces
   6:  {
   7:      public interface IMockDatabase
   8:      {
   9:          Dictionary<Type, IList> Tables { get; set; }
  10:      }
  11:  }

MockDatabase Class

   1:  using System;
   2:  using System.Collections;
   3:  using System.Collections.Generic;
   4:   
   5:  namespace UnitTest.Mocks
   6:  {
   7:      /// <summary>
   8:      /// Abstract Template class that represents our in memory database. We can create different implementations of this class that contain different
   9:      /// tables and data.
  10:      /// </summary>
  11:      public abstract class MockDatabase
  12:      {
  13:          protected MockDatabase()
  14:          {
  15:              InitializeDataBase();
  16:          }
  17:   
  18:          public Dictionary<Type, IList> Tables { get; set; }
  19:   
  20:          private void InitializeDataBase()
  21:          {
  22:              Tables = new Dictionary<Type, IList>();
  23:              CreateTables();
  24:              PopulateTables();
  25:          }
  26:   
  27:          protected abstract void CreateTables();
  28:          protected abstract void PopulateTables();
  29:   
  30:          protected void AddTable<T>()
  31:          {
  32:              var table = new List<T>();
  33:              Tables.Add(typeof (T), table);
  34:          }
  35:   
  36:          protected List<T> GetTable<T>()
  37:          {
  38:              return (List<T>) Tables[typeof (T)];
  39:          }
  40:      }
  41:  }

MockDatabaseContextWrapper Wrapper Class

   1:  using System.Collections.Generic;
   2:  using UnitTest.Interfaces;
   3:   
   4:  namespace UnitTest.Mocks
   5:  {
   6:      /// <summary>
   7:      /// A linq to sql wrapper class. This is a mock implementation of IDataContextWrapper
   8:      /// that works directly with an in memory version of a database 
   9:      /// </summary>
  10:      public class MockDataContextWrapper : IDataContextWrapper
  11:      {
  12:          private readonly MockDatabase _mockDatabase;
  13:   
  14:          public MockDataContextWrapper(MockDatabase database)
  15:          {
  16:              _mockDatabase = database;
  17:          }
  18:   
  19:          #region IDataContextWrapper Members
  20:   
  21:          public List<T> Table<T>() where T : class
  22:          {
  23:              return (List<T>) _mockDatabase.Tables[typeof (T)];
  24:          }
  25:   
  26:          public void DeleteAllOnSubmit<T>(IEnumerable<T> entities) where T : class
  27:          {
  28:              foreach (T entity in entities)
  29:              {
  30:                  Table<T>().Remove(entity);
  31:              }
  32:          }
  33:   
  34:          public void DeleteOnSubmit<T>(T entity) where T : class
  35:          {
  36:              Table<T>().Remove(entity);
  37:          }
  38:   
  39:          public void InsertOnSubmit<T>(T entity) where T : class
  40:          {
  41:              Table<T>().Add(entity);
  42:          }
  43:   
  44:          public void SubmitChanges()
  45:          {
  46:          }
  47:   
  48:          public void Dispose()
  49:          {
  50:          }
  51:   
  52:          #endregion
  53:      }
  54:  }

DataContextWrapper Wrapper Class

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Data.Linq;
   4:  using System.Linq;
   5:  using UnitTest.Interfaces;
   6:   
   7:  namespace UnitTest
   8:  {
   9:      /// <summary>
  10:      /// A linq to sql wrapper class for the Datacontext object. This is the real implementation of IDataContextWrapper
  11:      /// that works directly with a database 
  12:      /// </summary>
  13:      /// <typeparam name="T"></typeparam>
  14:      public class DataContextWrapper<T> : IDataContextWrapper where T : DataContext, new()
  15:      {
  16:          private readonly T db;
  17:          private bool _disposed;
  18:   
  19:          public DataContextWrapper()
  20:          {
  21:              Type t = typeof (T);
  22:              db = (T) Activator.CreateInstance(t);
  23:          }
  24:   
  25:          public DataContextWrapper(string connectionString)
  26:          {
  27:              Type t = typeof (T);
  28:              db = (T) Activator.CreateInstance(t, connectionString);
  29:          }
  30:   
  31:          #region IDataContextWrapper Members
  32:   
  33:          public List<TableName> Table<TableName>() where TableName : class
  34:          {
  35:              var table = (Table<TableName>) db.GetTable(typeof (TableName));
  36:   
  37:              return table.ToList();
  38:          }
  39:   
  40:          public void DeleteAllOnSubmit<Entity>(IEnumerable<Entity> entities) where Entity : class
  41:          {
  42:              db.GetTable(typeof (Entity)).DeleteAllOnSubmit(entities);
  43:          }
  44:   
  45:          public void DeleteOnSubmit<Entity>(Entity entity) where Entity : class
  46:          {
  47:              db.GetTable(typeof (Entity)).DeleteOnSubmit(entity);
  48:          }
  49:   
  50:          public void InsertOnSubmit<Entity>(Entity entity) where Entity : class
  51:          {
  52:              db.GetTable(typeof (Entity)).InsertOnSubmit(entity);
  53:          }
  54:   
  55:          public void SubmitChanges()
  56:          {
  57:              db.SubmitChanges();
  58:          }
  59:   
  60:          public void Dispose()
  61:          {
  62:              Dispose(true);
  63:              GC.SuppressFinalize(this);
  64:          }
  65:   
  66:          #endregion
  67:   
  68:          private void Dispose(bool disposing)
  69:          {
  70:              if (_disposed)
  71:                  return;
  72:   
  73:              if (disposing)
  74:              {
  75:                  db.Dispose();
  76:              }
  77:   
  78:              _disposed = true;
  79:          }
  80:      }
  81:  }

ExampleMockDatabase Class

   1:  using System;
   2:  using DataAccessLayer;
   3:   
   4:  namespace UnitTest.Mocks
   5:  {
   6:      /// <summary>
   7:      /// This is an actual implementation of our database containing specific tables and data.
   8:      /// </summary>
   9:      public class ExampleMockDatabase : MockDatabase
  10:      {
  11:          protected override void CreateTables()
  12:          {
  13:              AddTable<TsrUserListing>();
  14:          }
  15:   
  16:          protected override void PopulateTables()
  17:          {
  18:              var testTsrUserListing1 =
  19:                  new TsrUserListing
  20:                      {
  21:                          UserId = Guid.NewGuid(),
  22:                          UserName = "Test User",
  23:                          LoweredUserName = "test user",
  24:                          IsAnonymous = false,
  25:                          LastActivityDate = DateTime.Now.AddDays(-4),
  26:                          MobileAlias = "test user"
  27:                      };
  28:              var testTsrUserListing2 =
  29:                  new TsrUserListing
  30:                      {
  31:                          UserId = Guid.NewGuid(),
  32:                          UserName = "User Test",
  33:                          LoweredUserName = "user test",
  34:                          IsAnonymous = true,
  35:                          LastActivityDate = DateTime.Now.AddMinutes(-23),
  36:                          MobileAlias = "user test"
  37:                      };
  38:              var testTsrUserListing3 =
  39:                  new TsrUserListing
  40:                      {
  41:                          UserId = Guid.NewGuid(),
  42:                          UserName = "John Doe",
  43:                          LoweredUserName = "john doe",
  44:                          IsAnonymous = true,
  45:                          LastActivityDate = DateTime.Now.AddHours(-22),
  46:                          MobileAlias = "john doe"
  47:                      };
  48:   
  49:              GetTable<TsrUserListing>().Add(testTsrUserListing1);
  50:              GetTable<TsrUserListing>().Add(testTsrUserListing2);
  51:              GetTable<TsrUserListing>().Add(testTsrUserListing3);
  52:          }
  53:      }
  54:  }

CustomerController Class

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using DataAccessLayer;
   5:  using UnitTest.Interfaces;
   6:   
   7:  namespace UnitTest.Controller
   8:  {
   9:      public class TsrUserListingController
  10:      {
  11:          public IDataContextWrapper DataContext { get; set; }
  12:   
  13:          public IEnumerable<TsrUserListing> GetTsrUserListing(DateTime lastActivityDate)
  14:          {
  15:              IEnumerable<TsrUserListing> tsrUserListings = from tsrUserListing in DataContext.Table<TsrUserListing>()
  16:                                                            where tsrUserListing.LastActivityDate >= lastActivityDate
  17:                                                            select tsrUserListing;
  18:              return tsrUserListings;
  19:          }
  20:   
  21:          public IEnumerable<TsrUserListing> GetTsrUserListing()
  22:          {
  23:              IEnumerable<TsrUserListing> tsrUserListings = from tsrUserListing in DataContext.Table<TsrUserListing>()
  24:                                                            select tsrUserListing;
  25:              return tsrUserListings;
  26:          }
  27:      }
  28:  }

Now that we have the database fake/mock - whatever one wants to call it - we're ready for some tests.  So stay tuned, I'll have it up tomorrow.

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

TDD, Architecture and Testing Code in Isolation :: Part 1

Just a few examples here.  First we'll setup the basic architecture from the lowest common denominator - the database - bounce up to the first layer, and test in isolation and test in integration.  These examples are simply the easiest ways to test the basic data and data access layer using Stubs, Mocks, and general unit test practices.

First off here are the pieces of the architecture that you'll NEED regardless.  No real coding in this entry (except for the T-SQL), just setting up the solution to put the tests in and have the initial database architecture setup.  The part 2 entry will have more on the testing, and part 3 will have actual functional code tests and implementations - after all, I'm working this up in a test driven development mentality - "mostly".

The Beginning

Setup the following projects within a new VS.NET solution.  I broke out the projects as you see below. (Click to see the larger image)

I like to keep my unit and integration tests separate so that they're easy to include or exclude from a continuous integration build.  Because really, the integration tests aren't generally going to work in a regular build.  Unless of course you've scripted out some serious steps such as "Create a Setup MSI" and "install the software and run" etc.  Which in my mind, just seems a bit out of line with the build process.  Not to even mention extremely time consuming.  I however think that a good solid and separate CI build of the respective setup project should be kept in a different solution that when it does alter can have a build process and either an automated integration test run or have the integration tests manually run.  Either way, they get run, but in my humble opinion shouldn't be run during the regular CI build of the working solution.

If you don't have mbUnit installed, go grab a copy over at www.mbunit.com.

The next thing I did is setup the databases.  I have some odd requirements for the particular database schema and segmentation of various databases for the application components.  The Grand Central Database is used for the security, membership, roles, etc, the other databases are used for each of the application "components".  Each of these "component" databases I'll refer to as either "component" or "tsr" or "tmt" respectively.  These "component" databases I've setup for use once a user is authenticated.  So each of these databases has a Users Table that has a UserId Column that will be used for relating the respective user that has access to the particular component.

First I setup the tables:

tmtUsers

   1:  /****** Object:  Table [dbo].[tmtUsers]    Script Date: 07/06/2008 01:27:07 ******/
   2:  IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tmtUsers]') AND type in (N'U'))
   3:  DROP TABLE [dbo].[tmtUsers]
   4:  GO
   5:  /****** Object:  Table [dbo].[tmtUsers]    Script Date: 07/06/2008 01:27:07 ******/
   6:  SET ANSI_NULLS ON
   7:  GO
   8:  SET QUOTED_IDENTIFIER ON
   9:  GO
  10:  IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tmtUsers]') AND type in (N'U'))
  11:  BEGIN
  12:  CREATE TABLE [dbo].[tmtUsers](
  13:      [UserId] [uniqueidentifier] NOT NULL,
  14:   CONSTRAINT [PK_tmtUsers] PRIMARY KEY CLUSTERED 
  15:  (
  16:      [UserId] ASC
  17:  )WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
  18:  ) ON [PRIMARY]
  19:  END
  20:  GO
 

tsrUsers

 
   1:  /****** Object:  Table [dbo].[tsrUsers]    Script Date: 07/06/2008 01:50:30 ******/
   2:  IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tsrUsers]') AND type in (N'U'))
   3:  DROP TABLE [dbo].[tsrUsers]
   4:  GO
   5:  /****** Object:  Table [dbo].[tsrUsers]    Script Date: 07/06/2008 01:50:31 ******/
   6:  SET ANSI_NULLS ON
   7:  GO
   8:  SET QUOTED_IDENTIFIER ON
   9:  GO
  10:  IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tsrUsers]') AND type in (N'U'))
  11:  BEGIN
  12:  CREATE TABLE [dbo].[tsrUsers](
  13:      [UserId] [uniqueidentifier] NOT NULL,
  14:   CONSTRAINT [PK_tsrUsers] PRIMARY KEY CLUSTERED 
  15:  (
  16:      [UserId] ASC
  17:  )WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
  18:  ) ON [PRIMARY]
  19:  END
  20:  GO


After creating the tables I went ahead and created a view that would link the UserId do the Grand Central Database and a respective stored procedure too.  I created these by simply dragging the tables onto the designer for creating the view from each of the respective databases. (Click to see the larger image)

The SQL for the views is below.  The TSR and TMT Databases both use basically the same exact SQL.

tmtUserListing

   1:  SELECT     dbo.tmtUsers.UserId, GrandCentral.dbo.aspnet_Users.UserName
   2:  FROM         dbo.tmtUsers LEFT OUTER JOIN
   3:                        GrandCentral.dbo.aspnet_Users ON dbo.tmtUsers.UserId = GrandCentral.dbo.aspnet_Users.UserId

tsrUserListing

   1:  SELECT     dbo.tsrUsers.UserId, GrandCentral.dbo.aspnet_Users.UserName, GrandCentral.dbo.aspnet_Users.LoweredUserName, GrandCentral.dbo.aspnet_Users.MobileAlias, 
   2:                        GrandCentral.dbo.aspnet_Users.IsAnonymous, GrandCentral.dbo.aspnet_Users.LastActivityDate
   3:  FROM         dbo.tsrUsers INNER JOIN
   4:                        GrandCentral.dbo.aspnet_Users ON dbo.tsrUsers.UserId = GrandCentral.dbo.aspnet_Users.UserId
 

and last but not least the two stored procedures.

tmtUserListingSelect

 
   1:  /****** Object:  StoredProcedure [dbo].[tmtUserListingSelect]    Script Date: 07/06/2008 01:36:33 ******/
   2:  IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tmtUserListingSelect]') AND type in (N'P', N'PC'))
   3:  DROP PROCEDURE [dbo].[tmtUserListingSelect]
   4:  GO
   5:  /****** Object:  StoredProcedure [dbo].[tmtUserListingSelect]    Script Date: 07/06/2008 01:36:33 ******/
   6:  SET ANSI_NULLS ON
   7:  GO
   8:  SET QUOTED_IDENTIFIER ON
   9:  GO
  10:  IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tmtUserListingSelect]') AND type in (N'P', N'PC'))
  11:  BEGIN
  12:  EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE dbo.tmtUserListingSelect
  13:      
  14:  AS
  15:      SELECT     dbo.tmtUsers.UserId, GrandCentral.dbo.aspnet_Users.UserName
  16:  FROM         dbo.tmtUsers LEFT OUTER JOIN
  17:                        GrandCentral.dbo.aspnet_Users ON dbo.tmtUsers.UserId = GrandCentral.dbo.aspnet_Users.UserId
  18:                        
  19:      RETURN
  20:  ' 
  21:  END
  22:  GO

tsrUserListingSelect

 
   1:  /****** Object:  StoredProcedure [dbo].[tsrUserListingSelect]    Script Date: 07/06/2008 01:50:38 ******/
   2:  IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tsrUserListingSelect]') AND type in (N'P', N'PC'))
   3:  DROP PROCEDURE [dbo].[tsrUserListingSelect]
   4:  GO
   5:  /****** Object:  StoredProcedure [dbo].[tsrUserListingSelect]    Script Date: 07/06/2008 01:50:38 ******/
   6:  SET ANSI_NULLS ON
   7:  GO
   8:  SET QUOTED_IDENTIFIER ON
   9:  GO
  10:  IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[tsrUserListingSelect]') AND type in (N'P', N'PC'))
  11:  BEGIN
  12:  EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE dbo.tsrUserListingSelect
  13:      
  14:  AS
  15:  SELECT     dbo.tsrUsers.UserId, GrandCentral.dbo.aspnet_Users.UserName, GrandCentral.dbo.aspnet_Users.LoweredUserName, GrandCentral.dbo.aspnet_Users.MobileAlias, 
  16:                        GrandCentral.dbo.aspnet_Users.IsAnonymous, GrandCentral.dbo.aspnet_Users.LastActivityDate
  17:  FROM         dbo.tsrUsers INNER JOIN
  18:                        GrandCentral.dbo.aspnet_Users ON dbo.tsrUsers.UserId = GrandCentral.dbo.aspnet_Users.UserId
  19:      RETURN
  20:  ' 
  21:  END
  22:  GO
 

Now your server explorer should look like the image below.  (Click to see the larger image)

My database projects appear as below (all checked in). (Click to see the larger image)

Next we're going to setup the Data Access Layer (DAL).  Yes, this is somewhat crude, but really, we're only trying to get the basic objects and setup the business entities.  I've used SQL to LINQ for the DAL.  I dragged the three database objects from each "component" database over to the respective *.dbml files.

After that add the testing files to the various mbUnit test projects that have been created.  I create one for each of the objects that will be tested from the database, mainly based on the idea that they will generate entities or objects of some type, and this will keep them fairly organized.  A little bit more about this in part 2.

I'll have the next part up soon.  Until then this will get one setup for the initial tests and core data access layer.

kick it on DotNetKicks.com

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

DI, IoC, and Loose Coupling

Recently a situation were I needed to pull out the dependency injection and inversion of control skills came up again.  The need for loose coupling in so many projects is vital to these patterns.  I was going to start writing an article, but then realized there are some really amazing ones out there.  They point out the reason for Separation of Concerns (SoC), Loose Coupling of UI Components, Controller Independence (free from proprietary UI code).  With that said, here's some links;

Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkList

Posted by: Adron
Posted on: 6/25/2008 at 7:28 AM
Categories: Design Patterns
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed