CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

James Kovacs


Loosen Up: Tame Your Software Dependencies for More Flexible Apps

My latest article just hit the web in the March 2008 issue of MSDN Magazine. Loosen Up: Tame Your Software Dependencies for More Flexible Apps takes you on a journey from a highly-coupled architecture, which we're all familiar with, to gradually more loosely-coupled ones. First stop is the problems inherent in highly-coupled applications. To start solving those problems, I look to dependency inversion and service location. Next stop is poor man's dependency injection and then a simple, hand-rolled inversion of control (IoC) container. From there, I look at the features provided by full-fledged IoC containers and use Castle Windsor as an example, along with some Binsor thrown in for configuration goodness. My goal was to help developers understand the benefits of dependency injection and IoC containers by showing them the problems solved at each stage of the journey.

A big thanks to Howard Dierking, MSDN Magazine editor extraordinaire, for his encouragement and not having an issue with using Windsor for the advanced examples. Thanks to Oren Eini for help debugging a Binsor configuration problem in one of the examples. And an especially big thanks to my spouse and two young sons for their patience while I was writing.

Thanks in advance for reading the article. I welcome your feedback and questions.


Published Mar 13 2008, 10:54 PM by james.kovacs
Filed under: , ,

Comments

Sergio Pereira said:

Having that article in the MSDN magazine is a tremendous step towards making those good practices more common.

# March 14, 2008 1:06 PM

Colin Jack said:

I'm a big fan of DIP and I had a few comments on the article:

* Intro - "Few would disagree that striving for a loosely coupled design is a bad thing.", is this really what you meant?

* Missing Domain - "A simple layering scheme has a UI layer that talks to a service (or business) layer that talks to a repository (or data) layer". Personally as a DDDer I think this is a pretty bad description. Is my "service" layer my business layer? Are my repositories just my data layer? Also repository is primarily a DDD pattern but no mention at all of the domain.

* Coupling - Statements like "the service layer is intimately familiar with and dependent on the repository layer", extracting an interface from a repository and depending on that does not necessarily mean it is much less familiar. What I mean is I have repositories with interfaces that are simple (no details of querying, domain focussed) so extracting interfaces from them all and depending on them makes very little practical difference.

* Mocking - "Poor Error Isolation A failure in a data layer component often causes tests of upper-layer components to fail, too" and "We cannot test the service layer in isolation of the repository layer". This is not true, I would at least expect mention of the class mocking frameworks that are out there (TypeMock), even if you personally don't rate them.

* Service Layer Dependencies - "Supposing that you wanted to add auditing support for the InvoiceRepository, you would be forced to create an AuditingInvoiceRepository or modify InvoiceRepository itself.". In reality you could at that point extract an interface and inject it there and then. In actual fact I can't really see me wanting to audit/log at the repository leve but if I did it would be ridiculously easy to do in this sort of situation, especially as Service layers tend to be very shallow and have few callers. I'd be more worried if a call to an exertnal depdency was way down in some complex call stack in a domain class though.

* Rippling Changes - Statements like "if you need to change the implementation of a lower layer, you're often forced to modify the upper layers as well due to implicit or explicit dependencies that those layers have on the lower layer".

I agree, but how many changes to a repository are not going to in some way affects its interface?

If the repositories are supporting several interfaces (role based/ISP style) then you'd have an advantage, as a change only affects clients of that interface. However seeing an interface called "IInvoiceRepository" makes me think its just an extracted interface from the repository (or defined in advance I guess).

* Layering - I don't necessarily consider the Service layer to be a high level layer just because it calls the "lower" layers, I guess I'd consider the domain layer to be the highest level layer (www.artima.com/.../viewpost.jsp) so I focus more effort on its dependencies.

* Test Data - I'm all for mocking things like repositories but statements like this are not strictly true: "You can create and maintain complex scripts to ensure that the data in the database is correct so that InvoiceRepository returns the expected data for each InvoiceService test.". If I need a persisted Invoice for an integration test then I'll create and save that Invoice in the test setup and I'll ensure that this is done in a transaction thats rolled back at the end of the test.

* Namespace - Small thing, when you say "Simply by adding a new service to the JamesKovacs.IoCArticle.Services" I think you mean "".

Anyway its good to see things like DIP discussed in MSDN Magazine.

# March 15, 2008 12:16 PM

Colin Jack said:

Bah, just re-read it...on the last point I meant:

* Namespace - Small thing, when you say "Simply by adding a new service to the JamesKovacs.IoCArticle.Services" I think you mean "JamesKovacs.IoCArticle.IoCContainer".

# March 15, 2008 12:52 PM

Justice~! said:

James!!

I thought your article was a great introduction to IoC for many people.  I would have liked to have seen a discussion of the Domain in your "typical layered architecture" but otherwise it was a great read.

# March 16, 2008 11:22 PM

james.kovacs said:

@Justice: I'm a big believer in DDD, but I felt that adding a discussion of domain models to the article would detract from the main point - decoupling your software. As it was, I was bumping up against my word count limit. The realities of paper-based publishing...

@Colin: Thanks for the detailed comments.

Intro: I meant that few people would think that a loosely coupled design was bad.

Missing Domain: See above.

Coupling: Whether you extract interfaces is a matter of taste. For services and repositories, I typically do for ease of mocking. For domain classes, I do not until I need the interface. In the article, extracting the interface served to demonstrate dependency inversion - having two classes depend on an abstraction - the interface - rather than on each other. You can definitely extract interfaces opportunistically - especially if you're using ReSharper.

Mocking: I realize that, but didn't want to get into a TypeMock debate.

Service Layer Dependencies: See above on Coupling.

Rippling Changes: I design my software top-down from the UI or service layer - depending on the application. Adding new functionality requires changes to interfaces, implementation classes, and callers. My point was that these techniques provide better isolation against changes.

Layering: I agree. Layering is a simplification, but I didn't have the space for a longer discussion on layering strategies.

Test Data: There are many strategies for integration testing and data consistency. Unfortunately most people only use integration tests without even knowing it - and poor ones at that. My point was to raise awareness that you can unit test without hitting a database or other expensive resource.

Namespace: The namespace is correct. The point was that with convention over configuration using Binsor, you only have to add the code for the service and Binsor will automatically pick it up through the reflective techniques shown. No need to constantly be updating your IoC configuration explicitly.

Thanks again for your comments.

# March 18, 2008 1:05 PM

Colin Jack said:

To be honest I see what your saying on all these points. My worry was just that it all felt like statements of fact, when in fact in each case there was an alternative. I'm not a reader of MSDN magazine though so maybe thats the way of the articles, and as you say there was a limited amount of space.

On the namespace bit, I only mentioned it because the next line was "Even if you're not familiar with Boo, the intent of the code should be clear." but when I did look I was confused. Didn't realize thats the way Binsor works though, pretty cool.

# March 18, 2008 2:21 PM

AdamCox9 said:

Interesting article. This is a really good perspective on highly-coopled code. It is good practice to make code reusable for later on and at an abstract level.

# March 19, 2008 2:08 AM

james.kovacs said:

@Colin: The unwritten assumption by most magazine authors is "this is the way I do it - your mileage may vary". Given limited space, it's hard to cover all possible options. It also makes the article very choppy and disjointed if you try to cover all options IMHO. Imagine this: "We cannot test the service layer in isolation of the repository layer, unless we use TypeMock." Then I would have to get into a tangent about how TypeMock works, why I don't personally use it, compare and contrast mocking frameworks, ... It takes away from my main point of testability and the section becomes a discussion of TypeMock. Personally I have nothing against TypeMock. It's just not my mocking framework of choice. In my experience, if testing something is hard in Rhino Mocks, it means there is a problem in my design. Rhino Mocks acts as my early warning sign that something is amiss. With TypeMock, you can literally mock everything. So I don't see how it can provide you with a barometer of design health. Just my personal opinion.

As for Binsor confusion, maybe I didn't realize how different Binsor and Boo look to someone who has never seen them before. Point taken. :)

# March 21, 2008 3:08 PM

Colin Jack said:

@James

Guess so surely it means you can't trust those sorts of articles?

I can fully understand the "this is the way I do it" argument and why you might not want to mention TypeMock. Having said that I'm not sure I would make statements "We cannot test the service layer in isolation of the repository layer" because its just not factually correct (I do it).

I know what you mean on the barometer, I just find its sometimes not a good measure in application code . I've used Dependency Injection/Service Locator and I can DEFINITELY see the advantages. If you want the services that something like Castle provides then brilliant (especially the facilities). I just don't buy into the idea that the interfaces I introduce are necessarily improving my design. They may be, but not always. I guess I just find I end up with a lot of interface-implementation pairs when I do it blindly in application code and I'm better focusing on targeted decoupling.

# March 23, 2008 5:31 PM

james.kovacs said:

@Colin: I can understand your concern. Unfortunately articles that provide myriad options don't tend to read too well. I personally find you get bogged down in the alternatives and lose the main point of the discussion. I personally come from an academic background and would footnote statements like this. Unfortunately MSDN style guidelines don't permit footnotes. (My first article was heavily footnoted and they all got removed or incorporated into the main body of the text.)

As for interfaces, I understand what you're saying. Interfaces can add clutter to your code. I've avoided most of the clutter via ReSharper's excellent code navigation features. When it only takes a single shortcut key to jump to either the interface or implementing class, interfaces get in the way a lot less.

Thanks again for the feedback!

# April 2, 2008 3:03 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About james.kovacs

James Kovacs is an independent architect, developer, trainer, and jack-of-all-trades, specializing in agile development using the .NET Framework. He is passionate about helping developers create flexible software using test-driven development (TDD), unit testing, object-relational mapping, dependency injection, refactoring, continuous integration, and related techniques. He is a founding member of the Plumbers @ Work podcast, which is syndicated by MSDN Canada Community Radio. His article, “Debug Leaky Apps: Identify And Prevent Memory Leaks In Managed Code”, appeared in the January 2007 issue of MSDN Magazine. James is a Microsoft Most Valuable Professional (MVP) - Solutions Architect and card-carrying member of ALT.NET, a group of software professionals continually looking for more effective ways to develop applications. He received his Masters degree from Harvard University. Check out Devlicio.us!