WDTA= "What Does This Affect".
Yup. Came up again. Other developers came to me with a classic engineering problem (One of those, "Uhh, we think we shot ourselves in the foot", how do we fix it" kind of deals).
They were storing Xml documents that represent classes in the database in string form. Problem is, they didn't add a column to show the Version of the class / xml that was stored.
And of course, one ambitous developer modified the class in their DAL, and now when they retrieve the Xml, deserialization fails. He didn't ask that magic four word question that developers should ALWAYS ask when making a code change: "WHAT DOES THIS AFFECT?".
What's the answer? A simple answer is to add a column to the table that specfies the class version that is stored in the varchar or Text field of the table, and to mirror this
in some sort of constant string field in the class that is to represent the deserialized xml string. So when you pull the xml out of the database, you will automatically know which class it is supposed to be deserialized into. A better solution would be to store the assembly namespace.classname as the unique key. This way, you could even load the assembly dynamically at runtime if you needed to. For example you could have MyDALJunk.ClassDoSomethingCool1, MyDALJunk.ClassDoSomethingCool2, etc. as the version column items in the database table, and the compiled assemblies on the filesystem for these classes would be named exactly the same.
As far as matching up old records with new, I suppose you could write an XML -> XML XSL Transform to map the old documents into the new, or if it is simple, you could just eyeball the old guys and "Fix them up" by hand, and re-save them.
In this particular case it seems the "new" xml just has new elements but they aren't populated (yet). So the easy answer is to grab a dataset of the records that need to be changed, deserialize each row's xml column into an instance of the "old" class, then create an instance of the "new" class and do a node-for-node replacement, then serialize the "new" class and update the row in the database with it.
And of course, as one intelligent commenter has already posted, we could have unit tests too. I didn't even mention this in the original post, even though I recently wrote a review of James Newkirk's excellent new MS Press book on TDD. But of course, you need to be able to crawl before you can walk, and for a lot of developers, asking them to create and maintain test fixture code for NUnit is like asking a baseball player not to spit.
But the bottom line message is simple: Ask the magic question "What Does This Affect" whenever you are going to change code. Then you won't have to spend as much time going backwards, right?
They were storing Xml documents that represent classes in the database in string form. Problem is, they didn't add a column to show the Version of the class / xml that was stored.
And of course, one ambitous developer modified the class in their DAL, and now when they retrieve the Xml, deserialization fails. He didn't ask that magic four word question that developers should ALWAYS ask when making a code change: "WHAT DOES THIS AFFECT?".
What's the answer? A simple answer is to add a column to the table that specfies the class version that is stored in the varchar or Text field of the table, and to mirror this
in some sort of constant string field in the class that is to represent the deserialized xml string. So when you pull the xml out of the database, you will automatically know which class it is supposed to be deserialized into. A better solution would be to store the assembly namespace.classname as the unique key. This way, you could even load the assembly dynamically at runtime if you needed to. For example you could have MyDALJunk.ClassDoSomethingCool1, MyDALJunk.ClassDoSomethingCool2, etc. as the version column items in the database table, and the compiled assemblies on the filesystem for these classes would be named exactly the same.
As far as matching up old records with new, I suppose you could write an XML -> XML XSL Transform to map the old documents into the new, or if it is simple, you could just eyeball the old guys and "Fix them up" by hand, and re-save them.
In this particular case it seems the "new" xml just has new elements but they aren't populated (yet). So the easy answer is to grab a dataset of the records that need to be changed, deserialize each row's xml column into an instance of the "old" class, then create an instance of the "new" class and do a node-for-node replacement, then serialize the "new" class and update the row in the database with it.
And of course, as one intelligent commenter has already posted, we could have unit tests too. I didn't even mention this in the original post, even though I recently wrote a review of James Newkirk's excellent new MS Press book on TDD. But of course, you need to be able to crawl before you can walk, and for a lot of developers, asking them to create and maintain test fixture code for NUnit is like asking a baseball player not to spit.
But the bottom line message is simple: Ask the magic question "What Does This Affect" whenever you are going to change code. Then you won't have to spend as much time going backwards, right?
Unit Test. That way, you can ask your tests what your change affects, and have a reasonable chance of not screwing stuff up.
ReplyDeleteAmen, Brother.
ReplyDelete