Applying the Open Closed Principle in Silverlight and WPF using MEF
Posted on | June 29, 2010 | 2 Comments
In this post I want to show how MEF can be used to apply the Open Closed Principle where a class is open for extension but closed for modification.
In the Calculator application we have been building as part of the Silverlight refactoring series we could have used the code below to validate a users input.
By the way we are throwing exceptions because the application is using ValidatesOnExceptions.
public class CalculatorValidator
{
public void ValidateNumber(string value)
{
if (String.IsNullOrEmpty(value))
{
throw new Exception("Please enter a number");
}
int number;
if (!int.TryParse(value, out number))
{
throw new Exception("That's not a number");
}
}
}
If we wanted to add more validation rules to check the value cannot be negative or greater than a hundred we have to modify the CalculatorValidator class with two additional if statements.
public class CalculatorValidator
{
public void ValidateNumber(string value)
{
if (String.IsNullOrEmpty(value))
{
throw new Exception("Please enter a number");
}
int number;
if (!int.TryParse(value, out number))
{
throw new Exception("That's not a number");
}
if (number < 0)
{
throw new Exception("Number cannot be negative");
}
if (number > 100)
{
throw new Exception("That number is too big!");
}
}
}
and this pattern would continue every time you added a new rule, leaving the code as maintainable and stable as a wobbly tower!
Implementing the Open Closed Principle
Lets start by creating an interface for a validation rule
public interface ICalculatorValidationRule
{
bool IsValid(string number);
string ErrorMessage { get; }
}
Next we create a class for each validation rule by implementing the ICalculatorValidationRule interface
[Export(typeof(ICalculatorValidationRule))]
public class ValidateValueIsNotNullOrEmpty : ICalculatorValidationRule
{
public bool IsValid(string value)
{
return !String.IsNullOrEmpty(value);
}
public string ErrorMessage
{
get
{
return "Please enter a number";
}
}
}
[Export(typeof(ICalculatorValidationRule))]
public class ValidateValueIsANumber : ICalculatorValidationRule
{
public bool IsValid(string value)
{
if (!String.IsNullOrEmpty(value))
{
int number;
return int.TryParse(value, out number);
}
return true;
}
public string ErrorMessage
{
get { return "That's not a number"; }
}
}
[Export(typeof(ICalculatorValidationRule))]
public class ValidateValueIsNotNegative : ICalculatorValidationRule
{
public bool IsValid(string value)
{
int number;
if (int.TryParse(value, out number) && number < 0)
{
return false;
}
return true;
}
public string ErrorMessage
{
get { return "Number cannot be negative"; }
}
}
[Export(typeof(ICalculatorValidationRule))]
public class ValidateValueIsLessThanHundred : ICalculatorValidationRule
{
public bool IsValid(string value)
{
int number;
if (int.TryParse(value, out number) && number > 100)
{
return false;
}
return true;
}
public string ErrorMessage
{
get { return "That number is too big!"; }
}
}
An alternative to parsing the value to an integer in the validation rules to check the range would be to order how MEF composes the validation rules and ensure rule to validate the value is an integer is done earlier.
More information about this can be found in answer to this question on Stack Overflow – How does MEF determine the order of its imports?
ImportMany example in MEF
By using the ImportMany attribute on a collection in MEF we can iterate over all of the parts which export the ICalculatorValidatorInterface and check the value passes the validation rule by calling the IsValid method.
If the value is not valid a exception is thrown with the relevant error message.
The code below shows how the CalculatorValidator class would look
public class CalculatorValidator
{
[ImportMany]
public IEnumerable<ICalculatorValidationRule> CalculatorValidationRules { get; set; }
public void ValidateNumber(string value)
{
foreach (var calculatorValidationRule in CalculatorValidationRules)
{
if (!calculatorValidationRule.IsValid(value))
{
throw new Exception(calculatorValidationRule.ErrorMessage);
}
}
}
}
Couldn’t have done it without the extensibility of MEF
If we wanted to add a new validation rule, all we have to do is create another class which implements the ICalculatorValidationRule interface, add an export attribute and MEF will do the rest.
The CalculatorValidator class is now open to extension but closed for modification
SOLID design principles using MEF in Silverlight and WPF
Posted on | June 17, 2010 | 1 Comment
In this part of the Silverlight refactoring series we will be looking at two ways the Managed Extensibility Framework (MEF) can help you refactor Silverlight or WPF applications to follow SOLID design principles.
The code used in this post can be downloaded here.
Apart from saying
through discovery and composition MEF gives you the ability to build applications which will be flexible enough for your every need
I won’t be covering what MEF is or how it works in depth in this post. Instead I recommend checking out the following blogs as well as the MEF site on Codeplex for some great tutorials.
What problem does MEF solve in this application?
The code below shows the Calculate method in the ViewModel.
public void Calculate()
{
Calculator calculator = new Calculator();
Result = calculator.Add(Convert.ToInt32(FirstValue), Convert.ToInt32(SecondValue)).ToString();
}
Notice how Calculator class is created and used within the method. This means there’s no way of changing what class is used for calculations without modifying the code in the ViewModel.
In other words the calculator is tightly coupled to the ViewModel.
Composing, Initializing, Setting up, Bootstrapping, Configuring or whatever you want to call it in MEF
MEF works by using a catalog to discover extensions within assemblies. As the assemblies used in this application are in same XAP we can call the CompositionInitializer SatisfyImports method to automatically configure a container and compose the parts within it.
Looking at the class diagram for the application

we could decide
- only the Calculator class will be an composable part
- the ViewModel and the Calculator will be composable parts
- the CalculatorPage, ViewModel and the class should all be composable parts
As this application only contains a single page we will go with the second option. This means we will be calling the CompositionInitializer SatisfyImport method in the CalculatorPage constructor as shown below
public CalculatorPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
}
Adding MEF Export Attributes
An export attribute is used to make classes and properties discoverable to the catalog and composable by the container.
As the Calculator class is used by the ViewModel we need to add an Export attribute to it. Because the Calculator implements the ICalculator interface we can use this as the contract type.
[Export(typeof(ICalculator))]
public class Calculator : ICalculator
{
public int Add(int firstValue, int secondValue)
{
return firstValue + secondValue;
}
}
Similarly as the ViewModel is used by the CalculatorPage it also needs to be decorated with an Export attribute. As no contract is specified, MEF will use the fully qualified name of the type as the contract.
[Export]
public class CalculatorViewModel : INotifyPropertyChanged
{
.....
}
An important thing to remember is that the export attribute is not allowed on the instance passed to SatisfyImports otherwise you will see the error below

Using MEF Property Imports
To use property imports in MEF we need to add a Calculator property to the ViewModel add decorate it with an Import attribute. In Silverlight MEF requires the property to be public.
[Import]
public ICalculator Calculator { get; set; }
The Calculate method in the ViewModel uses the property like this
public void Calculate()
{
Result = Calculator.Add(Convert.ToInt32(FirstValue), Convert.ToInt32(SecondValue)).ToString();
}
In the code behind of the CalculatorPage we need to add a CalculatorViewModel property, decorate it with an Import attribute and set it as the data context.
public partial class CalculatorPage : UserControl
{
[Import]
public CalculatorViewModel CalculatorViewModel { get; set; }
public CalculatorPage()
{
InitializeComponent();
CompositionInitializer.SatisfyImports(this);
DataContext = CalculatorViewModel;
}
}
If we run the application as it is MEF composes all the parts of the application and we are able to add numbers together… which is good but not great because I don’t recommend you should build applications only using property imports.
Using MEF Constructor Imports
I always try to follow the SOLID design principles whenever I’m developing applications.
The D in SOLID design principles stands for Dependency Inversion Principle.
One of the first things you should be taught when learning test driven development or even good coding practices is how SOLID design principles will help you create applications that are easier to develop, configure, maintain and unit test.
See my blog post ‘How to write better unit tests using RhinoMocks and stubs‘ for an example.
The good news is MEF supports constructor imports.
Using the ImportingConstructor attribute the CalculatorViewModel now takes in a Calculator in its constructor as shown below
[ImportingConstructor]
public CalculatorViewModel(ICalculator calculator)
{
_calculator = calculator;
...
}
and the calculate method uses the calculator like this
public void Calculate()
{
Result = _calculator.Add(Convert.ToInt32(FirstValue), Convert.ToInt32(SecondValue)).ToString();
}
Take care not to over engineer
So what about the importing the ViewModel in the CalculatorPage? We could stick to using a property for the ViewModel or pass it in the ViewModel constructor (in which case the call to CompositionInitializer SatisfyImports method will have to done in the App.xaml code behind).
I would be inclined to leave it as it is. Because we want to be able to unit test the ViewModel it makes sense to use importing constructors so we stub out the calculator.
Are we ever going to unit test the CalculatorPage? Probably not, and if we do need to, it’s not a major refactoring task.
In any case thanks to MEF the ViewModel can be changed without modifying the code behind for the CalculatorPage.
So what have we achieved?
By using SOLID design principles and MEF we have managed to remove the tight coupling between the ViewModel and the Calculator.
There is a lot of discussion about what MEF is in the development community. Despite numerous claims and comments that it’s not a dependency injection framework, I can’t help thinking it takes a step closer to being one with each release.
The last thing I’ll say about MEF is that
the number of options you have of using MEF is either impressive or confusing depending on what side of the fence you sit on
If you have arrived here from a search engine, this post is part of series about refactoring Silverlight applications.
So if you’re thinking, what if there’s an exception converting a string into an integer, check out the post ‘Validation in Silverlight and WPF using ValidatesOnExceptions‘ which shows one approach in solving this problem using exceptions.
How to Apply the Single Responsibility Principle to View Models in Silverlight and WPF
Posted on | June 14, 2010 | No Comments
When you’re using the MVVM pattern with WPF or Silverlight it’s very easy to a have ViewModels that do too much.
In this part of the Silverlight Refactoring series we will convert a ViewModel with multiple responsibilities so that it adheres to the Single Responsibility Principle (SRP).
The code used in this post can be downloaded here.
Why should you care?
Currently the ViewModel looks like this
using System;
using System.ComponentModel;
using System.Windows.Input;
namespace SilverlightCalculator
{
public class CalculatorViewModel : INotifyPropertyChanged
{
private string _firstValue;
private string _secondValue;
private string _result;
private readonly ICommand _calculateCommand;
public event PropertyChangedEventHandler PropertyChanged;
public CalculatorViewModel()
{
_calculateCommand = new RelayCommand(Calculate){IsEnabled = true};
}
public void Calculate()
{
Result = (Convert.ToInt32(FirstValue) + Convert.ToInt32(SecondValue)).ToString();
}
public string FirstValue
{
get { return _firstValue; }
set
{
_firstValue = value;
OnPropertyChanged("FirstValue");
}
}
public string SecondValue
{
get { return _secondValue; }
set
{
_secondValue = value;
OnPropertyChanged("SecondValue");
}
}
public string Result
{
get { return _result; }
private set
{
_result = value;
OnPropertyChanged("Result");
}
}
public ICommand CalculateCommand
{
get { return _calculateCommand; }
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
}
As you can see the logic to add two numbers is in the Calculate method of the ViewModel.
Therefore the ViewModel is responsible for calculating two numbers.
A ViewModel without separation of concerns is difficult to test, maintain and contains code you can’t reuse.
Although we’re only adding two numbers here, brushing the issue under the carpet will have consequences later down the line.
For example in addition to adding numbers what if another developer was given the task of storing the result in a database.
If the ViewModel was as it is now, with no separation of concerns, there is a chance they would put the code to store the value in the calculate method like this
public void Calculate()
{
// Calculate result
Result = (Convert.ToInt32(FirstValue) + Convert.ToInt32(SecondValue)).ToString();
// Store value in database
DatabaseConnection connection = new DatabaseConnection();
DatabaseCommand command = new DatabaseCommand("TSQL TO STORE RESULT", connection);
command.ExecuteNonQuery();
}
Now the ViewModel would be responsible for two things. Next it would be three and this would continue until someone decides to separate the concerns or it gets to a stage where it’s impossible to work with let alone read.
Refactoring the ViewModel to follow the single responsibility principle
Let’s start by creating a class for calculating numbers.
public class Calculator
{
public int Add(int firstValue, int secondValue)
{
return firstValue + secondValue;
}
}
Notice how the parameters passed to the method are integers, the calculator doesn’t accept string values.
What we are saying here is while it’s acceptable for the ViewModel to use strings for storing numbers the domain layer (or business logic if you prefer) does not.
In other words the add method does nothing more than add two numbers together. Validation should be handled elsewhere.
This makes the unit tests for the calculator very easy to write
[TestFixture]
public class When_calculating_numbers
{
[Test]
public void Should_be_able_to_add_two_numbers_together()
{
// Arrange
Calculator calculator = new Calculator();
// Act
var result = calculator.Add(5, 5);
//Assert
Assert.That(result, Is.EqualTo(10));
}
}
The code below shows how the ViewModel could create an instance of the Calculator class and call the Add Method. Notice how I say could and not should. We’ll see why later in the series.
public void Calculate()
{
Calculator calculator = new Calculator();
Result = calculator.Add(Convert.ToInt32(FirstValue), Convert.ToInt32(SecondValue)).ToString();
}
So what have we achieved?
As good boy scouts we have ‘left the ViewModel cleaner than we found it’.
By following the single responsibility principle we have created a ViewModel which is a better canvas for other developers to work with.
If you have arrived here from a search engine, this post is part of series about refactoring Silverlight applications. So if you’re thinking why is the calculator class tightly coupled to the ViewModel? Find out how this can be resolved by applying SOLID design principles using MEF in Silverlight and WPF.
How to Implement MVVM, INotifyChanged and ICommand in a Silverlight Application
Posted on | June 10, 2010 | 6 Comments
In this post we will be converting an application that adds two numbers together to use the MVVM (Model-View-ViewModel) pattern as part of the How To Refactor And Build Better Microsoft Silverlight Applications series.
The code used in this post can be downloaded here.
Why MVVM?
While I could write about what MVVM is, I would just be repeating what Josh Smith and Jesse Liberty have already covered in the ‘WPF Apps With The Model-View-ViewModel Design Pattern’ MSDN article and the ‘MVVM – It’s Not Kool-Aid*’ blog post.
I like the MVVM pattern because it helps me to write code and develop solutions that:
- keeps my code behind files as code free as possible
- can be unit tested
- are simpler to read and understand
- are less headache to maintain
- adhere to good programming principles
- make validation easier to implement
It’s important to remember MVVM isn’t the solution to every problem. If you don’t need to use it, don’t, do whatever is right for your application.
The application pre MVVM
In the current application the XAML looks like this
<Grid x:Name="LayoutRoot" Background="White" Height="100" Width="350">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Grid.Column="0" Text="0" Height="25" TextAlignment="Right" x:Name="tbFirstValue"/>
<TextBlock Grid.Column="1" Text="+" Height="25" TextAlignment="Center"/>
<TextBox Grid.Column="2" Text="0" Height="25" TextAlignment="Right" x:Name="tbSecondValue"/>
<TextBlock Grid.Column="3" Text="=" Height="25" TextAlignment="Center"/>
<TextBlock Grid.Column="4" Text="0" Height="25" TextAlignment="Left" x:Name="tbResult"/>
<Button Grid.Row="1" Grid.ColumnSpan="5" Margin="0,5,0,0" Content="Calculate" x:Name="btnCalculate" Click="btnCalculate_Click" />
</Grid>
and the code behind looks like this
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void btnCalculate_Click(object sender, RoutedEventArgs e)
{
tbResult.Text = (Convert.ToInt32(tbFirstValue.Text) + Convert.ToInt32(tbSecondValue.Text)).ToString();
}
}
It’s all about the ViewModel
The name of the ViewModel for this application will be CalculatorViewModel.
If you follow the convention of naming the ViewModel using the name of the consumer who will be using it, knowing what the ViewModel is used for is easier as the application grows.
This will also help to ensure you do not use the same ViewModel for multiple controls, something which is considered to be a best practice.
Setting the CalculatorViewModel as the data context of the Silverlight user control is usually done in one of two ways (some people implement service locators or use a provider).
setting the ViewModel as the DataContext in the code behind
public CalculatorPage()
{
InitializeComponent();
DataContext = new CalculatorViewModel();
}
or setting the ViewModel as the DataContext in XAML
<UserControl.DataContext>
<local:CalculatorViewModel/>
</UserControl.DataContext>
INotifyChanged
By implementing the INotifyChanged interface (or inheriting from a base class which implements it), events can be raised when a property value changes.
For the calculator example events will be used to update the user interface when the values for the two input numbers or the calculated result change.
The code below shows how the OnPropertyChanged method is called in the property setters to raise the PropertyChangedEventHandler.
private string _firstValue;
private string _secondValue;
private string _result;
public event PropertyChangedEventHandler PropertyChanged;
public string FirstValue
{
get { return _firstValue; }
set
{
_firstValue = value;
OnPropertyChanged("FirstValue");
}
}
public string SecondValue
{
get { return _secondValue; }
set
{
_secondValue = value;
OnPropertyChanged("SecondValue");
}
}
public string Result
{
get { return _result; }
private set
{
_result = value;
OnPropertyChanged("Result");
}
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
The next step is to change the text controls in the XAML file to bind to the properties in the ViewModel
<TextBox Grid.Column="0" Text="{Binding FirstValue, Mode=TwoWay}" Height="25" TextAlignment="Right"/>
<TextBlock Grid.Column="1" Text="+" Height="25" TextAlignment="Center"/>
<TextBox Grid.Column="2" Text="{Binding SecondValue, Mode=TwoWay}" Height="25" TextAlignment="Right"/>
<TextBlock Grid.Column="3" Text="=" Height="25" TextAlignment="Center"/>
<TextBlock Grid.Column="4" Text="{Binding Result, Mode=OneWay}" Height="25" TextAlignment="Left"/>
Notice how the binding mode on the text boxes are two way but the result text block is only one way.
We need to use a two way binding to be able to update the ViewModel with the values the user enters.
As the user cannot enter a value in the result text block the binding only needs to be one way.
If you want more information about data binding check out the Data Binding Overview article on MSDN.
Commands in Silverlight 4
New in Silverlight 4 are commands (WPF already had them). Commands enable us to replace the click event for the calculate button in the XAML file with a command as shown below.
<Button Grid.Row="1" Grid.ColumnSpan="5" Margin="0,5,0,0" Content="Calculate" Command="{Binding CalculateCommand}" />
The command binds to a CalculateCommand property in the ViewModel which looks like this
private readonly ICommand _calculateCommand;
public ICommand CalculateCommand
{
get { return _calculateCommand; }
}
So how does the command know what to do?
The answer is by using a RelayCommand (which implements the ICommand interface) and passing a method (which adds two values together) in its constructor. A relay command allows for cleaner command implementation in ViewModel classes.
The code for the RelayCommand is shown below (I can’t take any credit for this as I’ve taken it from Josh Smiths MSDN article).
public class RelayCommand : ICommand
{
private Action _handler;
public RelayCommand(Action handler)
{
_handler = handler;
}
private bool _isEnabled;
public bool IsEnabled
{
get { return _isEnabled; }
set
{
if (value != _isEnabled)
{
_isEnabled = value;
if (CanExecuteChanged != null)
{
CanExecuteChanged(this, EventArgs.Empty);
}
}
}
}
public bool CanExecute(object parameter)
{
return IsEnabled;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_handler();
}
}
The code below shows the calculate method and how the relay command is set up in the ViewModels’ constructor
public CalculatorViewModel()
{
_calculateCommand = new RelayCommand(Calculate){IsEnabled = true};
}
private void Calculate()
{
Result = (Convert.ToInt32(FirstValue) + Convert.ToInt32(SecondValue)).ToString();
}
So what have we achieved?
Given that all we are doing here is adding two numbers together the effort of implementing the MVVM pattern looks to be a lot of work.
The important thing to take away is what an MVVM ViewModel looks like without the use of any third party frameworks such the MVVM Light Toolkit. The code in this post only uses the libraries that ship with Microsoft Silverlight 4.
The class diagram for the ViewModel looks like this

and the complete code listing for the ViewModel is shown below
using System;
using System.ComponentModel;
using System.Windows.Input;
namespace SilverlightCalculator
{
public class CalculatorViewModel : INotifyPropertyChanged
{
private string _firstValue;
private string _secondValue;
private string _result;
private readonly ICommand _calculateCommand;
public event PropertyChangedEventHandler PropertyChanged;
public CalculatorViewModel()
{
_calculateCommand = new RelayCommand(Calculate){IsEnabled = true};
}
private void Calculate()
{
Result = (Convert.ToInt32(FirstValue) + Convert.ToInt32(SecondValue)).ToString();
}
public string FirstValue
{
get { return _firstValue; }
set
{
_firstValue = value;
OnPropertyChanged("FirstValue");
}
}
public string SecondValue
{
get { return _secondValue; }
set
{
_secondValue = value;
OnPropertyChanged("SecondValue");
}
}
public string Result
{
get { return _result; }
private set
{
_result = value;
OnPropertyChanged("Result");
}
}
public ICommand CalculateCommand
{
get { return _calculateCommand; }
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(propertyName));
}
}
}
}
With the foundation code in place adding additional properties or commands is easy.
While MVVM can be used and implemented in the wrong way (as with every pattern), by applying good software craftsmanship skills a Silverlight or WPF application using the MVVM pattern will encourage you to adopt best practices (as we will see later in the series).
If you have arrived here from a search engine, this post is part of series about refactoring Silverlight applications. So if you’re thinking calculating numbers this way is a ‘code smell’, see how this can be resolved by applying the Single Responsibility Principle to View Models in Silverlight and WPF.
How To Refactor And Build Better Microsoft Silverlight Applications
Posted on | June 10, 2010 | No Comments
As with all development technologies if you asked two developers how to solve a problem it’s unlikely both would come up with the same solution.
It’s no surprise then the same solution to a problem using Silverlight and WPF applications can be implemented in a number of ways.
In a series of posts I want to show how we can refactor a Silverlight application which “works” to be a lot cleaner, easier to maintain and adheres to good development practices.
Although I’m using Silverlight many of the changes and suggestions would also apply to a WPF application.
So what’s the application?
The application adds two numbers together.

Yes that’s it. Click here to see a live demo of the calclator.
Using a simple example (as opposed to a huge complex monster) allows us to focus on refactoring and making improvements rather than trying to understand what the application is doing and wading through hundreds of lines of code.
So what’s wrong with it?
The XAML is shown below
<Grid x:Name="LayoutRoot" Background="White" Height="100" Width="350">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBox Grid.Column="0" Text="0" Height="25" TextAlignment="Right" x:Name="tbFirstValue"/>
<TextBlock Grid.Column="1" Text="+" Height="25" TextAlignment="Center"/>
<TextBox Grid.Column="2" Text="0" Height="25" TextAlignment="Right" x:Name="tbSecondValue"/>
<TextBlock Grid.Column="3" Text="=" Height="25" TextAlignment="Center"/>
<TextBlock Grid.Column="4" Text="0" Height="25" TextAlignment="Left" x:Name="tbResult"/>
<Button Grid.Row="1" Grid.ColumnSpan="5" Margin="0,5,0,0" Content="Calculate" x:Name="btnCalculate" Click="btnCalculate_Click" />
</Grid>
and this is what the code behind looks like
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void btnCalculate_Click(object sender, RoutedEventArgs e)
{
tbResult.Text = (Convert.ToInt32(tbFirstValue.Text) + Convert.ToInt32(tbSecondValue.Text)).ToString();
}
}
As it stands the application:
- Contains code in the code behind file. OK it’s not so much of an issue for this example and is down to individual preference, but this can quickly become a nightmare to maintain during the life of an application
- Isn’t unit testable – we can’t test two values can be added together
- Has no separation of concerns – the code behind shouldn’t be responsible for adding the numbers together
- A lot of repetition for the styling of the input boxes – if we wanted to make the input boxes bigger we would have to make multiple changes, ideally changes should only need to be made in one place.
- No validation – if the user enters alphabetical characters into application and hits the calculate button the application crashes
So how are we going to improve it?
By taking an agile approach the aim at the end of each refactoring is to have a releasable application i.e. be able to add two numbers together. Therefore each refactoring will involve small incremental changes.
After each refactoring exercise we will review the application to see what improvements have been made and if any new problems have been introduced…
-
Step 1: Implement the MVVM (Model-View-ViewModel) pattern to reduce the amount of code in the Silverlight code behind file and follow some best practices for Silverlight development
Review: The code behind file looks much cleaner now, thanks to the use of commands and the INotifyChanged interface, but should the ViewModel be responsible for calculating the two numbers together? -
Step 2: Remove the responsibility and concerns for calculating numbers in the ViewModel
Review: This refactoring has allowed us to reduce the responsibility of the ViewModel and unit test we can add two numbers together, but we are tightly coupled to the calculator class. -
Step 3: Using SOLID design principles and MEF to remove tight coupling
Review: The application is now made up of loosely coupled components which give us a good platform to build upon. But without any validation of what a user enters for a number the application isn’t very stable. -
Step 4: Validating what the user has entered using exceptions
Review: If the users input is not valid they are now are shown an error message. This is all very well but the user is still able to click the calculate button even if they have entered invalid values to add together. -
Step 5: Validating what the user has entered using exceptions and disabling the calculate button if there are any validation errors
Review: The user is only able to click the calculate button when there are no validation errors. Even though throwing exceptions for validation works, some developers aren’t so keen on doing this so what are the alternatives? -
Step 6a: Validating what the user has entered using IDataErrorInfo
Review: By implementing the IDataErrorInfo interface we are able to do validation without throwing exceptions. -
Step 6b: Validating what the user has entered using INotifyDataErrorInfo
Review: By implementing the INotifyDataErrorInfo interface we are able to do validation without throwing exceptions.