Sunday 20 December 2009

Prism Sample: Modules

Central to Prism is the concept of modules and modular design, therefore it's worth spending some time defining exactly what a module is, what it contains and what it shouldn't contain.  Per the Prism documentation:

A module in the Composite Application Library is a logical unit in your application. Modules assist in implementing a modular design. These modules are defined in such a way that they can be discovered and loaded by the application at run time. Because modules are self-contained, they promote separation of concerns in your application. Modules can communicate with other modules and access services in a loosely coupled fashion. They reduce the friction of maintaining, adding, and removing system functionality. Modules also aid in testing and deployment.

Having worked on a number of Prism projects with a wide range of developers, each interpreting this from their own perspective and experience.

Two of the guiding principles behind this are:
Single Responsibility Principle
Separation of Concerns

While most can agree on these principles, views differ on the depth and extent to which they are applied.  On one end of the spectrum we have the theorist, whose motivation may be to strictly adhere to these (some times with religious fervor).  And on the other end we have the realist, who simply wants to build a working piece of software that meets the business requirements.

The theorist looks beyond the business requirement, while the realist may argue that strict allegiance to these principles is outside the scope of the requirements.  Somewhere, somehow these views are resolved, usually by an architect or team lead; and the result usually falls somewhere in the middle.

Personally, I fall in the middle, and maybe lean towards the realist.  I don't feel software development should be an academic exercise.  If someone entertains the idea of using a certain design pattern, I'm always interested in "what problem does this solve?" and "what does it buy me?"  Unacceptable answers are "because Fowler said so" or "because that's what the Prism team does".

Enough of this, let's talk about modules...

In an earlier post, I talked about creating an Advertising module for Blogger and said I would create the following modules:

Blogger.Advertising.Interfaces
Blogger.Advertising.Views
Blogger.Advertising.ViewModels
Blogger.Advertising.Services
Blogger.Advertising.Services.Interfaces

Some developers would be tempted to bundle these up into two assemblies:
Blogger.Advertising
Blogger.Advertising.Interfaces

storing their Views, ViewModels and Services in a single assembly.

And I could be convinced of this.  It's certainly easier to maintain.  But I would argue that Views/ViewModels and Services are logically separate and warrant their own assemblies.  It's not inconceivable that another module or system could be a consumer of these services, without the need for Views or ViewModels.

So, why separate out Views from ViewModels?

I think it is somewhat idealistic to expect Views designed for Product A to be simply dropped into Product B (two different implementations).  In theory this is possible, but in practice I've never seen it happen.  Here we get into areas of look and feel and layouts.  While we can do a lot to make a view generic and use themes and skins to alter its appearance, at the end of the day there is always going to be something different or required which makes the view unusable.  So why bother?

I always assume my views are not going to be reusable; that they're part and parcel to a specific implementation.  My ViewModels, however, are completely reusable.  I would also argue that mocking up Views is far less time consuming than the creation of ViewModels.

Regardless of what I think, your design decisions are going to be driven by a number of factors.  I think its important to consider all views and options, and decide which is suitable.

4 comments:

xoma said...

Ron, when you mentioned "In an earlier post, I talked about creating an Advertising module for Blogger and said I would create the following modules ....", are all of those assemblies different PRISM modules or they are just assemblies with one AdvertisingModule, right?
My question is two folded:
1. Where is your actual PRISM module with Initialize() for the whole Advertising module.
2. How would you load dependencies, using unity.config, or using App.config file with

rgramann said...

Xoma,

At the time I had each of these in separate assemblies, but have since changed my viewpoint on this. I would place all of those in a single assembly.
The single assembly would have a Module class (implementing IModule).
Regarding configuration, I prefer to use a unity.config file instead of app.config. No real difference, just a personal preference.

xoma said...

Ron,

Thanks for a timely reply. Could you please elaborate on your new viewpoint? What has changed your mind?
I am in the process of refactoring an application in WPF/PRISM/WCF where we have some vertical modules essentially representing different "app" modules all of which could be launched from MainMenu module. For each of those "app" modules we have two assemblies:
1. ActualModule (contains Views/ViewModels/Services and IModule)
2. Domain (POCO entities, value objects, IRepositories, etc).

We have followed PRISM guidance in creating an infrastructure assembly that's now became a "catch all". It became something along the lines "If in doubt, put your stuff in an infrastructure assembly". I am trying to break this habit.

Does your post "Prism Sample: Introduction" where you outlined a possible solution structure for PRISM related application still reflects your current thinking?

rgramann said...

Hi xoma,

Initially I felt it was best (and more flexible) to separate everything out (e.g. Views, ViewModels, Interfaces, etc). That this would give you the most options in the future. While this maybe true, in reality I've never seen this happen. But what does happen is Team A is developing X and Team B has a requirement for X and wants to use what Team A developed. So Team B asks Team A to send it over. What Team B really wants is a single assembly that they can drop in their project.
Your not going to get that with everything separated out. What you will get is is about a half dozen assemblies all interdependent. Yuck.
So, with that in mind you ultimately want single assembly, low dependency. This is what I tried to address in my posting MVVM Revisited. Check it out and let me know what you think.
Regarding your infrastructure assembly, I think that is pretty common and not necessarily a bad thing. It does have to be monitored with some common sense though.
I'm currently trying to incorporate some of the concepts I introduced in MVVM Revisited and the use of MEF.