This post originated from an RSS feed registered with .NET Buzz
by Udi Dahan.
Original Post: Betcha can't cache me
Feed Title: Udi Dahan - The Software Simplist
Feed URL: http://feeds.feedburner.com/UdiDahan-TheSoftwareSimplist
Feed Description: I am a software simplist. I make this beast of architecting, analysing, designing, developing, testing, managing, deploying software systems simple.
This blog is about how I do it.
I'm going to break from my recent SOA series and touch on a topic near and dear to my heart. Caching. The reason for this is being labeled as dealing with things "in the large". <rant - no, sorry - tirade>I'm of the strongest opinion that an architect that can't code - no, strike that - isn't a great coder, has any business telling people how a system should be built. Same goes for people who only do UML. I actually find these people the most ridiculous. Unless you can run your UML diagrams and see that they produce the exact results desired, don't go telling programmers to "fill in the code" - convinced that if something doesn't work, then it's the programmer's fault for not implementing your perfectly designed class properly.</tirade>
On to caching. <rant - again>About the quickstart accompanying the caching application block - for starters, there's hardly anything there of any value about caching. Even worse, the code stinks ! Is this really how Microsoft should be showing developers to use their blocks ?! For god sake, the code has no intent ! The comments barely cover it up. If I can't understand code without the comments, then the code itself needs some serious refactoring.</rant - hopefully the last>
Scoble, do you think that a quickstart accompanying the caching application block should contain about 10 relevant lines of code and over 1000 lines about the asynchronous block ? When I go and present to a user group how great the caching application block is, am I expected to provide the code showing them the proper way to operate it ? I can, and will ( seeing as I have no choice ) - and maybe should even send it to the Microsofties in charge of the block - but this seems a bit off. Of course I don't blame you, Robert, but you have made yourself so accessible ( Thank you, thank you, thank you ) that I feel you are the one that could catalyze the change. I mean, really - this block's been out for over a year !
Now, on to caching - this time for sure =)
The very essence of caching can be demonstrated as follows:
public void Bad()
{
for ( int i=0; i < SOME_BIG_NUMBER; i++ )
DoSomethingWith( ReallyLongCalculation() );
}
public void Good()
{
object result = ReallyLongCalculation();
for ( int i=0; i < SOME_BIG_NUMBER; i++ )
DoSomethingWith( result );
}
This is called "client-side caching". Why ? Because the client code ( shown above ) decides that the result of the really long calculation needs to be locally cached to improve performance. There is also something insidious going on here. The client code "knows" - somehow - that calling the code once, or any number of times, has the same effect. This isn't "tightly coupled" as we know it. In some ways, its worse. We have no idea if the original behaviour is preserved when caching in this manner.
The fact of the matter is that we developers do this all the time when dealing with our own code. The problem is that we get into the habit, and when working with other code ( that we may not have the source code for ) we keep doing the same thing. What if each call has a necessary side effect ? Have we just introduced a bug ( a really sneaky one ) in trying to improve performance ?
Obviously, any caching that needs to be done should be done in the "server code" - the "ReallyLongCalculation()". But, that's not enough.
What's that ? You say - "What else can I do ?" Its called API design. You could change the signature to something like: "public object ReallyLongCalculation(bool cacheResult)" so that the developer working with your code would understand that he doesn't have to ( and, more importantly, shouldn't ) cache things himself. Actually, in order to improve the readability of his code you should do one more thing.
Instead of having the call look like: "ReallyLongCalculation(true)" - create an enum "ShouldCache : int { Yes = 0, No = 1 };" and change the signature to use it instead of the bool. This gives us a more intelligible call: "ReallyLongCalculation(ShouldCache.Yes);". Finally - change the name ! Duh !
These are the sorts of design issues that come up when developers are just starting out. The application blocks are there to help us with the implementation - and they're great ! But the quickstarts show us how to use the blocks. And if the quickstarts suck, we probably won't grok the block.
( Hey, I like that ! "Grok the Block" ! I think I'll copyright it. )
I guess that it's true for any code that you write - always consider how to make client code more understandable. TDD does wonders for this, forcing you to think about it beforehand.
Finally, I hope that I've kicked the "in the large" only image. Code rules, but, coupled with good design, it rocks. Wrap it up in a nice clean architecture ( like SOA <wink /> ) and you've got a system that will stand the trials and tribulations of the real world.