RSS CodeBetter.Com

http://codebetter.com/blogs/

Wednesday February 13th, 2008

6.0

Mocks are a code smell

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

                        

Now that the title has grabbed your attention no I don't really think that mocks are a code smell as a rule but I do think they are grossly overused and there are other ways of dealing with the same issues which should also be considered when designing  systems.

 

While not purely, I guess some may put me in the classicist camp ..

 

Ian Cooper has a great post up Classicist vs Mockist Test Driven Development. In the comments I have stated that I personally try to architect around a need for mocks in many cases and figured it a bit long to explain how in comments ...

 

Let me say before I continue that these are not new ideas.

 

Its not by accident that when you read old OOA/D books that they seem to use the concepts of "calling a method" on an object and "messaging an object" interchangeably. We can use this similarity to our advantage in our design ... While the former requires me to mock the thing I am calling (you can't call a method on a non-existent object) the latter if I introduce a dispatcher does not need to have an object that it is targeting. As we will also see this method also tends to remove  move the need for dependency injection.

 

Naive Example

I never understand things unless they are shown to me in code so let's imagine the canonical example of an ATM with a controller and various services it interacts with. This makes a great example as it has a few services that it would orchestrate (generally 1-2 per test). These scenarios are also almost exclusively request/response which is very common in most of our object interactions (especially with services) making a 1-way call an asynchronous message is rather trivial to do and is a no-brainer for nearly 'ility we could possibly discuss.

 

Let's start with the first stage of coming to an ATM machine. I put in my card and then expect it to ask me to authenticate (yes it usually asks me for a pin but maybe its a fancy-shiny-new-atm that uses biometrics so we will assume there are multiple interchangeable mechanisms).

 

In a mocking scenario we would have a few tests here using mocks. The first test would be in the ICardReaderService implementation where we would mock the HAL (Hardware Abstraction Layer) and insure that our expectation of it receiving a message and appropriately calling a mock of our ATMController is met.

Further we would have tests to insure our expectations of the controller properly calling the IAuthenticationService when it is notified that a card has been placed in the ATM. note that we could have the services call each other directly but generally a controller is a preferred pattern.

Have you noticed in visualizing these tests that almost all of our code is setting up mocks and expectations for our tests? What if we were to model this so instead of being direct method calls all of these items were done through messages and handled by Finite State Machines?

 

First we will need some concept of what exactly a message is. I am providing a naive example for the sake of this post.

public interface IMessage {     
    IMessageConsumer Sender { get ; }     
}   
   
public interface IBidirectionalMessage : IMessage  
{    
     IMessageConsumer Sender { get; }
     void ReplyWith(IMessage Reply);  
}  

Second we will need some way of having our messages sent between the objects, in a real system we would like use a message dispatcher that supports all sorts of neat and fun things but in testing we don't actually want them dispatched (we only care that they actually were created its for our integration tests to insure that they actually get dispatched appropriately) so we can come up with a pretty dumb implementation of our dispatcher ...

public interface IMessagePublisher   
{
      void Publish(IMessage message);   
}   


public class FakeMessagePublisher : IMessagePublisher   
{
     private Queue messages;
     public FakeMessagePublisher()
     {
         messages = new Queue();
     }
     public void Publish(IMessage message)
     {
         messages.Enqueue(message);
     }
     public IEnumerable AllMessages()
     {
         while (messages.Count > 0) {
             yield return messages.Dequeue();
         }
     }   
}   
 

To make things complete we will also need to bring in our IMessageConsumer interface which is used above. Non-naive versions of these interfaces and the dispatcher could probably have books written about them so please forgive the naivity of the examples.
If you want to take a look at a nice implementation of similar ideas take a look at nServiceBus though if you are working on smaller applications you may find this to be a rather large dependency, a simple stripped down in-process dispatcher is a very easy piece of code to write.

public interface IMessageConsumer  
{
     void ConsumeMessage(IMessage Message);     bool CanConsume();  
}  

Then we will create a simple static locator that everything can use to find the current messaging subsystem (yes DI is a good thing here but when we only have 1 thing to inject do we care?).

 

Once we have this class we can start working on our actual system and write some tests.

 

So our first test identified was to insure that the CardReaderService actually notifies the IATMController that a card has been placed in the reader.  We will need a message for it to use to do the notification.

class CardInsertedMessage   
{     
     public readonly string CardHolder;
     public readonly string CardNumber;

     public CardInsertedMessage(string cardHolder, string cardNumber)
     {
         CardNumber = cardNumber;
         CardHolder = cardHolder;
     }   
}  

Now we can write our first test using a Fake for the HAL (which btw is one place I always agree with using a fake).

[Test]  
public void Reader_ShouldSendCardInsertedMessage_When_CardInserted()  
{
     ICardReaderHAL FakeHAL = new FakeCardReaderHAL();
     IATMCardReaderService CardReader = new ATMCardReaderService(FakeHAL);
     FakeHAL.InsertCard("1111 1111 1111 1111", "Greg Young");
     List messages = new List(FakeMessagePublisher.AllMessages());
     Assert.AreEqual(1, messages.Count);
     Assert.IsType(messages[0]);
     CardInsertedMessage message = (CardInsertedMessage) message[0];
     Assert.AreEqual("Greg Young", message.CardHolder);
     Assert.AreEqual("1111111111111111", message.CardNumber);  
}  

Notice that we don't care here about the handling of the message? We only care that the message was created! This is very much the way that mocking works no? Our expectation is not that some other object was called but simply that the message was raised from this object. We will later test in integration tests that things do actually happen.

One thing I will also point out is that we don't have any mock setup for expectations that could deviate from how our actual objects work.

So now let's go to our next test, that the controller properly handles the fact that a card was inserted and asks the authentication service to authenticate us and that once it sends the request it is capable of receiving the response.

public void Controller_ShouldRequestAuthentication_When_CardInsertedMessageReceived()  
{
     ATMController Controller = New.ATMController.InState(ATMController.States.AwaitingCard);
     CardInsertedMessage InsertedMessage = new CardInsertedMessage("Greg Young", "11111111111111");
     controller.ConsumeMessage(InsertedMessage);
     List messages = new List(FakeMessagePublisher.AllMessages());
     Assert.AreEqual(1, messages.Count);
     Assert.IsType(messages[0]);
     Assert.AreEqual(Controller, request.Sender);
     Assert.IsTrue(Controller.CanAccept());  
}  

Dual Expectations?

In our Controller_ShouldRequestAuthentication_When_CardInsertedMessageReceived test the astute reader may hold an objection to the test actually testing two expectations. The first expectation being that the controller properly generated a message and the second expectation being that the controller was able to receive the expect response to the message. To be honest I am on the fence with this one, on one hand the expectations are very closely linked to each other, on the other hand they are very different expectations. I personally tend to put the two expectations into one test because if either fails it still gets me close enough to the point where things are failing that I can quickly solve the problem but mileage may vary for others. If people find it to be more correct, here are the seperated versions of the tests.

public void Controller_ShouldRequestAuthentication_When_CardInsertedMessageReceived()  
{
     ATMController Controller = New.ATMController.InState(ATMController.States.AwaitingCard);
     CardInsertedMessage InsertedMessage = new CardInsertedMessage("Greg Young", "11111111111111");
     controller.ConsumeMessage(InsertedMessage);
     List messages = new List(FakeMessageDispatcher.AllMessages());
     Assert.AreEqual(1, messages.Count);
     Assert.IsType(messages[0]);
     Assert.AreEqual(Controller, request.Sender);  
}   

public void Controller_ExpectsAuthenticationResponse_After_SendingAuthenticationRequest()  
{
     ATMController Controller = new ATMController();
     CardInsertedMessage InsertedMessage = new CardInsertedMessage("Greg Young", "11111111111111");
     controller.ConsumeMessage(InsertedMessage);
     Assert.IsTrue(Controller.CanAccept());  
}  

The tests for the IAuthenticationService and the handling of the return message to the controller are almost identical to these tests. Due to these similarities I am going to skip ahead to the final part of the process; a naive example of giving the customer money. As before we will need a message

class DispenseMoneyMessage  
{
     public readonly decimal Amount;
     public DispenseMoneyMessage(decimal amount)
     {         Amount = amount;
     }  
}

Now the part that is different with our pretend ATM is that the CashHopperService has a state in it of how much money is left in the machine. So we can write a test for how much money is in the ATM.

Now we can implement our test.

public void CashHopperService_ShouldUpdateAmountOfCash_WhenItDispensesCash()  
{
     FakeHopperHAL FakeHAL = new FakeHopperHAL();
     CashHopperService hopper = new CashHopperService(FakeHAL);
     FakeHAL.AddCash(5000.00m);
     hopper.ConsumeMessage(new DispenseCashMessage(500.00m));
     Assert.IsEmpty(FakeMessagePublisher.AllMessages());
     Assert.IsEqual(4500.00, hopper.CashAvailable);  
}  

The Testing Threesome

I said before I that I skipped many of the interactions because the were uninteresting. This is because there are EXACTLY THREE TYPES OF TESTS WE WILL EVER WRITE. In the examples above we covered all three.

  • Message-Is-Produced-When-An-External-Event-Occurs
  • Message-Produced-When-A-Message-Is-Consumed
  • State-Is-Transitioned-When-A-Message-Is-Consumed

That's it! Given that we only have these types of tests and all of them are extremely similar we can quite easily come through and use my other favorite programming threesome Reduce, Recycle, Reuse!

It doesn't take much imagination to see something like this in our not so distant future.

public void Controller_ShouldRequestAuthentication_When_CardInsertedMessageReceived()  
{
    When.Consumer<ATMController>().InState(ATMController.States.AwaitingCard)).
         Receives(Fakes.CardInsertedMessage).
         Expect<AuthenticationRequest>();
}

With an API like this why are we even naming our tests?!

We could even take this very quickly to a metadata based method of testing. There are MANY well known ways of easily testing state machines (and generating them from metadata descriptions of them which might be in a DSL).

 

Dependency Eradication

There has been ALOT of talk lately about dependency injection and all of the issues that can go along with it. Of late there was one particular thread on the altdotnet list AMC: Changes the way we think which is of interest.

Village Wisdom:

-          We use constructor dependency injection (and sometimes properties) because it’s important to expose your dependencies…

-          … so that callers who aren’t using IoC (ahem  tests) can easily work with the test in isolation by using mocks and not having to involve an IoC container…

-          … and so it behooves us to keep the number of dependencies in a class down to a minimum to keep tests from getting too complicated…

-          … which also forces us to battle between too-many-dependencies and dependencies-that-do-too-much.

Basically, it seems like we make a lot of choices based on writing tests and the fact that our tests don’t use IoC (to keep things less complicated, we tell ourselves).

Well I am going to disagree strongly with #1. I think an object is much better to have NO dependencies than to expose them. In the canonical example of sending an email why does the object need to even care that there is an email service which actually sends the email?

"Changing the way we think..." is what's really needed here ... walk away from doing EVERYTHING as direct object interations and move to decoupling through messaging!

Or to comment to Roy Osherove's post who ever said testability has to lead to dependency injection?! Given these posts lead to type mock but ...

 

Others have even gone so far as to make the fallacious statement that Domain Driven Design is not possible without DI and AOP but this deserves a long post on its own.

 

 

This is not to say that messaging is built on a system of Love and Rainbows.

 

Trouble in Paradise?

Are you thinking to yourself

'sure this is great in the success cases but what about the failures?'

Well umm yeah it can be a problem and a quick blog post is definitely not the place to address all of these issues. The big issue here is that since we are using messages for our interactions we may or may not have a call stack. Without a call stack exceptions as they exist in the framework well don't work.

There are a few cases that can be problematic with exceptions. The first is when dealing with a bi-directional message. When we send a request the processor gets an exception and fails. The processor (or in some implementations the dispatcher can) package up an exception message with the details of the message and return the results instead of the success response (a common pattern for this might also be to make the response support being a failure and including the exception).

The next case which is particularly nasty is when you are dealing with a one way message. What happens when the thing processing it on the other side fails? Depending on the situation this may be very problematic because if the message is say a delta message there is a real possibility that the component will not be able to process any more messages (possibly inconsistent state).

The last case that can be extremely problematic is when you have a request/response based message and either your message doesn't actually get routed anywhere or whatever was processing it on the other side died. Without someway of gracefully handling this your object will sit in its waiting on response state forever.

 

This difference in thinking of course does open us up to being able to distribute our objects fairly transparently to multiple processes and/or machines

 

Balancing the Scale

Since NOTHING has a reference to anything except for the dispatcher and our messages as objects are easily serializable we can quite easily move them out of our own process even to a processor running on a wrist-watch in Russia if we liked without our system knowing or really caring that we did that.

This does not bypass the old RPC should not be transparent thought as you still should be THINKING about the overhead involved.

 

The second large scalability gain is that we can quite easily multi-thread. Our threading boundaries are not decided within our code but in how we dispatch our messages.

 

Basically while a messaging based system may start out running a very simple model you can scale it by changing how you dispatch and process messages.

 

Conclusion

If there is one thing to quote from here it is this:

Messaging is not for EVERYWHERE but its a tool that should be in your toolkit. Each side has its pros and cons but right now everyone seems so focused on things like IOC containers and mocking frameworks that they have completely forgotten that its sometimes best to not have a dependency at all.

I personally like to keep a rule that I call methods inside of an aggregate root but as soon as I leave the aggregate root I use a message.

 

 

 

 

I know this has been a long read; but I am barely even scratching the surface of everything I want to say on this subject. I would love to go into further discussions like

 

"How do you actually implement that dispatcher thing?"

"How do you make that dispatcher thing work with multiple machines?"

"You mean somebody already implemented that dispatcher thing for me?"

"How do we make that fluent interface we saw"

"How do messaging and Domain Driven Design interact"

"Messaging, Pipelines, and Interception"

"What is the pi-calculus and why do I care?"

 

But even writing this takes quite a bit. What if any of those continuations sound good?

4.2

Another Handy Shortcut Combination (Shift + F10)

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

I might be a little late on this one, but I just learned a new shortcut that will definitely save me time when I am working in my VM on my mac. I love to use the keyboard. And when I use my natural keyboard it is fairly easy to access context menus (right click) by using the context menu key on the keyboard. My MacBook does not have such a key. This meant that up until yesterday (when I learned the shortcut) I had to have a mouse plugged in any time I wanted to access the context menu.

Shift-F10 is actually a keyboard shortcut that accomplishes the exact same thing as the context menu key / right click.

Thanks to Jay Smith for pointing this out for me.

 

6.0

Public Speaking Anti Patterns

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

Public  Speaking Anti-Patterns

Last week fellow CodeBetter blogger Kyle Baley wrote a blog topic called “Presentation Topics” (http://codebetter.com/blogs/kyle.baley/archive/2008/02/08/presentation-tips.aspx)

He did a good job of presenting a number of useful tips for speaking.  Well I am going take a shot here and point out a few bad habits that some of my fellow presenters have developed over the years that do nothing but piss me off because they should know better.

1.       SHUT UP AND LISTEN – I cannot tell you how many speakers I have seen that interrupt questions from the audience. 

       If you are going to allow questions in your sessions you need to shut up, listen, and let the person asking the question finish.  Don’t  interrupt!!!!  Don’t ASSume you know what the rest of the question is.

 

2.       REPEAT THE QUESTION – Whenever a question is asked:  Repeat it out loud. That dude in the back probably didn’t hear the question from the front row. 

       You need to be courteous to your audience and let them know what is happening.

 

3.       MAKE SURE YOU KNOW WHAT THE QUESTION IS -  If you don’t know what the question means or don’t understand it here’s a tip: Say this to the questioner: “Can you say that another way?”  This will help you understand what they are really asking.

 

4.       LESS IS MORE – If you have 60 slides for a 60 minute session you are not going to get to the end.  

 

5.       DON’T WRITE A BOOK – Slides are supposed to be outlines not dissertations. See #4.

 

6.       DON’T UPGRADE YOUR MACHINE - The week/day/hour/minute before your session is not the time to install that new alpha, beta, omega version.  

       Just because that beta is ready doesn’t mean your session is.  If you do this you deserve to have your shit break.

 

7.       DON’T MAKE EXCUSES - If stuff breaks in your session it’s your fault. You didn’t prepare properly. See #7 about upgrades.

 

8.       DO THE JULIA CHILD – Ever watch cooking shows. They always have one that’s done and ready to serve. You should have a copy of your sample code that runs perfectly.

      If your demo breaks you can always go to that copy.

 

9.       ARRIVE EARLY, SIT IN BACK – When you give a session you need to arrive early and check the lighting, sound, projection, etc in the room. All rooms are not created equally.  

     Check your colors, fonts, etc. Set up your machine with code on it and go sit in the last row. Can you read it? If not adjust accordingly.

 

10.   ONE FOR THE AGILE DUDES- You need to have an outline of what you are going cover.  In specifically titled sessions you need to have it planned and not do ad-hoc sessions.  

 

11.   FINISH ON TIME - At the last conference I attended there were a number of sessions that ran way long.  Don’t do this!!!  It’s RUDE! It’s RUDE to the attendee,

      RUDE to the conference coordinators and the RUDE to the next speaker.

 

12.   AND FINALLY ----- Don’t Ever Ask: “How much time do we have left” – This is my BIGGEST pet peave.  You might think it’s cute. It’s not… If you ask this in a session you are a total complete idiot. 

      If you want the real  answer to this question here it is:  “Here Mr./Ms./Mrs. speaker  let me look in the conference brochure and see what time the session with YOUR FREAKING NAME  

      on it is supposed to start and end.”  Asking this question is unprofessional and silly.  Get the point?

 

I hope this lists helps you as a speaker and attendee.

 

 

crossposted from blog.dashpoint.com

Tuesday February 12th, 2008

2.2

Alt.Net Seattle

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

Unfortunately I was at lunch so Dave beat me to it but  Registration is open ... only about 100 seats first come first serve and there are some amazing people coming already. There will be some awesome future looking discussions put up including I think some about spec#!

 
Hope to see you there.

 

3.8

I like this

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

I don't care if you're excited about the new MVC framework or if you're one of those people that are desensitized to the pain of WebForms, the fact that this graphic was in a blog post from ScottGu has to make any ALT.NET heart go pitter-patter:

 

All I'm excited about is the very idea that a Microsoft produced tool explicitly encourages unit testing (and acknowledges the existence of OSS tooling!). 

4.2

You broke the build!

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

Stumbled across this today in my search for build images. Perhaps not as subtle as Bil Simser's broken build handout but I believe people will get the message:

image

Don't forget to check out Agnes's friends at www.buildsonmymachine.com and www.wheresthebuild.com.

Monday February 11th, 2008

5.2

Pain-Driven Development: uncovering the motivation

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

To subscribe to my feed, add the following Url:  http://feeds.feedburner.com/jeffreypalermo.

Kevin Hurwitz and I talk at length about pain-driven development.  For those who don't know, Kevin is my lead architect and .Net Practice Manager at Headspring Systems, and we've worked together since mid-2006.  We both have the same mindset about PDD.  If we are motivated to put time into changing some aspect of the software, it has to be related to one or more areas of pain.  For instance, if the build is taking too long, we might look for ways to speed up the build.  If a particular interface has too many responsibilities, it may annoy us enough to break it up. 

Now, we do have a low threshold for pain.  We expect our software configuration management to be frictionless and go completely smoothly, including automatic database migrations; therefore, pain points that pop up are obvious, and we tend to kill the pain by fixing the source very quickly.

The point of this post is to think of pain reduction as ROI.  In business, we might spend money on software for some expected return on investment.  While working with the software, we also have returns on investment, but in the form of productivity.  Pain kills productivity.  Over time, we might learn to live with pain through parts of the process by taking a constant does of <insert painkiller here/>, but that only hides the pain.  It doesn't cure it. 

Pain-driven development is a mindset where developers react intensely to pain and solve it so that it goes away once and for all.  PDD practitioners don't just cover up the pain.  We eradicate it.  PDD leads to a completely frictionless software process that is a joy to experience.

Note:  I'm not advocating another XDD acronym, but I wanted to share our mindset.

5.5

First make it right. Then make it fast.

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

To subscribe to my feed, add the following Url:  http://feeds.feedburner.com/jeffreypalermo.

I spent the first part of my career on the side of the fence where I want to make it fast first.  In fact, I wanted to keep it fast all the way through.

I'm talking about software.  Performance optimization.  Speed. 

There was a time when every time I concatenated a string I weighed the theoretical pros and cons of using the plus operator vs StringBuilder vs. string.Format().  I even measured differences.  I've now come to the point where I realize that PDD (pain-driven development) is the real decision-maker.  It's no longer worth my time to think about what concatenation method might be faster.  Compared to a single database call, the speed different is irrelevant.

Point:  A well-designed application can be tuned at any conceivable place after it's working correctly.  An application that has "performance optimizations" coded into it from the start has less flexibility for the inevitable bottleneck that surfaces unexpectedly.

Point:  I will not guess at what part of my code will be a bottleneck unless I have past experience in the exact same scenario.  Rather, I will lead the team to create correct software that _appears_ to be fast enough throughout the project.  At an agreed-upon time we'll profile (with the appropriate tools - yes, I mean _measure_) the application and find any bottlenecks that are not acceptable for production.  Then, with real data in hand, we'll tune exactly the right parts of the application.  We will not guess before measuring.  After measuring, guessing is not necessary.

Point:  First make it right.  Then make it fast.

In general, out of process calls are performance bottlenecks, not in-process logic.  Either way, measuring tells the truth, not guessing.

5.2

NAnt 0.86 beta 1 nightly build seamlessly supports .Net 3.5 and a host of other platforms.

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

To subscribe to my feed, add the following Url:  http://feeds.feedburner.com/jeffreypalermo.

With the original 0.86 beta 1 release, there was a small problem with folks who only had VS 2008 installed because there was a dependency on a registry key that was installed with the .Net 2.0 SDK (or VS 2005). 

The latest nightly build has fixed this, and a clean machine with VS 2008 can now use NAnt just fine.  CodeCampServer is using NAnt 0.86.2909.0, and it's working well so far. 

I have to say that over the past 2.5 years, I have been very pleased with NAnt.  It is a great open-source build tool, and it integrates with every other command-line tool I could want.  I normally <exec/> out to msbuild.exe for the compile.   I have a NAnt build template available in my public source code repository here.

5.6

How do you build your application?

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

The Hillbilly asks: How do you compile your application in your NAnt script for releases?

There are many options, you see, even though the <solution> task is no longer one of them. You could use the <msbuild> task to build the solution as it is built in VS (I think; the documentation is a little sketchy on this task if you don't know the inner workings of msbuild). Or you could use the <csc> or <vbc> tasks to compile a group of code files into an assembly (similar to a .csproj or .vbproj file). Or, for the ultimate control, you could use the <exec> task to call out to msbuild.exe, csc.exe, or vbc.exe directly though I couldn't tell you personally what that offers you that the imagecorresponding tasks don't. Future-proofing maybe.

Usually, for testing purposes at least, this entails using <csc> (or <exec> with csc.exe) to compile all the application code into a single assembly that I can run tests against. It's a practice I learned from JP Boodhoo and I've been happy with the results in the absence of anything better.

But I don't care much about the unit tests. I'm more interested in your releases. Assuming you've automated them in a NAnt script, how do you build the application in preparation for them?

Historically, I've usually used the <msbuild>/msbuild.exe scenario mostly because I couldn't wrap my head around writing a bunch of <csc> tasks to compile the code into the same structure I see in Visual Studio. For example, if your solution has a Domain project, a DataAccess project, and a UI project, I would need three <csc> tasks to create the individual assemblies. Or one <msbuild> task running against the solution. My reasoning was that it was the easiest way to build the application the same way I did in Visual Studio, which I assumed was how I wanted to deploy it.

Then I talked to Donald Belcham.

Conversations with Donald Belcham are always eye-opening (and I won't expand on that comment this time; happy belated birthday, dude). And during our chat, he admitted to using <csc> to create his releases. I expressed my surprise: "But Iggy, what if your solution has a dozen projects in it? I don't want to deal with the pain of a dozen <csc> tasks in the right order". To which he replied: "Dude, you don't need to deploy the same way you build. The Visual Studio solution is a file management mechanism, not a deployment mechanism." And my mind awakened like it did during my last visit to Brian Head.

The basic idea Donald described was thus: Just because you build your application one way in Visual Studio during development, doesn't mean you need to build your releases the same way. Especially if you are using NAnt to create your releases because then you can do it however you like.

And as if my mind wasn't expanded enough, he typically shoots for one assembly per physical location. Not one assembly for the domain, one for the data layer, one for the common utilities, and so on and so forth. One. Total. If I were building a WinForms application with no other physical layers, I'd have one file: MyApp.exe. If it were a WinForms app calling a web service, there would be two assemblies. One for the client and one for the web service (plus corresponding .asmx files).image

This is the extreme position of course and there are caveats. If the application depends on third-party libraries, naturally we won't bundle those up into the assembly. And if you're using an internal client library that is common to more than one project, you'd treat that as you would any other third-party library and keep them separate. But if your application-specific domain code and data access code sits on the same server, that all gets munged into one assembly regardless of how it is organized in the .sln file. NAnt gives us that flexibility.

I'm kind of putting Donald out there for potential ridicule so I'll expose myself ever so slightly and admit that I really like this idea. Why *do* we feel we have to ship a dozen assemblies for our application? If something changes in our domain, what difference does it make if we re-deploy MyCompany.MyApp.Domain.dll or MyCompand.MyApp.exe? And in speaking with Donald, he points out that even though we have the flexibility to deploy only parts of an application, rarely do we exercise it. In a typical scenario, new versions and hot fixes are deployed as an "all or nothing" in each physical layer anyway. This matches my experience. Even if nothing changed in certain assemblies, I typically re-deploy everything during an upgrade just to be safe.

Now, we still need to be practical about it. If the resulting executable is 300Mb, then ISDN line or not, you'll want to break that into something more manageable. But for the average application, one assembly should function just as easily as five, yesno?

Looking forward to hearing the counter-arguments because I haven't quite thought this through too much except from a maintenance point of view. In particular, are there performance differences with loading several smaller assemblies vs. one "larger" (but still manageable) one? What about issues with unloading an assembly from an application pool in IIS?

Enquiring minds want to know!

Kyle the Inquisitive

First Causes: Reversibility

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

I've just started a blog series to talk about how the first causes of software development can help us make better choices and decisions.  In previous posts I talked about how we can know something and how to decide what is good.  For my very first deep dive I want to talk about Reversibility.  It's an important thing to consider because Reversibility, or the lack thereof, pretty well dictates when you have to make a decision and whether or not you can unmake that decision.  Why you care about Reversibility is summed up nicely by this quote from Martin Fowler in his seminal paper Is Design Dead?

“If you can easily change your decisions, this means it's less important to get them right - which makes your life much simpler. ”

Think about that.  If you can't change a decision at a later time, you've got to make that decision quicker and you've got less leeway to be wrong.  We can't control everything, but in many ways we can apply techniques and choose technologies that give us more Reversibility as a way to make decision making easier.  I see Reversibility manifesting itself in three general themes:

  1. Working and delivering incrementally.  I want to work incrementally by building a system one useful feature at a time.  There are solid economic reasons to work a project this way.  Underlying everything I'm writing about in this series is the desire to maximize the return on investment of our development efforts.  There's no return on investment whatsoever until something gets released into production.  In my company's case, we can make a release after the very first little module is complete to get an additional cashflow going.  To get that positive cashflow going I need to get the first module out the door, and it doesn't require the same complexity of infrastructure that the following modules will.  I can make the company more money by building out a simple infrastructure for the first release, even though that simple infrastructure will eventually need to become much more complex and robust.  I do want the ability to build out the more complex infrastructure later without breaking or rewriting the first module.

    There's also the issue of complexity and the limits of the human mind.  We can only consciously deal with so many variables at any one time.  It's easier to develop a system when we can eat the elephant one bite at a time by working on one feature at a time.  In order to really work one feature at a time and keep up the pace of continuous delivery, we often make simplistic solutions for some infrastructure elements.  That infrastructure might be perfectly good for the features at hand, but insufficient for later features and later system loads.  That's perfectly fine, and I'd argue that it's desirable, as long as I can reverse the simplistic solution with a more complex or robust solution later.  Not having to worry about making the infrastructure robust for later features let's me escape the analysis/paralysis trap and keep getting completed features out the door.  If I feel like I need to get some piece of infrastructure code exactly right before going any farther with features, I've got to pause and complete that infrastructure before I can continue with more features.
  2. You will make wrong choices and mistakes.  I want everybody to think hard about this.  Putting yourself in a situation where an early decision made wrongly can is expensive to be undone is going to lead to a brittle project.  It's going to be easy to fail because you're dependent upon every decision being exactly right upfront.  On the other hand, if you can make adaptations in the requirements or refactor away problems in the design later without substantial extra costs, you're going to be more resilient.  That implies some attention to finding your mistakes and problem spots in the design before it's too late, but I'll save that for a following essay on Feedback.  Working adaptively will lead to more consistent success than working only by prediction.  What would you rather base your decisions on, adapting to what is actually happening as the project progresses, or basing decisions solely on what you think is going to happen?  Adaptability is much easier with Reversibility. 
  3. Things will change.  Your current requirements are exactly right for today's business situation, and your current design elegantly satisfies those requirements, but tomorrow is going to come with unexpected surprises.  Business drivers will change.  Technologies will change.  Your understanding of the design will change.  You'll stumble into performance problems that you didn't foresee.  You'll make assumptions that will blow up in your face.  Change will happen.  With good reversibility, you'll be able to deal with change.

 

I think it boils down to making good decisions.  Having Reversibility makes it easier for you to get decisions right.  It makes decision making easier by allowing you to make decisions without the fear that you can never undo that decision, by allowing you to wait longer in the project to make more informed decisions, and by allowing you to back out decisions that turn out to have been wrong.  In situations where you have to make irreversible decisions you're going to be more brittle because you're forced to make decisions earlier and you have less flexibility to change bad decisions.  Since I think it's impossible to be right every time, put me down for an extra helping of Reversibility.

 

The Mini Saga of the Clustered Index

Here's an example from my current project that brings out several of the issues around Reversibility.  My boss has a deep background in database design and development, but little in Sql Server.  He's very concerned about the choice of which column in any given database table should be the clustered index.  It's a big, important decision that potentially has a lot of impact on the performance of the system.  My boss is concerned, and he wants that decision made right now so that he can rest assured that our baseline performance is going to be good enough.  I think it's an important decision too, and that's why I think we should put that decision off for at least six months to make sure that our baseline performance is going to be good enough.  So who's right?  It basically comes down to how the two of us perceive the Reversibility issue.

I think that decision needs to be put off until much later in the project when we have real performance numbers and usage scenarios to consider.  If we tried to design the clustered index solution right now we would just be making an educated guess that's more than likely going to be wrong anyway, so why bother?  I want to wait until the Last Responsible Moment to make that decision.  For a refresher course, as stated by Mary Poppendieck, the intent behind Last Responsible Moment is to:

“…delay commitment until the last responsible moment, that is, the moment at which failing to make a decision eliminates an important alternative. “

Roughly put, the Last Responsible Moment calls for you to make better informed decisions by waiting as long as possible to make a decision.  The Last Responsible Moment is the point at which you have the most information in your hands with which to make that decision.  In six months we'll have much more information about the performance characteristics of our new system and know where our database performance bottlenecks really are based on empirical performance measurements.  In six months I'll be much better able to determine which database column is the best choice for the clustered index in every table. 

Now I have to answer the question "can I get away with waiting to make this decision?"  The Last Responsible Moment is also the last point at which you can wait to make a decision before the lack of a decision causes problems.  Using the logic of the Last Responsible Moment, I want to wait as long as possible to make well informed, and hence better, decisions.  Unfortunately, there's a limit to how long I can wait to make a decision, and this is where Reversibility comes into the picture.  If a decision is easy to reverse or retrofit into the system later, I don't need to make that decision right now.  If a decision is hard or expensive to change later, then I have to spend more upfront analysis and design time to make that decision earlier.  Decisiveness can be an admirable trait, but good decision making often requires reflection and feedback.  When I can put off a decision for later I gather more insights from the project work that can lead me to better or even simpler solutions than I might choose if I had to make the decision upfront.  Oftentimes the Reversibility of a decision is out of your control, but in other cases like my clustered index decision, I can take steps to increase my Reversibility.

My boss's worry is partially based on how hard he found it to change the clustered index on a table using the Sql Server Management Studio GUI tool.  The admin screen promptly put up a message box telling him that he couldn't change the clustered index on a table without dropping a bunch of other indexes on other tables first.  That experience made him conclude that changing the clustered index late in the game was going to be too hard.  He was afraid that the choice of clustered index is not a reversible decision.  One way or another we're going to have the entire database schema scripted out with all of the DDL in Subversion, with a fully automated way to rebuild the database schema from scratch.  Since rebuilding the database from scratch is going to be part of the normal Continuous Integration strategy anyway, all I have to do to change the clustered index later on any table is to modify a single DDL script, check it back in, and voila! -- I've changed the clustered index.  My point being that the existence of a good configuration management strategy for the database will allow me to change the database schema at will right up to the point when we're actually ready to deploy the database to a customer.  Add in an automated regression test suite, plus the unit test coverage that falls out of TDD, and I'm much more able to make changes later.  By baking in more Reversibility with the database build and test automation strategies, I can push back the Last Responsible Moment, and make better decisions in regards to my clustered index decisions.

Database design isn't rocket science, so why can't I take the time to do the analysis and think it through right now?  Maybe I could, but the time spent on upfront database design would be taken away from other areas where I see more immediate risk.  Performance is a risk for sure, but our biggest risks are delivering a good user experience and getting the right Domain Model in place to support the necessary behavior.  I'd rather put my time and focus on those issues now because I see those decisions being harder to reverse.  The Last Responsible Moment for the user interface machinery is coming up a lot faster than the database.  By making the reconstruction of the database schema highly automated and ruthlessly keeping persistence concerns out of my business logic and user interface code (orthogonality, but I'll get to that later), the decisions about the database structure are highly reversible.  Therefore, I can put my focus on the first complicated screen and Domain Model without worrying if I can make it work with the database or not. 

 

Team Composition Matters

The composition of your team and organization can have a dramatic effect on your reversibility.  If all of your decision making can be done within your team, you've got a lot more Reversibility in your decision making than you do when your decisions have to coordinated with or made by an external resource.  When you need to deal with an external specialist, you have to do more upfront planning to best take advantage of the expert while they are available to you.  The expert often adds value to your project, but the availibility of the expert decreases your scheduling flexibilityy.  I don't know if I've said it explicitly enough, but I think that a small self-contained team of full time generalists trumps a team of part time specialists every single time. 

Earlier in this decade I worked in the manufacturing IT arm of a company that was an interesting juxtaposition of elite business moxie and putrid software development.  The company was undeniably one of the best examples of lean manufacturing in the world (the intellectual progenitor of Agile development), but its IT departments were the worst examples of bad Waterfall thinking.  Near the end of my captivity there we went to a "consulting" model (our VP was from CapGemini and Accenture).  The idea being that we would sharpen a set of very solid specialists and share those specialists across the entire portfolio of projects.  Of course, it also meant that those specialists were moved very rapidly from project to project.  Business analysts would go onto a project early, write the requirements, hand them over to an architect and move on to the next project.  The architect would take the requirements, document a system design, then (you guessed it) skedaddle on to one of the other 6-7 projects he was responsible for.  At no time in the project were developers, analysts, the architect, and the testers ever actively engaged on the project at the same time.  It was unbelievably brittle.  The whole thing crashed and burned anytime anybody made a mistake.  The developers on the team were typically not empowered to make decisions on design direction or the requirements, and it would always take some time to get the original analysts and architects back to the project to consult.  The organization wasn't that great to begin with, but it took a major step backwards because of the "consulting" model.  The business finally became angry enough that they stepped in and took over direct control of the IT program management.  I just googled the VP that inflicted that insanity upon us.  She was named CIO of a Fortune 100 company last year.

At DevTeach Vancouver I heard Greg Young say "I can find an argument to defend everything but scope creep."  I'll pick up the torch here from Greg, because I can think of a great defense of scope creep.  Very frequently the user requirements that come in very late in the game represent some great ideas that would add a lot of value into the system.  The most popular feature of the most successful system I ever built was a near last minute user request.  Fortunately, I had access to the business folks, analysts, and testers all the way through the project and we could happily take on that user request.  If we had needed an external expert (I will NOT refer to any human being as a "resource") for any part of that feature we wouldn't have been able to coordinate with the external person fast enough to complete that feature -- and the project would have been less successful for not having done that feature.

 

Sooner or later, you're going to hit a project that's too big for the ideal 4-6 developer sized team.  In those cases we generally have to divide the team, but how?  We could divide the team by:

  1. Horizontal layers.  In my financial development experience, that ended up being a backend Java team and a frontend .Net team.
  2. Vertical features, but maybe create a centralized team to manage shared services and framework construction.
  3. Vertical feature teams, and share the responsibility for shared infrastructure among the teams (which doesn't preclude an architecture team) 

I choose number 3, and I'll use the concept of Reversibility to explain my answer.  Like I said above, you can most easily reverse the decisions that you own while decisions you can only make with the participation of people external to your team are harder to reverse.  In case number 1 you might be dependent upon an external team to build your web services.  Every single feature that you build is going to be dependent upon that other team.  The Last Responsible Moment is going to come relatively early as you and the backend team need to agree on a web service contract fairly early so that the backend team can start their work and your team knows what signature to code to.  In case #2, you're reliant on infrastructure code that you can't change yourself.  You can ask the central team to change the framework to better suit your needs, but that's going to involve more friction and resistance than it would in code that's completely under your control.  Again, you don't want to put yourself in a position where any mistakes are hard to reverse by putting organizational overhead in the way.

I'm jumping ahead of myself, but choices #1 and #2 also result in less corrective Feedback by splitting the infrastructure builders from the infrastructure users.

 

 

More examples

  • Code GenerationRob Conery just shared a story about using code generation for an admin site where the database and generated code got out of synch and eventually blew up.  If you're going to use Code Generation, I'd very strongly recommend you use active code generation instead of passive code generation.  Make the code generation part of the automated build process.  If you absolutely have to use one of those schemes where the object model is codegen'd from the database schema, set something up with the Continuous Integration build that automatically builds the database from the latest source and uses that schema to regenerate the code.
  • The Myth of Service Oriented Architecture:  I'll get flamed for this again, but I don't care.  SOA is a means, not a goal.  Used in the right circumstances it will make your business more nimble by making the business automation processes easier to change.  Great, more reversibility is good.  But think on this as you compose your service boundaries, what can you change faster, an in-process service provider completely contained within one logical system/service boundary, or the same service provider exposed externally and maintained separately by a different team.  Which is easier to change?  You do NOT have good reversibility in changing the contract of a publicly published web service contract, especially if there is more than one development team involved.  I hit this before in a Microcosm of Agile Design, but I don't think anybody picked up on the Reversibility angle of the two choices.  SOA is partially predicated on the assumption that "monolithic" applications are hard to change.  I think that good application architecture can frequently eliminate the economic advantage of building distributed SOA style solutions.  SOA is most appropriate to me in cases where rapidly changing business processes need to interact with legacy systems that aren't easy to change themselves.
  • Process and Modeling Weight:  If you invest a lot of time in creating elaborate UML models and spiffy design documentation upfront, are you really going to be as emotionally able to ditch that design when it's proven to be wrong or a better solution is discovered?  You should, because the design documentation is a sunk cost.  However, human nature is going to make that decision harder because of the emotional investment in the bad design.  One of the truisms of Agile design lore is to not give yourself any incentive to keep a bad design.  If you need to go through some sort of process vetting to make or change a decision you've also got less reversibility.  A lot of shops will use formal quality gates at various times to "lock down" designs or requirements.  That might be a good thing, unless that quality gate process makes it harder to change your design or analysis after the quality gate process is done.  I guess that what I'm trying to say is that you never want to give your teams artificial reasons not to do the right thing.
  • Project Friction:  I've been in a couple spots where configuration management practices actually made it difficult to check in code changes.  In that situation you don't want to be making coding changes any more often that you possibly have to.  More frequently, I've been in shops that had very poor configuration management processes around the database structure.  If you can't reliably synchronize database changes across different development environments, or if you have to fill out a lot of paperwork to make those changes, you'll find yourself bending over backwards to avoid making database changes -- often to the detriment of the project's quality.
  • Model First:  I do not like the concept of designing the database first then codegen'ing the object model.  I think the Agile database community has made strides in the last couple years, but Object Oriented code is much, much easier to evolve and refactor.  With refactoring tools like ReSharper and fast running automated tests, OO Domain Models are much "softer" than a database schema can ever be.  My strong preference is to use a "Persistence Ignorant" Object Relational Mapper like NHibernate and let the database largely fall out of my Domain Model (or at least make the design of the database run in parallel with the Domain Model).  I think a database first approach forces you into doing much more design upfront.  The upfront code generation is great for the initial creation, but I think those tools are balky when it comes time to make little changes.  When I want to add a property to a Domain Model class I want to go right to it in Visual Studio and add the property.  I don't want to fire up a sluggish code generation tool just to add a single property.  I also get irritated with the code generation strategies when I want to change a property name.  With ReSharper I hit SHIFT-F6 and do the Rename refactoring.  With a codegen tool I modify the code generation model, start the code generation, then compile to find all the places in my code that is now broken because the generated code changed.  No thank you.
  • VB6 COM versus .Net:  You didn't want to do much evolutionary design with COM components written in VB6.  You really wanted to lock in the public signature of the COM classes as early as possible, then warn other developers not to breathe on your IDL signature.  Anytime you changed the public signature of a COM class you risked a chance of breaking the entire COM class and rendering the newly compiled class useless from its clients.  With the advent of .Net, those problems largely went away.  As long as the binary signature of an existing method was maintained, you could happily add new things to a .Net assembly without any concern for binary compatibility.  It's no coincidence that the evolutionary practices behind Agile development first came into the Microsoft development world as we switched from Windows DNA to .Net based solutions.  Your technology choice greatly impacts your Reversibility.
  • Duplication is a Killer:  One of the best ways to increase your Reversibility is to reduce duplication in the system.  If you Don't Repeat Yourself, you can change your system much more effectively.  An example of this for me last week is the "autocomplete" behavior in our screens.  My business folks want something more sophisticated than the built in ComboBox, but for reasons of my own, I don't want to touch the equivalent control in our 3rd party suite.  Sometime when I shake free I'm actually going to write my own autocomplete functionality (sigh).  I don't think I need to do this right now because every ComboBox in our user interface is governed by an instance of the same MicroController class.  All I need to do to add the autocomplete functionality later is enhance this one class.  If I had to make that change manually to each and every ComboBox in every code behind, I'd have to stop and do that code right now.
  • Test Automation:  A solid safety net of test automation makes changing the code safer.  Any time we change an existing system we incur a risk of causing regression errors in existing code.  That fear of regression problems prevents many teams from considering improvements or changes to their system.  With a good amount of test coverage we can confidently change a system and know if and where we've broken some existing code.  Regression testing is a major cost over the lifetime of an application.  So much so that it often dictates the end of life of many systems.  I see test automation as a means to lengthen the lifecycle of a codebase.

 

How does Reversibility relate to the other first causes?

  1. Orthogonality is a huge contributor to improving your Reversibility.  You can most easily reverse prior decisions if you only have to change that one decision.  You can't rapidly change your caching strategy if it means getting into and changing user interface and business logic code as well.  Orthogonality helps to contain changes.
  2. If we're going to take advantage of making decisions at the Last Responsible Moment, we need to gather more information about our system as we go.  Feedback helps guide us in our decisions and informs us when we need to reverse a decision.  Another quote from Martin Fowler:  "Designing for reversibility also implies a process that makes errors show up quickly."  You need to build in Feedback loops to find problems.
  3. Code readability/understandability/solubility whatever you want to call it.  In order to make a change in a system, you've got to find the place to make that change and understand the impact of your change.

 

Summary

Reversibility makes it easier to make good decisions.  You can partially and advantageously control the timing of your decision making by choosing tools that give you more Reversibility.  Stealing another saying from the Poppendiecks, you need to decide when to decide.  Some decisions cannot be put off and you'll have to do the best you can with these.

 

 

There'll be more to come sometime next week.  I think I'll do Feedback next.

Sunday February 10th, 2008

Container Ignorance

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

There's a pretty good thread on the altdotnet board around AutoMocking Containers and the role of an IoC tool. I'm going to second something that Ayende said: 

...I would say that container ignorance is as important as persistence ignorance. I don't want to deal with infrastructure in my code unless I cannot avoid it.

Ditto from me.  As the guy who's most likely been using an IoC container in .Net systems for the longest time, minimize your exposure to the IoC container.  It's infrastructure code.  The classes that do the real work in your system probably shouldn't have an reference to infrastructure.  Use the heck out of the IoC tool to put together services and object graphs by pushing dependencies into a class, but minimize the number of places where a class has to directly pull something out of the container.  Besides, if you're leaning hard on autowiring of dependencies, you shouldn't need that many calls to ObjectFactory.GetInstance().

Layering, the Level metric and the Discourse of Method

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

 

When we are discussing the architecture of a code base, we often qualify a piece of code with terms such as high level and low level. This is common vocabulary and we all intuitively know what does it means. A piece of code A (whether it is a method a class, a namespace or an assembly) is considered as higher level than a piece of code B if A is using B while B doesn’t know about A. From this simple definition, we can order piece of codes in our program as shown in the following diagram:


We can say that tier code that our application is using but that we are not maintaining has no level. Indeed, such code doesn’t use our application and it doesn’t belong to our code base.

 

Then we can say that our code that doesn't use anything has a level of 0.

 

We can say that our code that is using only tier code or code of level 0 has a level of 1.

 

Etc…

 

We actually just defined a code metric that is named Level. To be computed, the Level metric just need a graph of dependencies. If you consider the graph of dependencies between the methods of your program, you can assign a Level to your methods.  The same apply to the graph of dependencies between your types, the graph of dependencies between your namespaces and the graph of dependencies between your assemblies.

 

We then obtained 4 Level code metrics defined respectively on methods, types, namespaces and assemblies. These metrics are supported by the tool NDepend. For example, you can easily order your namespace with this simple Code Query Language query:

 

SELECT NAMESPACES ORDER BY NamespaceLevel DESC

 

What is cool is that knowing about Level is a sort of reengineering. With this metric, one doesn’t need to ask to the code base expert where high level code is and where low level code is. One can just check by himself with the tool.

 

But why a developer would want to know about high level and low level? There is actually a very good reason: at any time a developer should make sure that low level code that she is writing doesn’t accidentally rely on higher level code.

 

Maybe the most important design rule in making software is divide and conquer. Taking care about level is so important in software design because it is the primary way to divide and conquer.

 

  • We divide our code into component (i.e piece of code, no matter it is class, namespace, assemblies).
  • We conquer by making sure that there are no dependency cycles between our components.

If A is using B that is using C that is using A, then A, B and C cannot be developed and tested independently. In other words A, B and C are indivisible, they are not 3 components anymore but instead they form one single super-component, globally more complex than the 3 smaller components.

 

 

Level and dependencies cycles

 

Interestingly enough, the Level metric cannot be computed when the graph of dependencies contains dependencies cycles as shown in the following picture.

 

 

Not only component involved in a cycle cannot have a level but also component that use directly or indirectly a component involved in a cycle cannot have a level. The Level metric can then become a proper indicator to know if your components are layered correctly. If it cannot be computed for some components, there are some cycles. Translated into NDepend and CQL terms, if you consider for example that namespaces are components, you just need to write the following CQL constraint to be warned if your code is not layered correctly:

 

WARN IF Count > 0 IN SELECT NAMESPACES WHERE !HasLevel AND !IsInFrameworkAssembly

 

The condition !IsInFrameworkAssembly is just here to avoid matching tier code, that haven’t level anyway.

 

 

Level and abstraction

 

The Level metric can also help to detect poor use of abstraction. Indeed, if you only have concrete components that depend on each others, you will necessarily end up with components with high Level value. On the other hand, if you separate your abstractions and implementations and link them at run-time by using the plug-in pattern, the Level values of your components will decrease significantly. The following picture illustrates this fact. The 2 red arrows shows the direction where the high level components reside. We can see that the Level values doesn’t increase in case of loose coupling between implementations.

 



As a consequence, if your code base contains types or namespaces or assemblies with a high level value (>10) this might be an indication that you need to create more abstraction to reduce coupling between implementations.

 

If you are interested in knowing more about how to use NDepend for layering, you can read an article I wrote, available here. It is about how to get a clear and maintainable architecture by controlling dependencies between your components.

 

 

Origin of the Level metric

 

As far as I know, the Level metric has been first introduced by John Lakos in his great book Large-Scale C++ Software Design (Addison-Wesley 1996). Although this book was well-known, IMHO the principles it states should have become mainstream but they actually didn't. Maybe the book targeted a too small population of developers and architects that are responsible for very large projects. Maybe the industry was not ready for these concepts because the C++ language doesn’t make it easy, both to write static analyzer and to componentize code properly.

 

 

Rambling on Divide and Conquer

 

Finally I would like to digress a bit on the divide and conquer principle. It was first introduced by the French philosopher and mathematician René Descartes in 1628 in its Discourse of Method. Descartes is widely considered as a major contributor to modern science and mathematics, it is worth quoting the forth tenets that summarize this discourse:

 

  • The first was never to accept anything as true if I did not have evident knowledge of its truth; that is, carefully to avoid precipitate conclusions and preconceptions, and to include nothing more in my judgements than what presented itself to my mind so clearly and distinctly that I had no occasion to doubt it.
  • The second, to divide each of the difficulties I examined into as many parts as possible and as may be required in order to resolve them better.
  • The third, to direct my thoughts in an orderly manner, by beginning with the simplest and most easily known objects in order to ascend little by little, step by step, to knowledge of the most complex, and by supposing some order even among objects that have no natural order of precedence.
  • And the last, throughout to make enumerations so complete, and reviews so comprehensive, that I could be sure of leaving nothing out.

I think that these tenets apply so well to software development. Here is my personal interpretation:

  • The first tenet can be seen as writing your test at least in the same time (or even before) as you write your code to make sure that you are actually writing code that undoubtly works (I had no occasion to doubt it).
  • The second tenet can be seen as separating concerns in order to separate difficulties to code each concern better (divide each of the difficulties I examined).
  • The third tenet can be seen as writing low level components first, in order to raise (step by step) the complexity of the code. It also pinpoints that a total order between components should exist, meaning that dependencies cycle are unacceptable.
  • The forth tenet can be seen as writing as many integration tests as needed to make sure to have a high test code coverage ratio, ideally equal to 100% (I could be sure of leaving nothing out).

Undoubtly if Descartes was alive today, he could be a great developer :o)

 

Saturday February 9th, 2008

Splitter bars: Not for the farsighted

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

I think there are a few "standard" controls that are in serious need of revisiting/refactoring. One of them is the splitter control. Below is an image from Word 2003 with a document on the left and the thesaurus on the right. This is probably more obvious on standard monitors but on my laptop, the space between the dark grey bar and the side window appears almost as a single colour. I've placed red lines around the actual "clickable" area for the splitter.

image

Here's another example with a horizontal splitter in Word 2003.

image

And yet another, this time in Visual Studio 2008. Note that there is also a darker grey bar outside the red lines but just to add to the confusion, this is not, in fact, clickable.

image

I'm still primarily in Windows XP/Office 2003 so maybe this has been addressed in Vista/Office 2007. If not, it needs to be. I've seen other complaints over the years about having to hunt for pixels in order to control the splitter so I don't understand why it is still an issue in 2008. Even the Apple guidelines state that a 1-pixel splitter is the most common. Or maybe it's just my eyesight and motor skills deteriorating.

The Hillbilly is gettin' too old for this #*%$.

Kyle the Myopic

AutoMocker in StructureMap 2.5

CodeBetter.Com From CodeBetter.Com, 11 months ago, 0 comments Comment

Steve Harman asked me yesterday to show a little demo of the AutoMocking container coming soon in StructureMap 2.5.  Honestly, I was very lukewarm to the idea of an "AutoMocking" container at first because I thought it would obfuscate tests.  Everyone else was doing it, so I figured I'd give it a shot too and I built an automocker into StructureMap.  I'm not entirely thrilled with the API as it stands, so any feedback would be very welcome.

My advice for the last four years has remained pretty consistent:  use StructureMap (or container of your choice) in unit tests very sparingly.  Just use plain Jane constructor injection inside your unit tests.  That advice aside, what you end up with is a lot of boring, repetitive code like this sample from StoryTeller that tests a class called WikiTextPresenter:

        private MockRepository _mocks;
        private IWikiTextEditor _editor;
        private ITestFormatConverter _converter;
        private WikiTextPresenter _presenter;

        [SetUp]
        public void SetUp()
        {
            _mocks = new MockRepository();
            _editor = _mocks.CreateMock<IWikiTextEditor>();
            _converter = _mocks.CreateMock<ITestFormatConverter>();

            _presenter = new WikiTextPresenter(_editor, _converter);
        }

It's simple code, but it's code that you write over and over and over again to do interaction testing.  Instead, what if we wrote something that can

  1. Look at the constructor of the WikiTextPresenter class being tested above
  2. See that it requires an IWikiTextEditor and an ITestFormatConverter in its constructor
  3. Create a mock object for each of WikiTextPresenter's dependencies
  4. Poke all the mock objects into WikiTextPresenter for us
  5. And lastly, give us easy access to both the class under test and all the mock objects that the class under test depends on

That in a nutshell is an automocking container.

After seeing what the Eleutian guys were doing, I wanted something similar to their AutoMocking container just to eliminate the repetitious code of building mock objects and ramming them through a constructor function.  I built a new assembly in StructureMap called StructureMap.AutoMocking.  Inside it is a class called RhinoAutoMocker that extends the RhinoMocks MockRepository class with some StructureMap magic.  RhinoAutoMocker's responsibility in life is to connect the right mocks and/or stubs to the class under test, freeing you from the monotonous code shown up above.  Specifically, you use a generic parameter to tell the RhinoAutoMocker what the concrete class under test is.  The class itself is below.  After the break, I'll talk about usage.

    // Note that it subclasses the RhinoMocks.MockRepository class
    public class RhinoAutoMocker<TARGETCLASS> : MockRepository where TARGETCLASS : class
    {
        private readonly AutoMockedInstanceManager _manager;
        private TARGETCLASS _classUnderTest;

        public RhinoAutoMocker()
        {
            RhinoMocksServiceLocator locator = new RhinoMocksServiceLocator(this);
            _manager = new AutoMockedInstanceManager(locator);
        }

        // Replaces the inner InstanceManager in ObjectFactory with the mocked
        // InstanceManager from the auto mocking container.  This will make ObjectFactory
        // return mocks for everything.  Use cautiously!!!!!!!!!!!!!!!
        public void MockObjectFactory()
        {
            ObjectFactory.ReplaceManager(_manager);
        }

        // Gets the ClassUnderTest with mock objects (or stubs) pushed in
        // for all of its dependencies
        public TARGETCLASS ClassUnderTest
        {
            get
            {
                if (_classUnderTest == null)
                {
                    _classUnderTest = _manager.FillDependencies<TARGETCLASS>();
                }

                return _classUnderTest;
            }
        }

        // I find it useful from time to time to use partial mocks for the ClassUnderTest
        // Especially in Presenter testing
        public void PartialMockTheClassUnderTest()
        {
            _classUnderTest = PartialMock<TARGETCLASS>(getConstructorArgs());
        }

        private object[] getConstructorArgs()
        {
            ConstructorInfo ctor = Plugin.GetGreediestConstructor(typeof (TARGETCLASS));
            List<object> list = new List<object>();
            foreach (ParameterInfo parameterInfo in ctor.GetParameters())
            {
                Type dependencyType = parameterInfo.ParameterType;
                object dependency = _manager.CreateInstance(dependencyType);
                list.Add(dependency);
            }

            return list.ToArray();
        }

        // Get one of the mock objects that are injected into the constructor function
        // of the ClassUnderTest
        public T Get<T>()
        {
            return _manager.CreateInstance<T>();
        }

        // Set the auto mocking container to use a Stub for Type T
        public void InjectStub<T>(T stub)
        {
            _manager.InjectStub<T>(stub);
        }
    }

In usage it looks like this for the WikiTextPresenter class we looked at up top.  The test specifies that when ApplyChanges() is called on WikiTextPresenter, it will take the raw text from its view (IWikiTextEditor), convert that text to the internal data structure with ITestFormatConverter, and finally update some information in the View.

        [Test]
        public void ApplyChanges_with_the_automocker()
        {
            RhinoAutoMocker<WikiTextPresenter> mocks = new RhinoAutoMocker<WikiTextPresenter>();
            using (mocks.Record())
            {
                Test test = new Test();
                mocks.ClassUnderTest.TestPart = test;

                string theWikiText = "!|SomeFixture|";
                Expect.Call(mocks.Get<IWikiTextEditor>().WikiText).Return(theWikiText);

                WikiVersion expectedVersion = new WikiVersion(0, theWikiText);
                mocks.Get<ITestFormatConverter>().ApplyChangesFromWiki(test, theWikiText);
                mocks.Get<IWikiTextEditor>().AddWikiVersionToList(expectedVersion);
                mocks.Get<IWikiTextEditor>().SetWikiVersion(expectedVersion);
            }

            using (mocks.Playback())
            {
                mocks.ClassUnderTest.ApplyChanges();
            }
        }

RhinoAutoMocker creates the WikiTextPresenter instance under test on the first call to RhinoAutoMocker.ClassUnderTest.  The Get<T>() method on RhinoAutoMocker simply retrieves the mock object of type T that was used to construct the class under test.  Otherwise, all other usage is just the normal RhinoMocks usage.

In case you're wondering, I chose RhinoMocks because:

  1. RhinoMocks is probably the most common mocking tool by a large margin.  It's what I use, and I ultimately wanted a tool for me;)
  2. NMock/NMock2 seems to be dead.  I finally eliminated the direct NMock support from StructureMap for the 2.5 release anyway.
  3. If you're using TypeMock you probably don't care about dependency injection and automocking anyway

Making the RhinoAutoMocker subclass MockRepository just seemed like a good way to have all of the RhinoMocks capabilities right there at hand instead of wrapped up behind the scenes.

 

 

If you want to use this now, you need to download the very latest code out of StructureMap's subversion repository at https://structuremap.svn.sourceforge.net/svnroot/structuremap/trunk.  Like I've said before, I'm basically done with coding on 2.5, but I'm not releasing officially until I can do a full rewrite of the website and documentation.

 

« older items