In the first part I tried to set the scene and give you some background of my problem. I’ll try to continue now, and create an interesting and at the same time informative story about performing the refactoring in question.
Most curious of all is that you don’t have to prepare for refactoring. It can happen no matter what, and the price usually isn’t so high after all. Let me remind you – main tool of component design that is dependency injection wasn’t used. Yes, classes do have their responsibilities cleverly defined, and it helps a lot here, because if it weren’t so – whole deal would have to start few steps ‘before’.
I’m not an experienced writer, so I don’t know if I will get the point across, but to me refactoring this was like building level of level of scaffolding, just to use one level to test the next, and at the same time creating scaffolding so it would be used later in a production environment! I guess that there is a name for it, it has to be
Step 1:
Creating a duplicate of the main working class, and see how to force the rest of the application to use it when needed.
Say that class name is PCMHasher, and it has following structure (method declarations only):
class PCM_Hash { public bool Initialize(PCMBufferedReader sourceDataReader); public uint GetNextHash(); }
My goal was to create alternative class to this. I needed the old class to be able to have some reference to get the results from.
So I created class PCMHash_2. That was my first decision – to create same class as before and try to get same results from it, replacing its guts one step at the time.
Using replaced version wasn’t easy, so I took an interface out and derived from it, and created something like:
IPCM_Hash rph; if (!_refactoring) rph = new PCMHash(); else rph = new PCMHash_R2();
At this time I would like to re-state the fact that I am in the production all the time, and have to decide on my feet, having to weight out all the implications that would arise from it. I am telling that because everyone could see that some dependency injection was to be used here. But, apart from having to spend much time installing it through the code, I’m not sure how and if it would work anyway.
Why: at a testing time, I want both classes to be able to function side by side. Concretely, if I have:
class FileHasher { // will use IPCM_Hash implementation somewhere... }
I’ll need:
FileHasher usesOriginal=new FileHasher(); FileHasher usesRefactored=new FileHasher(); usesRefactored.Refactored=true; // compare results object resultFromOriginal=usesOriginal.GetResult(); object resultFromRefactored=usesRefactored.GetResult(); Assert.AreEqual( resultFromOriginal, resultFromRefactored);
Here, the GetResult() method could create new IPCMHash several times, and I am not sure if for example nInject would be able to handle such a thing.
Also, I was toying with an idea to use class factories manually created or send a type of the implementation class in the constructor of the consumer, but that options also faded.
Anyway, there is original class, and there is new refactored class ready to be taken apart and put together again in some different order, preserving functionality that was here before.
Next steps to be added in next editions of the refactoring talks…







