I spent a week in Redmond in January taking part in a focus group on the vision for the P&P’s new Prism work on composite applications. Part of the week long exercise was to identify the basic building blocks of building large composite clients. This is my list of the significant parts of an application that I see regularly reoccurring from app to app. For CAB fans, you’ll note that there is no “WorkItem” in my list, but the responsibilities that it fulfills in the CAB framework are all present in other (more logical) places. if you’re moving onto Composite Application Street, these are the classes and in your neighborhood (, in your neighborhood, in your neigh-bor-hood, oh here are… ):
The IoC/DI tool of your choice
These tools are good for more than just crowbarring mock objects into your code. When you’re talking about extensibility and modularity, an IoC tool is an easy way to wire up new Views, Presenters, and Services to your existing application. If you take a long look at the CAB, you’ll see that a major portion of it is related to Dependency Injection and (ObjectBuilder) and service location (the WorkItems). One of the main reasons that I’ve always been dismissive of the CAB itself is how easy it is to roll your own framework wrapped around an existing IoC tool. You could build a composite application without an IoC tool, but the responsibilities that were assumed by an IoC tool are just accomplished by something else (or hard coded which would pretty well shoot down the idea of a composite application). Obviously I’m biased here, but I think that using an IoC tool is a huge shortcut in building any kind of extensible application. Assuming that that level of extensibility is actually justified of course;-)
The main form that contains everything else. The responsibility of the shell is to hold the main components of the user interface like menus, ribbon bars, and holders (panels, docking managers, etc.) for the screens that get activated later. This should be fairly thin, and there’s some very real danger in the ApplicationShell becoming a catch all that collects way too many unrelated responsibilities.
The Application Controller pattern identified by Martin Fowler is “A centralized point for handling screen navigation and the flow of an application.” The ApplicationController controls the screen activate lifecycle and the lifecycle of the main form. In most of my systems other screens are activated by calling methods on the ApplicationController. In smaller systems the ApplicationController would also control screen workflow. In larger systems I would break some of that responsibility out into separate collaborating classes.
I should point out that the ApplicationController is probably going to be a full blown subsystem in its own right. The Single Responsibility Principle will often drive you to split the ApplicationController into some smaller parts:
- Screen Conductor — Controls the activation and deactivation lifecycle of the screens within the application. Depending on the application, the conductor may be synchronizing the menu state of the shell, attaching views in the main panel or otherwise, and calling hook methods on the Presenter’s to bootstrap the screen. It may also be just as important to deactivate a screen when it’s made the inactive tab to stop timers. My first exposure to a Screen Conductor was an insurance application that was built with web style navigation. Anytime the user moved away from a screen we needed to check for “dirty” screens to give the user a chance to deal with unsaved work. On the other hand, we also had to check the entry into a requested screen to see if we could really open the screen based on pessimistic locking or permission rules. We pulled our a Layer SuperType for our Presenters for methods like CanLeave() and CanEnter(). The Screen Conductor would use these methods and others to manage screen navigation.
- Screen Collection — In applications that have some sort of tabbed or MDI display of screens, you usually need to track what screens are active. The easiest example I can think of is a TradeCapture application I built last year. When a user opened a trade from either a search screen or by entering a trade id, the trade ticket window would popup in a separate window. It was important that there only be one window for each trade up at one time, so if the user happened to request the same trade that was already opened, we would just show the existing screen instead of opening a brand new screen. We used a Screen Collection class to track the open screens so that we could retrieve the active screen for an individual screen. I’ve seen this pop up on at least 3 separate occasions now.
- Screen Subject — I’ve only used this a couple times, but it’s going into my regular rotation from now on. I’ve built several applications along the tabbed display motif now. In many of them there’s a need to respond to a navigation request by first checking if the screen exists to either make the already open screen be the active tab or to create a brand new screen and make that the active tab. I’ve gone to the idea of a ScreenSubject object that can determine if it matches an open Presenter and knows how to create the new screen if it isn’t already open. ScreenSubject works very closely with Screen Collection.
- Bootstrapper and Registry – The IoC container and the ApplicationShell has to be constructed somewhere. I like to put all of the “bootstrapping” into a class called, wait for it, Bootstrapper. It’s very useful to keep this separate from the ApplicationShell itself, both to keep the ApplicationShell cleaner and also to enabled integration testing scenarios that test partial application stacks. Bootstrapper is also responsible for spinning up any services that need to run throughout the application lifecycle (like caching or the event aggregator). The Registry is an optional piece that contains configuration for a specific module. It might help configure the IoC container, add more menu items to the shell, or attach new services.
- Model, View, and Presenter – I won’t rehash these pieces here. See the rest of Build your own CAB for more information. There’s about a hundred different ways to divide and organize these three things.
- Service – The most overloaded term in all of software development. Roughly put, it’s the classes that you interact with that aren’t one of the other things. I would strongly recommend that
- Command – Gang of Four Command objects. “Jeremy’s first law of enterprisey systems” — Every system of sufficient complexity will have an ICommand interface. This subject deserves its own chapter/post.
- Event Aggregator / Event Broker – Here and here. I’m going to include at least three different flavors of this in my book.
- CommandExecutor – Also known as the Active Object. I like to use Command Executor to standardize the way my applications use background threading.
What did I miss? Comments are open.