Design principles and testing – part 1
So, to start let’s try and do a quick analysis of exactly what the OnLoad method in our page does in it’s current form.
The OnLoad method
This method fetches some xml-data from another server, process the returned xml and then finally sets properties on some controls.
So what’s the problem with this?
As you can see this method now handles at least two different things, fetching data and formatting it. That means that when you must change either one of those implementations you have to change this method to do it. Let’s say that you want to change the formatting. You then first have to read the whole method to realize that the first part has nothing to do with formatting, just fetching. You then have to be careful that the changes you just made doesn’t affect the fetching part of the method.
Our code would be much more readable and easier to maintain of those different responsibilities were more contained. So let’s create some methods with telling names.
This makes the process of finding what you’re after so much easier. If you, for instance, is faced with the task of changing the way the data is fetched where would your gut feeling tell you to look? A method called GetWeatherData or a method called OnLoad?
It’s also easy to imagine that our page is going to be using other services, perhaps some SetupRssFeed which would make the separation of different concerns even more important.
The single responsibility principle
What we’ve been talking about here is related to the single responsibility principle (SRP) which states “every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class”. It can also be phrased that classes should have just one reason to change.
As you notice this principle talks about classes and I just refactored the code to different methods, but they still belong to the same class. Remember (and this goes for basically everything in this post and the posts to come) that these are principles and guidelines; not rules; and there’s an important difference.
Talking specifically about SRP, it’s also somewhat up to you as a developer to define what “responsibility” means to you, often this can vary depending on context.
Refactoring to comply with SRP
If we wanted to comply with SRP one approach could be the following separation. We create a data abstraction class that represents the data we’re interested in. This is returned from our weather service which behind the scenes works with a weather repository (that fetches xml) and a mapper that maps from xml to the data abstraction.
We can now rewrite the SetupWeather to work with the service, like this
So what does all this moving and creating classes give us?
So, by the looks of it we retain the same functionality but now it’s spread out amongst a lot of classes. Besides the pros we talked about above the code, since we’ve moved it away from code behind, it’s easier to reuse (since sharing code between code behind files can be problematic). This also makes the code behind file less aware of specific implementations. It now talks to some service to get WeatherData but it doesn’t know or care about exactly how that data is fetched and formed.
While this solution might look slightly over-engineered at the moment structuring your code in this manner has other benefits as well which I’ll talk about in later posts.