Tuesday, November 10, 2009

The Learning Cliff

Been pounding away at Signaller, trying to re-do it using some semblance of structure, using the MVVM (Model - View - ViewModel) Pattern and Unity, neither which I knew anything about 2 weeks ago, but seem to provide the way forward. Of course, I've never really made a huge application before, so at least I don't have so much to unlearn...

I've made about 4 attempts at making this before, but I fell off the learning cliff.
I don't consider them failures because I tended to concentrate on different areas in each one, which carries forward into the next attempt.

This one so far is far better structured and elegant, and should prove easier to update.

A example:

On sim editor screen, I wanted the Title to display one of two things:

1: Default:
"Simulation Editor - New Simulation"

2: If the sim has a Name:
Simulation Editor - " + SimulationName

Naive Method:
Every time some code changes the SimulationName,

set the Window.Title to a new string, ie
StartScreen.Title = Simulation Editor - " + SimName;

This will work, but has to be inserted EVERYWHERE the name changes, which means that the class must know about the StartScreen instance, even pure data classes. A pain to maintain or change, as now a whole bunch of classes depend on StartScreen existing, and having a property named Title, which takes a string.
If that changes, you have to change the code everywhere, which especially in a team environment, might be a class you have no control of.

2nd Approach, using WPF Data binding (And my first attempt!)
Bind StartScreen directly to the Title property on the Data object, and use a Converter in the code-behind to create the appropriate string. Have the Data object implement INotifyPropertyChanged, and call NotifyPropertyChanged in the Data.SimulationName's setter. When the name changes, the StartScreen's binding recieves the change notification, and changes the title as necessary.
The data object now doesn't need to know (or care) about the Window,
but the Window is still dependent on the Data object, and the binding is a bit funky.




Lucky I have control of the data object, so I could add the NotifyPropertyChanged.
What if I didn't, if it was some old legacy library, that I couldn't edit?


Enter the MVVM pattern.
What it attempts to do is remove the dependencies between the View and the Model, and make your application cleaner, more flexible, easier to change and update, and unit-testable.

Before, I had:
Model: The ModelData object
View: The StartWindow.


Since the two were dependent on each other, a change in one might require a change in the other. If say the Model was dependent on other classes as well, then a change in the View could cause a cascade of changes in many classes, that are completely unrelated to the visual View.


With MVVM it adds a ViewModel in between the two. The ViewModel, is sort of like a super adapter between the two, The View simply binds to properties on the ViewModel ie Title="{Binding StartScreenTitle}. All the view needs is to set the Window.DataContext to the ViewModel. The view can exactly the data it wants in exactly the form it wants, and it doesn't depend on the data model at all.

For the StartScreen, its pretty trivial. As the complexity increases though, MVVM starts to make sense.


But for something like the Editor screen, well, I want to be to be able to create different signalling control systems.
Given a base set of data about tracks\signals, etc. plug that into whatever Visual representation (be it IECC, a mosaic panel, lever frame etc)
If I have a series of modules that provide the visuals etc, something like
SystemIECC.dll, SystemPanel.dll, or something, They would each have data on top of the base data that was only related to the Visual part. The interface for editing the visual portions would all be fairly different.

The naive method (And first thing I thought of! ;D ) was to make a series of Editor Windows, one for each of the Visual types I wanted to use.
That's a lot of duplication, and I'd have to create new windows everytime a new System*.dll is created. It would be possible, but be a complete pain to maintain and update. There would be lots of data that would only be appropriate to a specific signalling control technology, or to put it another way, to the View.
The base data shouldn't have to be changed to support a new module, with stuff that that only applies to specific cases.

Now, what If I have just one Editor window, but inject it with the appropriate VisualModel for the appropriate control system. The ViewModel holds all the View-specific data, and the underlying data Model isn't changed.
 
I've barely scratched the surface of what MVVM and dependecy  injection offers, I'm still trying to get my head around it too!

No comments: