Limitations of Declerative Coding

time to read 5 min | 853 words

David Hayden is talking about AOP, and he mentioned Caching declaratively, which sturk a chord, and I had to write a post about it. I want to talk about a completely different aspect of declerative coding, how far you should go with it. Just to be clear, this is fake code, and it has little to do with David's post other than using the scenario to make a point.

Let us take the code example that David has:

public class NewsController { private INewsService _service; public NewsController(INewsService service) { _service = service; } [CachingCallHandler] public NewsHeadlineCollection GetLatestNewsHeadlines() { return _service.GetLatestNews(); } }

 

Now, assume that you want to specify an expiration time? No problem, just put it in the attribute:

[CachingCallHandler(Expiration="10:00")]
public NewsHeadlineCollection GetLatestNewsHeadlines()
{
       
return _service.GetLatestNews();
}

What if I want to add a bit of smarts to the caching and only cache costly calls?

[CachingCallHandler(Expiration="0:15", CacheIfCallOver="0:30")]
public NewsHeadlineCollection GetLatestNewsHeadlines()
{
       
return _service.GetLatestNews();
}

Now I want to handle dependencies:

[CachingCallHandler(Expiration="10:00", CacheIfCallOver="0:30", DependencyConnectionStringName="MyDatabase"
                         DependencyStatement="SELECT * FROM HeadLines Where datePublished > getdate()-1"
)
]
public NewsHeadlineCollection GetLatestNewsHeadlines()
{
       
return _service.GetLatestNews();
}

But wait, I have a bit of business logic here as well, if there is a developing story, I want to skip caching altogether:

[CachingCallHandler(Expiration="10:00", CacheIfCallOver="0:30", DependencyConnectionStringName="MyDatabase"
                         DependencyStatement="SELECT * FROM HeadLines Where datePublished > getdate()-1"
)
]
public NewsHeadlineCollection GetLatestNewsHeadlines()
{
        if( _service.BigStoryNowDeveloping)
              CachingCallHandler.Current.SkipCaching();

       
return _service.GetLatestNews();
}

And now I have a different case, I want to call the GetLatestNewsHeadlines() and get the uncached results, maybe I am building a ticker, and it really need to be up to date. Now I need:

CachingCallHandler.DisableCachingForNextMethodOn(newsController);
return newsController.GetLatestNews();

This is a fake scenario, obviously, but just note how each additional business requirements make declerative more complex. I am not showing the code for the CachingCallHanlder, but you can be that somewhere its developer would be groaning for each such new requirement.

For myself, the minute that I put the connection string name hard coded SQL, that went way over the line. Even if I could skip it and use just the table name directly, that would be too much. And what happens if I need expiration from sources that do not support cache dependecies natively?

In short, I really love declerative coding, and I tend to overuse it at times, but it is really important to understand that you probably shouldn't try declerative coding for everything. If the scenario is simple and straightforward, that is a good candidate for ocde reduction and simplification. If it isn't, imperative coding (you know, if and else, as well as a while or two) are going to be more intent revealing, and would be easier to maintain.