Continuing in my exploration of the Effectus code base, which originated from my Building a Desktop To-Do Application with NHibernate article on MSDN Magazine, I wanted to talk today about separating features into individual pieces in the application.
Each feature in the Effectus application is built as an isolated unit, that has little to do with any other features. This is very clear when you look at how they are organized:
Sidenote: In each feature, the component parts are named the same (Presenter, View, Model). This is intentional, since it make it that much harder to mix stuff from other features.
Every feature has a pretty rigid structure, defined by the application, and trying to reuse stuff between features is frowned upon and avoided, even if doing so can reduce duplication. As a good example, the Model for both CreateNew and Edit features are identical, but they are two different classes with no attempt to merge it up.
The reason for this is quite simple, treating each feature as an isolated unit bring us great benefits, we can have different developers working on different features without the chance of stepping on each other toes, it is very hard for one feature to break another, deploying new features is easier to handle, etc. Trying to apply DRY and consolidate common pieces of code would introduce dependencies between features, and that is a bad idea.
But what about communication between features? What about when one feature needs to call another?
As it turned out, it is quite easy to turn a lot of the inter feature communication into an indirect calls, using pub/sub. We gain the independence from dependencies using pub/sub, while maintaining the feel of a well integrated product for the user. For the rare cases of one feature calling another, I create a simple Call(“FeatureName”) mechanism (in the code, this is Presenters.Show(name) method) that all us to just explicitly invoke another feature, maybe with some initial arguments. A more complete implementation will handle even that using pub/sub, probably with an integrator class that would dispatch the appropriate event to start and invoke the feature(s) that want to handle it.
You can read more about the architecture principles behind this system in: Application structure: Concepts & Features