I was recently refactoring some code in a Web Service that is called by numerous external consumers as well as internal clients. As we all know when you publish an interface you are more or less signing a contract not to change that interface. This becomes even more of an issue when clients outside of your organization are calling your code.

Or perhaps you have written and distributed an SDK or API that is used by others to access functionality in your application. Either way, you change such public facing interfaces at your peril! It's why you often see method names like the following in public SDK's:

ShinyMethod
ShinyMethod2
ShinyMethod3
NewShinyMethod

This results from having realized, after the fact, that your public interfaces were unable to do something you want/need them to. Or perhaps something you are calling changed and now you need more information or different parameters than before. Whatever the reason since you signed the contract, you had to implement different methods leaving the old ones intact so that you don't break every caller instantly during your next update.

This is a legitimate response to a common problem. Now don't start screaming at me about better design, overloading methods etc. I know there are dozens of ways to tackle issues like these. I am using this as an example about how to notify your callers that you are about to "renegotiate" your contract in a gentle kind manner!

So, let's say you have a method, called MyShinyMethod that takes two integers and a string as parameters. For 6 months or so that method has sufficed to handle it's intended function. Then one day you get a call from accounting telling you that now you need to handle two integers, 1 string and a double! Ah, you say, no problem and add an overload to your method.

Then, sometime later accounting and marketing call, now the calling programs need to be able to pass 2 doubles, 3 strings, and a boolean and return an XML file.

Ok, you see where this is going, you really can't continue to handle this with overloads, and what you really want to do is change your public interface. But you can't do that, at least not immediately. So we need a way to tell all our callers that we are going to change our interface. In comes the "Obsolete" attribute.

You build a new version of you service, with the existing public methods you had, and you add a new even shinier method called MyNewShineyMethod that is designed to take just about anything and return even more!

Now we need a way to notify existing clients that there is a new method in town, and that the old method will soon be leaving!

Your old method would look something like this:

Public Function MyShinyMethod(ByVal int1 As Integer, ByVal int2 As Integer, ByVal str1 As String) As Boolean
     'do something cool here
     Return True
End Function

 So now you add your new method, and need a way to tell your callers that they should start to use the new method, and get ready to stop using the old one:
 <Obsolete("This method is not so shiny anymore, start using: MyNewShinyMethod")> _ 
Public Function MyShinyMethod(ByVal int1 As Integer, ByVal int2 As Integer, ByVal str1 As String) As Boolean
'do something cool here
Return True
End Function
Public Function MyNewShinyMethod(ByVal params As Collection) As String 
'do something cooler here
Return ""
End Function

Now when users compile their applications that call your service, they will get a warning error if they are using the old version with the text you supplied with the Obsolete attribute. They can still compile run and call the method, but they will begin to see the "error of their ways" in the form of compiler warnings.

Now, eventually you want to be able to "retire" the not so shiny method. Change the attribute as shown below, and instead of warnings, the caller will get Errors!

 <Obsolete("This method is no longer available, use: MyNewShinyMethod instead.", True)> _ 
Public Function MyShinyMethod(ByVal int1 As Integer, ByVal int2 As Integer, ByVal str1 As String) As Boolean
'do something cool here
Return True
End Function
Public Function MyNewShinyMethod(ByVal params As Collection) As String 
'do something cooler here
Return ""
End Function

By adding the "true" parameter we are telling the IDE in the calling applications to flag this as an error and not allow compilation. But the error message shows the caller what to use instead!

Hope this helps!

Cheers,

Robert Porter


 
Comments are closed.