|
 Sunday, May 25, 2008

Intro to Microsoft Unity - Dependency Injection Container

 

Note: A full solution is supplied at the bottom of this post if you would like to download it and run it.

A couple of days ago Matt wrote about the new Unity Application Block. The Unity MSDN article describes Unity as:

The Unity Application Block (Unity) is a lightweight, extensible dependency injection container. It facilitates building loosely coupled applications and provides developers with the following advantages:

  • Simplified object creation, especially for hierarchical object structures and dependencies
  • Abstraction of requirements; this allows developers to specify dependencies at run time or in configuration and simplify management of crosscutting concerns
  • Increased flexibility by deferring component configuration to the container
  • Service location capability; this allows clients to store or cache the container

Designing a software system architecture with loosely coupled components makes life easier in the long run. A few of the benefits of loose coupling are : maximizing testability, modularizing components, and increase the maintainability of the code.

This is a simple introduction into Unity that exemplifies the simplicity of the container setup. I will cover two options for type registration:

  1. Manual Method based type Registration
  2. Configuration file (XML Based) type Registration

 

The Example Application

The application that is included at the bottom of this post is visualized via the class diagram below. This simple application utilizes very simple implementations of the repository, mapper, domain model, data transfer object (DTO) and service layer patterns for example purposes.

The application follows a very simple flow as shown below:

image

 

The console application calls into the Service layer which calls into the repository to get the data which calls into the DB. A domain object is created from the Repository call, which is passed up to the service layer. The Service layer returns a DTO via the DTO Mapper to the parent caller (the console app) and then the console app displays the customer name via a write line call.

None of these layers have any inter-dependent dependencies coded inside of them. I'm using constructor injection to inject dependencies into the calling object.

Once unity is set up, it will find the dependencies and supply them to the program at runtime. Therefore, if I need a ICustomerRepository for the service layer to work properly, Unity will give the Service layer a CustomerRepository instance. Since CustomerRepository inherits from ICustomerRepository Unity is able to make this link (once you've set it up) and supply the proper instance.

Class Diagram

image

 

The Setup & Code

The easiest way to see HOW Unity works is to get into the code. My recommendation is to download the sample below, fire it up in Visual Studio and set some break points to see how the code is interacting. Seeing is believing!

Before Unity can supply your application types at runtime, you have to tell Unity WHAT you want it to supply and where to find it. This can be done multiple ways as described here. Today we will go over manual configuration inside of the console app, and xml configuration.

Manual Configuration

image

The manual configuration that I've utilized here utilizes the fluent interface of the container.

Explanation of code: Here we are telling Unity to register a type. We're saying "If someone requests ICustomerRepository, give them an instance of CustomerRepository. If someone requests ICustomerDTOMapper, then give them an instance of CustomerDTOMapper. ..." and so on.

 

 

Using the Container From Manual Configuration

After you've set up the types of objects the container should resolve, you can then ask the container for a instance of "ICustomerService" and then invoke a method call on it. At this very point in time Unity will give you the CustomerService, and then when the customer service needs a repository Unity will then give it a instance of CustomerRepository, etc. At this point in time, everything is mapped for you behind the scenes. The only thing you have to do is ask for the first object and Unity will walk the dependency graph and fill in the blanks for you (if as long as you've given Unity the proper types it needs).

Here's how to do this in the code:

image

 

 

 

XML Configuration

XML configuration utilizes an external XML file (app.config/web.config) to create its dependency graph. This allows for a lot more freedom in what you would like to do with your app. If you're not happy with a certain version of "ICustomerRepository" you can create a new one, drop the DLL in the bin folder and change this config file to point to the new one and you're done. No recompiling!

In this implementation I'm using the app.config file because this is a Console App for example purposes. The full schema for XML configuration can be found here on the MSDN.

To utilize the XML configuration you'll need to utilize a custom config section. You can do this by placing this code into your config section of your app.config file:

image

Next, you'll need to add the container and type definition as shown below (this is just a snippet, full code is included at the bottom of the post):

image

The container gets its types from the config file at runtime.

Each type is declared in the config file as the "type" of object to find and the "mapTo" defines which object to return when the "type" is requested.

The type definitions are declared as type, assembly.

 

 

 

 

 

 

Using the Container From XML Configuration

To force Unity to use the XML Configuration you have to perform few extra set up steps in the application code as shown below. Essentially you're telling Unity that it's configuration/mappings are stored in a config file. The config section configures the container for you, as shown below.

image

To have Unity resolve an instance, its the same as the manual configuration option above. Here is the same image from above that displays how to do this:

image

 

 

 

 

Conclusion

Overall, using Unity as quite simple for this example. The docs on MSDN were pretty good, however I didn't really like the examples that were contained with the download because they did not show you how to utilize XML configuration as I wanted to. It didn't take but a few minutes to figure out what I needed to do. I think Unity is a decent solution at this time. I plan to investigate further into the depths of Unity to see if it may possibly be an alternative for my favorite container tool, Windsor Container.

 

Download The Code For This Post

FooTheory.UnityExample.zip (~477K)

#    Comments [2] |
 Sunday, March 23, 2008

Beginner Test Driven Development Habits

Having worked on quite a few teams where I've been the lead responsible for helping implement TDD or been an Agile Coach - I've seen a group of habits develop when teams first start utilizing TDD. These are ...

 

1. No test isolation

All functionality that is being tested is in one test. Tests are heavily over specified.

How to fix: Spend some time pairing with the developers that are having the issue. Help explain why we want to break tests apart into smaller units, aka: "UNIT" tests. Let them know that we do not want to test the entire class in one unit test. Just because it can be done doesn't mean it should be done. Ya know, I COULD drive into oncoming traffic, but its just not a good idea. :)

 

2. Failure to recognize the TDD Mantra tddcycle

Most  new TDD'rs will go from Red to Green to - I'm done! Nope. I'm sorry guys, we have one more in that list - Refactor. Let's say it together.  Red/Green/ReFactor, Red/Green/ReFactor :)

How To Fix: Help the developers realize that we want to refactor for a reason. We have a passing test, we know what to expect from our results. Now lets clean up our code, maybe introduce some interfaces, change some variable names, introduce some fields, extract some methods, etc. Doing this allows us to clean up the code as well as have the confidence that our changes did not muck up the expected result. Run the unit tests after you refactor. If it breaks, oops, lets go figure out WHY it broke. We caught the error early, its a lot cheaper now. :)

 

3. The previous lends itself to Insufficient Test Coverage/TDD is my new Debugger

The developers usually will do enough to get the test passing and then move onto the next task. They think of TDD as a new debugger.

How To Fix: Sit down with the developers that have this issue and explain: Just because we can now unit test a method/object and step through it with a debugger doesn't mean that this is the new debugger.  That's not the point. Just because the test passes doesn't mean we're done. Just because your method passes if you pass a valid object into it doesn't mean that its fully tested. What happens if I pass a null object into it? What happens if I pass a new'd up object with nothing instantiated? Have those instances been tested? Have we tested that our objects are interacting as we expect them to? Do we know if the Logger got called? How do we know if we didn't test it?  That its the classic question: How do we know it works, if we don't have a test to prove it?

 

4. No concept of separation of concerns or IoC/dependency injection.

This is not a big deal and I expect it of most new TDD converts. Usually while learning TDD the first few tests do not need DI/IoC, but this is something that will help in the future and will need to be understood to really grasp. This really comes into play when we start separating our concerns and breaking dependencies between objects. The refactoring that takes place here can really get deep into DI/IoC sometimes.

How To Fix: Give them a great intro into interfaces and how they're used. Show them great articles on DI/IoC written by Martin Fowler, Jeremy D. Miller, Ayende, and have them join certain mailing lists such as altdotnet to join in/read the discussions. On that list alone, DI/IoC discussions occur on a daily basis.

5. TDD Complaints

I've seen complaints such as:

    1. It takes too long to write the tests
    2. I write more test code than real code.
    3. The tests are harder to write than the real code.
    4. How is this going to help me get my project done? I can just hit F5 and test it and I can tell if it works or not with my own eyes.
    5. Who cares if it passes a unit test, I'm the only person who works on this project.

How To Fix: This is one of those habits I've seen in every place I've coached. These are classic examples of someone who hasn't "seen the light" of TDD yet. In my experience, the easiest way to help them see the light is to pair with with them while writing unit tests. They will instantly see why the unit tests help them and the team. Every single time I do this I help the TDD newcomer realize that by writing this test they've exposed X bugs that they didn't think about before. It usually goes like this: "Ok, that test passes, what would happen if an empty string was passed into this? Would the DB accept an empty string?" Them: "Oh... good point, I didn't think of that." Instantly lights start turning on. Another thing that works great to help developers see the light is to ensure that you're utilizing Continuous Integration such as CCNET, or TeamCity. Have them create a unit test for a section of code. Check it in. Watch it build and watch unit tests pass. . Then have them change the code (the code which is under test) and ensure it returns a different result. Maybe it returned a user's name, such as "bob", now have it return the users name with some characters appended to the end of it, such as "bob123". Have them check it in, watch the build fail because the unit test failed. Explaining to them that this helps catch errors before the product is live is crucial. Once they have the "Ohhh!! I get it now moment", they won't want to stop writing tests.

#    Comments [0] |
 Tuesday, February 19, 2008

A FREE Remote-Collab Tool From Microsoft? (And a list of others)

sharedviewBeta Microsofts SharedView has been around for awhile now and at this point is in Beta. Scott Hanselborg posted about the tool just recently and I finally gave it a spin yesterday with another coworker.

sharedviewBeta-2

I was very impressed with the smoothness of the application and I really loved how each user was given their own mouse cursor with their name attached. They were not controlling the session, but they were allowed to move their cursor around. This is very nice to have because you can see what everyone is looking at when they're talking. Very nice.

I know there are many other tools out there, but I think this one might be a one for Development teams to embrace. I've used RealVNC before for Pair Programming sessions at previous clients, but sometimes I found it choppy and the display was horrendous at times (depending on network latency). I didn’t encounter these issues with SharedView at all.

If you're looking for a new remote tool, or maybe you're just trying to show Mom how to burn a CD of photos, check out SharedView.

If you realize SharedView is not for you, check out some of these other collaboration Tools (some free, some not-so-free):

g2a_logo_small LogmeIn
GoToMyPc  yugma
 GoToMeeting  webex_logo
 RealVnc CoPilot
#    Comments [0] |
 Friday, November 30, 2007

Cruise Control.NET & Visual Source Safe - SS.EXE Hangs

I recently help set up a CI (Continuous Integration) environment using CC.NET (Cruise Control.NET) at a client that I'm at. We're in the process of implementing TFS (Team Foundation Server) but until some red tape is cleared we're still stuck on VSS (Visual Source Safe).

While setting up the environment we were given a test VSS account to work with until everything worked as expected. Well the user they gave me had a blank password.

Example -

User: ccnet Pass: (no password)

The visual source safe source control block looked like this:

<sourcecontrol type="vss" autoGetSource="true" applyLabel="true">
   <executable>C:\Program Files\Microsoft Visual Studio\VSS\win32\SS.EXE</executable>
   <project>$/CCNET</project>
   <username>ccnet</username>
   <password> </password>
   <ssdir>c:\repos\</ssdir>
   <workingDirectory>c:\myBuild</workingDirectory>
   <culture>en-us</culture>
   <cleanCopy>false</cleanCopy>
</sourcecontrol>

When I fired up the CC.NET Service, everything started off fine. The project said "Checking For Modifications" and then it HUNG there, forever. It never stopped. I had to stop the service and then kill SS.exe (source safes process).

Solution

The reason this happened is because of this line:

   <password> </password>

The password was left as " ". It was a space. If I fired up VSS and typed in ccnet and put a space into the password, it would let me in, no problem. But if I did that with CC.NET SS.EXE would hang.

Pretty much, here's what's happening - Source Safe is firing up and its trying to log in and its giving an invalid password. SS.EXE is trying to raise a dialog box, but its running under the context of the Cruise Control.NET service, therefore it cannot open that dialog box.

I changed the password field to this:

   <password></password>

and then it worked flawlessly.

 

Simple solution to a simple mistake. :)

#    Comments [0] |
 Sunday, November 18, 2007

Frustrating MS Test Issue - blah blah blah is not trusted

I'm not going to lie, I'm a NUnit guy. I've used it for years. But just recently I've decided to start using MSTest. I run Team Suite and I've been using it for some basic integration and functional tests, but not full on TDD. Well this weekend I embarked on a task that utilizes full on TDD and I decided to make the jump and try to do it with MS Test.

So the first thing I had to do was reference and import Rhino Mocks. I then ran the test real quick (I had a test that did not depend on mocks yet) to make sure nothing in the import broke it (it shouldn't, but hey, I'm ADD when it comes to this TDD business). To my utter amazement, something broke. I was seeing red.

This was the beautiful error:

Microsoft.VisualStudio.TestTools.TestManagement.ExecutionException: Test Run deployment issue: The location of the file or directory '(path omitted)\main\Source\SharedBinaries\Rhino.Mocks.dll' is not trusted.

WTF? It's on my local machine. It's not a file share, hell, its even included in my project in my SharedBinaries folder. WTF MAN!?

After some looking around, I was able to figure it out.

If you download a DLL from the Internet, or get it in an email or where ever and you saved it to your disk (including a DLL in a zip too) it has some extra info attached to it called an "AES" file. (see my reference below for more info)...

To fix this annoying issue, go to the DLL, right click and then click "Unblock". See the screen shot below. Once that is done, your test will work.

unblockdll

 

Source: MSDN Forums

#    Comments [3] |
 Wednesday, November 14, 2007

Vitamin or Prescription?

As developers we're constantly inundated with requests like this ....

  • Can you add a button that does does ________
  • On this screen _________ I need to have a chart of ________ displaying data ...
  • I need a report that shows me _________
  • Can we add _______ to this page?
  • It shouldn't be too hard to add this, its just a field on the screen .... (then they explain what its supposed to do)...

(classic scope creep)

Prioritization

The order in which a developer prioritizes items in their "todo" list is often determined by the urgency placed on them by their direct managers (or higher ups). More often than not we find a high level executive or decision maker wants a feature implemented because they "think" it will add value to the product. Again, more often than not, the executives theory of how this feature is a viable request has no data to back it up. Therefore a feature is implemented with no verification that its a needed or requested feature. Please remember, this doesn't always fall upon the shoulders of the decision makers... as developers we're enamored with making things sparkly and shiny. If we think of a cool new "hot key" that we can add to our app, we'll do it, even though it might take four hours to implement, we're confident it will be the feature that saves the world.

Uhhhhh, Nope. Afraid not McFly.

 

What's the root of the issue?

We need to ask ourselves a simple question....

Question: Is this feature a vitamin or is it a prescription?

Before we can answer this... lets look at some simple definitions...

Vitamin - A supplement that helps you, its good for you, its nice to have, but its not required.

Prescription - Medicine that helps you. Its required, it helps you survive.

 

Answer: It depends. (the classic developer answer... well... it depends... :)   )

 

The Process of the Request

When an feature request comes in you need to ask (as well as the client who requested it) ...

Is this feature/request a Vitamin or a Prescription?

This is the same as asking...

Is this feature request a "nice to have" or a "requirement to survive"?

This is going to determine if the request is worth putting into the system immediately. If you have 10 tasks, ask this question ten times and  you might some up with something that looks like this:

(This mimics a fake Online Order Management system - for example purposes)

VitaminsPerscriptions

As you can see, we see that everything on the LEFT is a requirement for the system "requirement to survive" (prescription). Everything on the right is a "nice to have" (vitamin).

We may need graphs of data, but we don't need 3-d graphs. We may need Web Access to the Order Management System, but we don't need a Silverlight implementation to get this project to work. It would be "nice to have" a Silverlight implementation, but its not required.

Conclusion

The next time you're asked to implement a feature, ask yourself...

Is this a vitamin or a prescription? Then put it in that bucket. Then, once that's figured out, go into the prescription bucket and prioritize those upon business requirements. Then, when you've taken all of your prescriptions (all of those items are complete), ask yourself if the "vitamins" are going to add value to the project. if they are, then ask that question again (is this a vitamin or a prescription).

This ultimately comes down to an agile type of development process. We should only be implementing the things that add value and that are required for the app to serve its purpose. Most of the time a lot of these "Vitamins" will never make it into the system because its just not cost effective or necessary. Eventually some vitamins will make it into the system and sometimes its these Vitamins that make your system a step above the other systems, but this cannot be established until you've taken all of your prescriptions. If you're sick and bed-ridden, you can't take muscle vitamin supplements to get muscles big. You have to take the prescription to get well, then you can take the muscle supplements to get muscular.

Next time you get ready to implement a feature/request - ask yourself ...

Is this a Vitamin, or a Prescription?

#    Comments [1] |