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. 😉

Comments (7)

  1. aleonard763 says:

    This sounds really cool. It reminds me of the "spiral" methodology some, where you started by identifying the holes in the design and then wrote little applications to demonstrate feasibility.

    :{> Andy

  2. FKruesch says:

    That sounds all very promsing. Looking forward to the first CTP!

    cheers

    Florian

  3. cnblogs.com says:

    看了P&amp;P client product manager Glenn Block 的最新的一篇blog Have you heard of SFD? ,P&amp;P的这些专家们总是在拼命的创造新名词

  4. Ben Fulton says:

    Otherwise known as the YAGNI principle, no?

  5. "SFD stands for Simple-First Development" – why do we keep on coining up new terms for things such as "Bottom-Up" and "Top-To-Bottom"?

  6. saurabhd says:

    I am glad to see that real life examples are being used to drive the development of PRISM. I am looking forward for the first CTP.

    In the Purchasing Module example cited above,I would like the team to put a thought on following scenario:

    After my ERP application has been deployed to the customer, the customer’s development team may want to add some more views to the composite application. Needless to say, this should happen in a pluggable way, i.e. the original base source code should not be changed.

  7. michael.plavnik says:

    At the shell level we decided that we should allow modules to push views into named regions in the shell.

    ———————————————

    Could you elaborate on your decision a little bit more?

    ———————————————

    This makes sense because in a composite application you may have many teams that are all contributing content to the shell.

    ———————————————

    That is certainly true.

    ———————————————

    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.

    ———————————————

    It asks for big WHY? There would likely be a team that is repsonsible (product wise) for this screen. Situation would not change  even in case of screen that is completely customizable by the end-user. Taken my assumption into consideration, there can be simpler solution.