Have you heard of SFD?

OK, you've heard of TDD and BDD, but have you heard of SFD? SFD stands for Simple-First Development. It's a principle that we're driving on as we move forward in our "Prism" (Composite WPF) project. Essentially it means that when we attempt to solve any problem, let's start with focusing on the easiest path that addresses the most common cases rather than over-complexifying the simple cases in order to handle the edge cases.

Let me give you an example to show you how we are applying this principle. One of the features that CAB provided was allowing you to have modules that dynamically populate content anywhere on the screen by grabbing a handle to a Workspace that lies somewhere in the cloud by using it's key name. The mechanism is so flexible that it allows Module A to load a new Workspace into an existing workspace in the Shell, and then Module B can come along and dynamically add content to that Workspace from Module A.

So what's the problem with this? Well the problem is it introduces complexity, reduces debug ability, learn ability and in some cases may even post a security issue. It introduces complexity because suddenly I have things magically appearing throughout my app, that I may have to spend quite a lot of time tracking down. Depending on the complexity of this system, this could be an arduous task. Learn ability is affected because now in addition to understanding the tangible pieces of the system that i see, I have to be concerned about a whole other magical world that i don't see. The security issue maybe that I may not want certain modules to be able to populate their content into a specific portion of the screen, but because everything is dynamic, I have no way of really controlling it. Even if I could do it, it would be very ugly.

As we've been working on "Prism" we've encountered this same problem, and although our first instinct was to use a similar pattern, we took another look with the Simple-First approach in mind. In "Prism" we have a notion of Regions which are similar to workspaces. A Region is a place to store content (views). At the shell level we decided that we should allow modules to push views into named regions in the shell. This makes sense because in a composite application you may have many teams that are all contributing content to the shell. You don't want the shell to become a hotspot with every team having to modify it to hard-code where the injection of screens.

For example, imagine an ERP system where there are many different sub-systems that are accessed from a navigation tree on the left side of the screen. Each sub-system is potentially maintained by a different team.As you click on the sub-system, it loads up the screens for that  right portion of the screen.

Now let's say that sub-system say Purchasing is actually deployed among several modules. So one module (PurchasingModule) loads up that has the main set of screens which are added to the shell. Then additional modules may load for the sub-system such as PurchasingHistoryModule. PurchasingHistoryModule then has some views like HistoryView that it wants display in PurchasingModule. But there are other modules as well that might contribute content to PurchasingModule like the PurchasingTrackingModule. But, PurchasingModule doesn't have any direct references to those other modules.

Below is a diagram to illustrate this.

image

So how do we apply Simple-First to solve this problem without doing the module push. Instead we do an explicit pull model. But wait, PurchasingModule doesn't have any direct references to the other modules right?. Aaah yes, so instead create an interface assembly that has interfaces for all the different views that PurchasingModule shares. Then each "child" module that loads can register it's views when it loads with the IOC. The PurchasingModule's Presenter however can contain explicit code that pulls the views from the container that it needs, and it can populate them as it sees fit.

For example see the code below (just for illustration)

 class PurchasingPresenter {
   ...
   public void OnLoad() {
      IHistoryView HistoryView = container.Get<IHistoryView>();
      Put(HistoryView).In("HistoryRegion");
   }
}

Will this approach handle all cases? probably not. But we think it will address a large set, and for those cases will make the code more maintainable and easier to debug. Applying simple-first, we'll stick with it for now. Once we see a need we'll consider applying complex-next. ;)