I am working on a legacy code base which not only is quite challenging but troublesome as well, sometimes shit, sometimes pleasant, all in all its a roller coaster ride for me. So lately i picked up a task of implementing a feature where in had to provide a functionality of Import and Exporting some data by other indirect means i.e no manual user intervention. Based on my analysis, i found out that this feature is already present for one particular type via GUI intervention. Now i need to replicate this feature as a background activity.
Yes it might sound like what is the big fuss to blog about it? Right, even before writing this blog i though of this point many times. But i did face 1 challenge in solving this problem w.r.t design issue which i am going to share it soon. But before let me give you a brief overview about the current design and then later i shall share how i got stuck for like half day thinking about possible best solution.
Below image shows the current class design:
As you can see from the above hierarchy design structure which looks pretty much good, but for this feature which i am implementing poses a challenge because this feature which is already provided via a manual invocation via GUI menu is only supported for Master Types specifically supported for MasterC type. But unfortunately the earlier developer didn’t see this through well and implemented all the code in base class i.e BaseType.
But the similar feature which i have to implement should only be supported by all Master types which is almost similar to already implemented for MasterC, but remember the full implementation is in BaseType which logically is wrong but i am guessing that original developer didn’t had the requirement at that time of supporting all other derived types, but still it was wrong.
Any way, to implement my feature for all Master Types i had this problem of how to override this already implemented code which is in BaseType. So i came up with couple of possible solution which has pro’s and con’s. Lemme list them below:
- Just move the code (marking that method as virtual and override in MasterC type) which is already implemented for MasterC from BaseType to MasterC, because as of now it just only supported for MasterC as far as i know.
- Very simple and easy to do, but has problems.
- Product is legacy, so its high risk to move it. I never know which corner test case i could break.
- Overriding this feature in MasterC, poses another problem where in, the feature which i am implementing should world in the background as well as same functionality (Import and Export) should work when manually invoked via GUI menu for MasterC.
- So overriding this method for my feature will break the manual intervention feature.
- Implement subclass for this feature for MasterC, lets call the feature as FeatureX, thus naming the class as MasterCFetureX as shown, since MasterC is the odd type here having both features to be supported.
- This way, as thought in solution 1, i can mark that method as virtual and override in MasterCFeatureX to execute a customize version of the same code already implemented for my requirement/feature and when manual invocation is done which is already existing feature for MasterC, then the virtual method in MasterC will get execute. This way, i get what i want and existing functionality is not broken.
- But the problem is, the source where the object MasterC is created based on the menu action is not implemented via any creational patterns viz Factory. If it had been, for this sub menu item action i could create object of MasterCFeatureX an played with it. But since it is not there, implementing such patten at the UI level till business is huge and very risky because changes and impact is huge in terms of effort and time.
- Another problem is the level of hierarchy could grow more, thus making code maintainability tedious.
- Many test cases are risk to be broken if chosen this way. Hence dropped.
- Very simple and straightforward but crude and filthy which i myself still do not like. But i am forced, so that feature gets delivered in time.
- The method which is already implemented BaseType takes an argument (some container from another library). So i added a enum type called ViewFeatureTypes which had None, FeatureX, FeatureY, etc. into this container. Now when i am invoking this call for my feature from View, i set this enum type value in the container and check this value in the code in BaseType.
- This enum can be used in various other places where i am sure such design constraints exists. So for future purposes added Enum than a bool member to this container type.
- As said, very safe and simple yet crude and dirty.
Thanks & Happy Designing,
P.S: Please drop your feedback. I am not a good designer, but see myself there in career. So any suggestions are welcome.