I am working on a Wpfapplication developed in a WinForms style; I am saying this because application consists –
- UserControls having more then 2000 lines of code (without any regions, members scattered all over the class). No separation of concerns whatsoever.
- UserControls having ~1000 lines of code and corresponding ViewModel having another 1000 lines of code.
- UserControls having a lot of event handlers (some having > 25).
- UserControls having nested classes.
- UserControls implementing INotifyPropertyChanged and having DP’s.
- Lot of unused classes/code (although referenced/used in code but not doing anything);
- More then 30 MultiValue converters and 40 value converters.
- Converter instances are used frequently in code behind/VM.
- Few MultiValue converters
- having hundreds of lines of code (few having upto 400 lines of code).
- having business logic inside them.
- creating the ViewModel instances.
- having Nested classes.
- exposing methods used by user controls in code behind.
- exposing properties used by user controls in code behind and view models.
- having static methods returning observable collections/Lists, used by other converters & View Models.
- exposing events, subscribed by UserControl’s and view model’s.
- Implementing IDisposable.
- Converters are used extensively to create/set the DataContext and ItemSources of controls/ListViews/DataGrids:
like this –
<Editor:EditorControl.DataContext>
<MultiBinding Converter="{StaticResource EditorControlModelConverter}">
<Binding
ElementName="UserControl"
Path="RefId" />
<Binding
ElementName="UserControl"
Path="CollectionView.SelectedScenario" />
<Binding
ElementName="UserControl"
Path="ParentComponentName" />
</MultiBinding>
</Editor:EditorControl.DataContext>
and this –
<ListView.ItemsSource>
<MultiBinding Converter="{StaticResource ItemsSourceInsertConverter}">
<Binding
ElementName="EditorControl"
Path="EditorControl.ContextListEnabled" />
<Binding
ElementName="EditorControl"
Path="EditorContainer.ParentComponent.Model.ModelList" />
<Binding
ElementName="EditorControl"
Path="EditorContainer.ParentComponent.Model.CategoryModelList" />
<Binding
ElementName="EditorControl"
Path="EditorContainer.ParentComponent.Model.ItemSortOrder" />
<Binding
ElementName="EditorControl"
Path="IsItemSourceMatrixInsertConverterSuspended" />
<Binding
ElementName="EditorControl"
Path="EditorControlModel.IsUpdating" />
<Binding
ElementName="EditorControl"
Path="EditorControlModel.ContextListEnabledInitialized" />
<Binding
BindsDirectlyToSource="true"
ElementName="listView" />
<Binding
ElementName="EditorControl"
Path="EditorControlModel" />
<Binding
ElementName="EditorControl"
Path="EditorContainer.Plugin.FeatureManager.EditorCategoryFeatureEnabled" />
<Binding
ElementName="EditorControl"
Path="EditorContainer.Plugin.FeatureManager.EditorMatrixFeaturesEnabled" />
</MultiBinding>
List goes on…Has any one of you faced similar situation and how you dealt with it? what approach should be taken to refactor this kind of application for better performance and maintainability?
Update:
Answer of Andrew’s Q – “Why we need to refactor this”:
-
Performance – we are not happy with the performance of our application and feel it should be better(considering the functionality and usability).
-
Better Extensibility : we are still in early stages of our product and know that a lot of new features needs to be added in future; but looking at the current code base it looks tough and may break old functionality.
-
Better Maintainability : It will be tough to maintain a non standards-compliant/ tricky/hacky code in future(it’s very imp. as we see this product running for years to come).
I’d ask the question why do you need to refactor this? if the answer is “So its standards compliant”, “It looks better” or “So our development team is happy” then I’d seriously reconsider doing it.
If the answer is “Because we are unable to meet business needs due to difficulty of changing/updating our application” then you have a valid business reason.
I’ve worked on many projects where my first instinct was to scrap and rewrite it. Many of those I did actually scrap and rewrite, only to find out half way through that the original developers, while they didn’t do it the way I would (or even had poor coding standards) had fixed a lot of issues I’d never considered!
Similarly I’ve worked on one or two where a rewrite or deep refactor had a strong business reason and the outcome was a success. Nevertheless its always painful to make these changes.
So. In conclusion, if I had to do this due to a strong business need, I would probably start by creating a test script (manual testing) or better yet, automated tests (UI or UNit Tests, doesnt matter) which coarsely test the functionality of your application.
Then I would take Views in turn and creating ViewModels for them, moving functionality out to ViewModels. For instance, moving the dependency properties & INotifyPropertyChanged to a VM.
I would then look at Dependency Injection e.g. StructureMap to wire up dependencies required into those viewmodels or some other method to keep coupling low.
These techniques and others are outlined in the book, Brownfield Application Development in .NET.
Finally I would look back in glory at my pretty code which does half the features that the old application did. Joke! Ok this last part was facecious, I do think there are many reasons why this is a very good thing (refactoring), however I have learned from bitter experience to not take these decisions lightly.
Best regards!