Categorized | Code, Development

Setting up a maintainable windows phone development project in Visual Studio 2008

In this post i share what is my experience, and what i have found to work for me as a best practice for setting up my projects and software structure when developing windows phone applications in Visual Studio 2008.

Basically I am  applying some Model-View-Presenter principles tweaked for simplicity and dividing the different parts into separate projects.

The Model-View-Presenter software design pattern is in my opinion the easiest pattern to use. It is also easy to get going with if you`re not familiar with the jungle of three or four letter acronym patterns and support frameworks available.

Patterns are important and you should use them! By applying, in this case a MVP pattern we can easily handle the rapid changes in new hardware, screen form factors, UX requirements and connectivity requirements to back-end systems.

Other software design patterns exists and they can do the same thing and more, but the MVP pattern is simplistic, easy to understand and to implement. It also (if implemented correctly) ensures testability.

Model-View-Presenter pattern overview
As you will see later; each application form is a view. Each view sends and receives data through a presenter and the presenter is responsible for delivering the correct data required by the view. The presenter acts as a data broker between the back end model that communicate with back end databases and/or web services etc. and the front end view that is communicating with the end user.

mvp

The most effective implementation of this pattern is by creating a 1:1 mapping for object:interface. Meaning that for each view you have a view interface, for every presenter a presenter interface and for each model object there is a model interface.

There is no specific requirements regarding the use of application level events in this pattern besides that events must follow the data flow set in the design pattern. A model interface can expose events to be consumed by a presenter, a presenter can expose events for the view to consume, and the presenter can subscribe to events from the view.

Setting up the Visuals Studio 2008 solution
visualstudio2008When you are setting up Visual Studio 2008 for development you do this with a base set of 4 core projects which will be the foundation of your application. By applying this layering you create a solution that is easy to maintain and extend, this is valuable if you should need to re-design the application for a different mobile form factor or screen size. And it would be easy to replace the concrete implementation of the model if you are to use a different communication platform in the application or different back-end database system.

The next section shows in detail how you divide your solution and what you place where.

Mobile.[ProjectName].MVP
The MVP project is created as a Library project type and is the skeleton for your application. In this project you create 3 subfolders named “Model”, “View” and “Presenter”.

My opinion on the best practice for naming conventions for interfaces is that every interface name should be prefixed with an upper case “I” to indicate that it is an interface.

There are different views on the topic of prefixing interfaces. The upper case “I”  is one opinion, another one, popular in the Java community is that you do not prefix interfaces and rather have an “impl” suffix on your concrete implementation classes. Example of this would be that you have a Login interface and a LoginImpl concrete class implementation, but I have found that prefixing interfaces makes more sense to me.

The skeleton project; Mobile.[ProjectName].MVP should NOT have any bindings to concrete hardware or software modules in code or thrugh references. This is to be implemented inside the concrete view or model projects.

Mobile.[ProjectName].MVP parts
The next section is a detailed explanation on how the MVP  skeleton is implemented.

Model
In the model folder you place interfaces for retrieving data and sending data to the backend domain, this needs to be generic and should contain data access factory interfaces, communication factory interfaces etc.

public interface ILoginModel
{
     Bool UserAuthenticated(string user, string password);
     SomeObject GetPreConditions();
}

View
In the view folder you place the view interfaces. There must be an interface for each main application form. Each view interface name should be named logically for its use with a naming pattern like I<function>View. For instance an interface for your login screen will be named ILoginView and product detail view should be called IProductDetailsView.

ViewData/SaveData and View requirements
A view will have some requirements for initial data upon presentation and also return some changed or processed data that it wants to deliver up the application stack.  It might have need of localized resources like language spesific label texts, it might need a list of data the user is to do a selection from, or it is the product details to display on a product details form. This is what we call “ViewData” and “SaveData”. These requirements are defined in a view interface using generics.

public interface ILoginView<TViewData, TSaveData> { … }

You do not need to define both view and/or save data. Define those your view requires. The advantage of this is that you can havecustom view/savedata for each concrete implementation of the view interface, giving great flexibility. The constraint is that the concrete implementation of your presenter needs to know what this “custom” view/save data is throughout its lifecycle.

We’ve found that defining a BaseViewData class inside the Mobile.[ProjectName].View namespace ensures that it is always available.

The BaseViewData class encapsulates everything that is a common requirement for all views. This could i.e. be a text source reader for language specific UI labels amongst others.
Inside the view interface file we create a concrete ViewData class for that specific view that extends the BaseViewData. The same can/should be done if there are common SaveData.

namespace Mobile.[ProjectName].MVP.View
{
     public interface ILoginView
     {
          void InitializeView(TViewData viewData);
          void UserValidated();
          void InvalidUser(string reason);
     }

     public class LoginViewData : BaseViewData
     {
          LoginView specific view data
     }

     Public class LoginSaveData
     {
          LoginViewspecific save data
     }
}

Presenter
The presenter interfaces defines the minimum requirements for the concrete presenter implementations.

public interface ILoginPresenter
{
     void Initialize();
     void AuthenticateUser(string user, string pass);
}

As we have designed it; it is not bound to a view or view interface.

The above explains how you create the “skeleton”,  next we continue with the concrete implementation of these interfaces.

Mobile.[ProjectName].Model
The model project is created as a library project and has a reference to the Mobile.[ProjectName].MVP project/assembly. Mobile.[ProjectName].Model is the concrete implementations of the Mobile.[ProjectName].MVP.Model interfaces. This module should handle all database operations and network and hardware I/O  in your application. The model project should not need to know anything about your presenter or view.

Public class LoginModel : ILoginModel
{
     Bool UserAuthenticated(string user, string password)
     {
          // connect to web service or database
          // check user credentials
          return (true|false)
     }

     SomeObject GetPreConditions()
     {
          // get some pre conditions and return them…
     }
}

Mobile.[ProjectName]
The Mobile.[ProjectName] project is created as a Windows Application and is the concrete implementation of the Mobile.[ProjectName].MVP.View interfaces. All code specific to this implementation should be placed here. This is the UI of the application.

public class LoginForm : Form , ILoginView<LoginViewData>
{
     ILoginPresenter _presenter = new LoginPresenter(this);
     Public LoginForm()
     {
          _presenter = new LoginPresenter(this);
          _presenter.Initialize();
     }
     public void InitializeView(LoginViewData viewData)
     {
          … Set up form data.
     }
     Private void LoginButton_Click(object s, EventArgs e)
     {
          // ask the presenter to validate user input….
          _presenter.AuthenticateUser(txtUser.Text, txtPass.Text);
     }
     public void UserValidated()
     {
          … Validated user can continue to work…
     }
     public void InvalidUser(string reason)
     {
          … Inform user about error…
     }
}

Mobile.[ProjectName].Presenter
The presenter project is created as a library project and references the Mobile.[ProjectName].MVP project. In this project you place all concrete presenter implementations. The concrete implementation of ILoginPresenter is in our implementation example bound to a login view interfaces and a concrete ViewData or SaveData class through its constructor.

Namespace Mobile.[ProjectName].Presenter
{
     public class LoginPresenter : ILoginPresenter
     {
          private ILoginView<LoginViewData> _currentView;
          private ILoginModel _currentModel;
          Public LoginPresenter(
          ILoginView&lt;LoginViewData&gt; view,
          ILoginModel model

          public LoginPresenter(ILoginView<LoginViewData> view, ILoginModel model);
          {
               _currentView = view;
               _currentModel = model;
          }

          Public void Initialize()
          {
               LoginViewData lvd = new LoginViewData();

               // populate the view data object if needed.
               SomeObject obj = _currentModel.GetPreConditions();
               Lvd.property1 = obj.property1
               ….

               // send the data required  by the view
               _currentView.InitializeView(lvd);
          }

          Public void AuthenticateUser(string user, string pass)
          {
               If (_currentModel.UserAuthenticated(user,pass)
                    _currentView.UserValidated()
               Else
                    _currentView.InvalidUser(“Unknown user”);
          }
     }
}

Other supporting projects
In addition to the above 4 projects you might have utility classes that can be shared amongst different implementations. This could be custom UI controls placed in a separate project for reusability communication libraries etc. They should be referenced and consumed in either your concrete model or view implementations.

Software Design Pattern Summary
From this pattern you see that there is constant communication between the presenter and the view and the presenter and the model. The concrete view is responsible for defining what presenter to use and tells the presenter what view is calling the presenter. The view then tells the presenter to start initialization, and the presenter informs the view by calling its initialize view method. The concrete presenter does not care where it gets its data from as long as it comes through a model interface, and it does not care about the inner workings of the view as long as its outer working environment is defined through the view interface.

We have now implemented testability.

This pattern could be extended even further; it is just a matter of finding the right layer of abstraction. For instance the ViewData and SaveData classes could have been interface based, more use of generics could have been implemented etc. but the preceding examples provides the layering we have found useful in our development projects.

Thoughts on code quality control
If you are ready to go this step into implementing a pattern that makes your code extendable, you should also think about how you code it and how you keep it bug free.

Coding conventions
I choose to follow the naming conventions found here: http://msdn.microsoft.com/en-us/library/xzf533w0%28VS.71%29.aspx, if you don’t like this one, find one that is commonly know and stick to it!

When naming methods, properties and variables make sure they are descriptive of what they do.  Descriptive property, method or variable names should make in-code comments obsolete.

There is no need to limit the amount of characters used for naming a method “GetListOfUsersFromNamedSource” is a descriptive name that explains what it does.

If your method name contains “and” in it; it indicates that your method does more than one thing and should be re-factored into two or more separate methods. One method should have one single responsibility.

Avoid “super methods”! If you have a method with an if/else block and eClean-Codeach of the blocks contain 30 lines of code, re-factor into a method with an if/else block that calls two descriptive methods.

More pointers on how to improve code quality can be found in the book “Clean Code” by Robert C. Martin – http://blog.objectmentor.com/articles/2008/04/08/clean-code-whew. It is a great book.

Logging and Error handling
Log all errors! Logging of exception events shuld be done through log4net from Apache (http://logging.apache.org/log4net/index.html)

All developed code modules should implement and use log4net as a logging mechanism. In a try/catch/finally code block, the catch block should always log it´s exception to log4net as in the following example.

try
{
     .... do something
}
catch (SpesificException ex)
{
     log.Error("Unable to do something",ex);

     .... do error handling and/or push it up the stack.
}
catch (Exception ex)
{
     log.Error("Unhandled exception",ex);
}
finally
{
     ... do cleanup stuff
}

If any other log4net logger types are used; Debug, Warn and Info, i check to confirm that the used type is configured like the following example:

if (log.IsDebugEnabled)
     log.Debug("Some debug information");

if (log.IsInfoEnabled)
     log.Info("Some informational message")

if (log.IsWarnEnabled)
     log.Warn("Some warning message");

Testability
While writing unit tests i try to follow the principles found in the book “Art of unit testing” by Roy Osherove  – http://www.artofunittesting.com/

artofunittesting“A unit test is an automated piece of code that invokes the method or class being tested and then checks some assumptions about the logical behavior of that method or class. A unit test is almost always written using a unit-testing framework. It can be written easily and runs quickly. It’s fully automated, trustworthy, readable, and maintainable.”

The preceding MVC implementation is created with testability in mind and each module containing logical code must have a set of accompanying unit tests proving how it behaves within and outside the bounds of its specification.

Logical code is any piece of code that has some sort of logic in it, small as it may be. It’s logical code if it has one or more of the following: an IF statement, a loop, switch or case statements, calculations, or any other type of decision-making code.

Unit tests must be implemented using the Nunit testing framework (http://www.nunit.org/index.php)and each of the tests must be created as isolated tests with no external requirements. Meaning that you have to run test s“a”, “b” and “c“ in sequence, or that have a tests that require any other pre-conditions like access to databases, network etc.

When naming test, for clarity use the naming convention from “Art of Unit Testing”:

[Test]
public void [MethodUnderTest]_[Scenario]_[ExpectedBehavior]()
{
     .... test code
}

A sample sample MVP Visual Studio 2008 solution can be found here.

Use Facebook to Comment on this Post

2 Responses to “Setting up a maintainable windows phone development project in Visual Studio 2008”

  1. Kostas says:

    Hi, thanks for your post – I am new to the MVP – I wanted to ask you whether you have the above example in a solution so I can download it and examine it better .
    If not, do you know where I can find one that is simple for beginners. I tried to use the MVC# but I found it bit complicated to follow.
    thanks

  2. Hi Kostas.

    I have added a download link for a Visual Studio 2008 demo solution in the post. It can be found her: http://cid-196625bc59fbf3e3.skydrive.live.com/self.aspx/Offentlig/SmartDeviceMvpDemo.zip I hope this helps.

Trackbacks/Pingbacks


Leave a Reply

Google Translate

EnglishFrenchGermanItalianPortugueseRussianSpanish

Blog Traffic

Hits

Pages|Hits |Unique

  • Last 24 hours: 2,101
  • Last 7 days: 19,452
  • Last 30 days: 63,407
  • Online now: 7

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

%d bloggers like this: