30 December 2009

Using shims in programming

For those of you who may be new to computer programming, or even a seasoned programmer, the concept of using shims for maintaining code may be new to you as it is a relatively new concept. Fortunately, the concept is easy to understand. I will explain the concept of using shims in a function-centric point-of-view.
As time goes on, APIs change and sometimes those changes require functional parameter or processing changes. If a function's parameters are changed (whether reorganized, retyped, or additional or fewer parameters are passed), every other function that relies on a call to the changed function will need to be revised, which for large projects, may become daunting and adds a significant amount of development and testing time.
Introducing shims. Shims are used to bridge already written code (legacy code) with the new functionality. This allows APIs to continue to evolve, whilst providing a smoother method of deprecating older code yet still allowing it to function.
Here's an example that I actually ran into a few minutes ago: I had a method called ProcessWebRequest which processes HTTP requests and returns data. Here are the original function prototypes (in C#):
protected HttpStatusCode ProcessWebRequest(ref XmlDocument in_XML, string URL, bool IsPost, bool useHttps, bool requireCredentials)...
protected HttpStatusCode ProcessWebRequest(ref XmlDocument in_XML, string URL, bool IsPost, bool useHttps, bool requireCredentials, uint retries)...

I ran into a problem where HTTP request methods GET and POST did not provide enough functionality, and so I had to make the IsPost parameter obsolete and substitute it with something that would be more robust. I thus created an enumeration:
enum HTTPREQUESTMETHOD {
GET,
POST,
DELETE
};

But now I was presented with a problem: I had a lot of code working with this old function and now needed to bridge the old code with new code in the easiest, most concise way possible without going back and editing the previously-written code (I could always go and change all the references, but I do not have time for such a revision). Thus, I created a shim: I changed the code thusly:
protected HttpStatusCode ProcessWebRequest(ref XmlDocument in_XML, string URL, bool IsPost, bool useHttps, bool requireCredentials)...
protected HttpStatusCode ProcessWebRequest(ref XmlDocument in_XML, string URL, bool IsPost, bool useHttps, bool requireCredentials, uint retries){
return ProcessWebRequest(ref XmlDocument in_XML, string URL, IsPost ? HTTPREQUESTMETHOD.POST : HTTPREQUESTMETHOD.GET, useHttps, requireCredentials, retries);
}
protected HttpStatusCode ProcessWebRequest(ref XmlDocument in_XML, string URL, HTTPREQUESTMETHOD RequestMethod, bool useHttps, bool requireCredentials, uint retries)...

That's it! Now my old code immediately compiles with the new functionality and the changes work exactly as expected! Now I can tag the older functions as deprecated (with the "[Obsolete]" attribute) and gracefully phase out the old code over time. Its a very useful method of transitioning between old and new code, and can be used in many different scenarios.

No comments: