I’m working in a WPF application that both imports and exports delimited text files. At both ends, there is a UserControl which encapsulates some logic about delimiter configuration. It has some controls for individually selecting delimiters, and a ‘Presets’ dropdown for quickly selecting certain common combinations such as CSV.
I’ve been tasked with modifying the export configuration dialog. They want the presets feature modified to also cover some text formatting options that aren’t related to delimiters. The changes should only appear in the export configuration dialog, because the settings in question aren’t applicable to importing. They will involve both adding some new controls, which isn’t too bad. But there will also need to be some additional presets which aren’t available on the import dialog, and their presence may impact the behavior of the dialog overall.
I’m unsure of the best way to do this. Three options come to mind, but of course I might be missing one:
-
Clone the UserControl and make the requisite changes to it. Each dialog now has a separate control. However, both controls will have a lot of logic in common, so I’m uncomfortable with this from a DRY perspective.
-
Keep the single UserControl but throw in a ‘mode’ property. Based on its setting, show or hide certain controls, swap out the ItemsSource for the ‘Presets’ dropdown, etc. This is attractive since it involves less copy-and-paste, but at the cost of the single control being more complicated overall, and perhaps more difficult to maintain on down the road.
-
Redo the whole thing’s architecture so that the behavior-related aspects are properly managed in a separate ViewModel. This new ViewModel should be programmatically configurable to represent the different working modes (basically by just swapping out the list of available Presets, each represented as an instance of a Preset class). Create two different sets of UI to represent the different layouts, with one simply not having the controls for options it doesn’t care about.
My gut instinct is that #3 is the best option. I’m concerned that it’s an excessive effort, though, and that I’m just being too picky about one of the first two options. Or that there’s some other pitfall with it I haven’t thought of. I have a bit of a history with this UserControl and my personal feeling is that it’s kind of a PITA to maintain, so I want to be cautious in case I’m overeager for the rewrite for emotional reasons.
2
Option 1 is the quick and easy solution, and if the logic being duplicated isn’t likely to change, or if any likely change would cause the duplicated logic to diverge, this option makes sense.
In my experience, solutions like option 2 become unwieldy unless you can clearly and simply differentiate the branches for the possible modes. If that’s possible in this situation, take this option, because you get the benefit of easier logical changes (through less code duplication) without the complexity of abstraction.
Option 3 seems to be the ideal solution; however assuming that it will take more time to implement than the other two, it’s worthwhile to guess at the likelihood that you’ll be able to leverage your abstraction for future pages. We obviously can’t know this with certainty, but avoiding unnecessary complexity will simplify maintenance.
With the information given, I would choose option 2 for now, and if any future enhancements require additional modes or forms, refactor to option 3 at that time.
1