Best Practices (Inconsistency across quick starts)

Topics: CAB & Smart Client Software Factory
Nov 18, 2005 at 8:47 PM
originally posted by: samkuehn

Just curious if somebody has some ideas of CAB best practices. It seem that there is inconsistency across the different quick starts (perhaps to demonstrate different approaches). For instance some examples show the controller (MVC) delegating the creation of work items to its parent work item while in other examples the controller creates the new work items. I know this is a vague example, but I would be curious as to which of the quick start (or hopefully other more complete samples you may have) are the most architecturally sound? Is there any docs out there on the subject?
Dec 9, 2005 at 3:39 PM
originally posted by: DotNetRules

I agree completely.... we are scratching our heads trying to figure out which are the best practices. There are other threads raising this same issue but no response so far.
Dec 9, 2005 at 9:17 PM
originally posted by: BradWilsonMSFT

Honestly, the inconsistency comes from the fact that:

- The quickstarts were written over time, by different people
- CAB evolved a lot from the time they were written until now
- In the prioritization of work, we could not find time to re-write them like we wanted to (unfortunately)

Don't fret, though, because the Smart Client program isn't finished. :)
Dec 10, 2005 at 9:08 AM
originally posted by: kozaczynski

Let me add to Brad’s comment. Of course CAB is about developing smart client applications, but the focus of the project has bee the underlying framework. Consequently the quick starts are more about demonstrating the features of the framework than about communicating how to build a complete, consistent and elegant client. We recognize that, and have a new project called Smart Client Baseline Architecture. The objective of that project is to provide comprehensive, end-to-end guidance on how to develop smart client applications. The project is right now kicking into full gear and we will be opening the community site soon. In the meantime, we would be very interested in your comments on what kind of guidance you would like to see us develop.



-- Wojtek, p&p
Dec 10, 2005 at 9:48 AM
originally posted by: samkuehn

I completely understand that the goal of the project isn't to develop a smart client best practices guide. However, a CAB app is a at least a little different than smart clients that many of us have been developing. Those of us looking for guidance are going to have a hard time finding architecture suggestions regarding WorkItems, Services and such from the smart client community. So I think that you have to consider the fact that there are issues specific to developing CAB applications and that if these questions are not addressed by this community or the CAB team they will go unanswered. I belive the success of CAB is largely dependant on sound solutions being developed around it; so any push it the right direction would be beneficial to all.

That said, I love the product and appreciate the work that you guys have done.

Thanks!
Dec 10, 2005 at 12:07 PM
originally posted by: headlam

Part II

When all is said and done you should codify what every pattern you choose to use within your organization via GAT and/or VS Templates. This will make governance go much better. To echo what Wojtek said, I think SC-BAT will answer a lot of your questions you have, but until then, this is just my $0.02.
Dec 10, 2005 at 2:14 PM
originally posted by: samkuehn

Thanks for the post and ideas. I agree 100% with you! I love the flexibility that CAB provides; I was just hoping for some guidance regarding the inconsistent use of the framework. I realize there are many ways to skin a cat and the term BEST is subjective; but I don't want to make an errant architectural decision if I can learn from other experts in the community!

Your solution is a great one and I am currently using a similar architecture although I do have some tight coupling that you solution would not have. For instance I am not using accessing my controller methods through an interface, although I had thought about it i just haven't re-factored to that point yet but I will definitely go that way. My main problem is that my controller is very dependant on the WorkItem right now. For instance all my Business object live in the WorkItem so that I can share them across multiple views/controllers. So my controllers are littered with code like this:
public new MyWorkItem WorkItem
{
get { return base.WorkItem as MyWorkItem ; } //Ouch!
}
and
public MyBusinessObject SomeBusinessObject
{
get { return WorkItem.SomeBusinessObject; }
}
Judging by your previous post I would think that you would not do things this way ( side note: just to make my point this type of thing is done all over the place in the quick starts). I know that you were saying that you would put everything in the Controller class and completely decouple it from the WorkItem. How would you do this differently?

Thanks again for the great earlier post.
Dec 10, 2005 at 10:11 PM
originally posted by: headlam

Part 1

I will add my $0.02. I found demonstrating the architecture of CAB to be very usefully. It gets across the point of what the CAB architecture is. How I dress it up and use it is then up to me. That said I see the point you are making in that each quick start look and feel different in how it applies the CAB architecture and the need for guidance on how best to apply the CAB architecture in ones application. The strength of the CAB application (my opinion) is the flexibility the architecture still allows for (i.e., my SmartPart doesn’t have to use the SmartPart attribute; I can actually take existing assets and compose them into a CAB application without changing the existing code.

But here is why I’m really responding to this thread. Here is one way you could break up you CAB application. I will do a subsequent follow-up with more reasons why I would do it this way.

My Control/SmartPart class would represent the view. The V in MVC/MVP. I would limit my view to just rendering data in whatever way it chooses to do so. No business processing. I would delegate all user gestures to the Controller/Presenter class. The view (i.e., SmartPart, User Control, etc.) would get a hold of the Controller/Presenter class via injection (i.e., using the CreateNew attribute). The Controller should be exposed its capabilities to the view via an interface. (i.e., IMyPresenter, IMyController, etc.)
Dec 10, 2005 at 10:12 PM
originally posted by: headlam

Part II

The Controller/Presenter in this case would be a class that derives from the CAB Controller class and represents the V/P in MVC/MVP. Note: You don’t have to derive from the CAB Controller class. All the CAB Controller class does is inject a reference to the current WorkItem and expose the State property on the WorkItem class as a property on the Controller derived class, you could do this your self if you really wanted to). The controller is where I would put all my business logic to get data, respond to commands, raise CAB events, sink CAB events, get data from external system (i.e., web services, etc.), and so on. The Controller/Presenter class is really where the work gets done. I would expose my Controller/Presenter class behavior via an interface as stated above. So when the view communicates with the Controller/Presenter (i.e., pass user gesture, etc), it does so via the Controller/Presenter interface (i.e., IMyController, etc.) and not the concrete class reference. The Controller/Presenter would store state in the WorkItem.State property.

The Controller/Presenter and SmartPart (or User Control) should be viewed as the asset I would most likely reuse. Thus, they should have no dependency on a specific WorkItem instance. Additionally, as stated above, the View get a reference to the Controller/Presenter via injection (i.e., the CreateNew attribute). This makes the Controller/Presenter very testable (i.e., you don’t need a view or WorkItem to test your processing logic; you can mock the user gestures). The Controller communicates to the SmartPart (i.e., the View) via an interface that the Controller/Presenter design determines and the SmartPart/User Control implements (if it can).

The WorkItem should represent the Model in MVC/MVP and is where your state is stored. But it is more of an Application Controller in that it determines (for the most part) what gets shown to the user or not. I say not, because in some instance you may have a use case where no visual UI gets displayed to the end user. The WorkItem, which is the container, should add the Controller/Presenter or the View (i.e.., SmartPart/User Control) to the container (i.e., Add or AddNew). Doing this will cause the various strategies and policies to be execute for the given type being added to the container. In other words this will cause the object to get initialize based on the attributes that are present (i.e., event wire up, command wire up, dependencies injected, methods get initialized, etc.). The WorkItem is also where you determine where the view will be displayed and display the view. The WorkItem can also raise events in indicate changes to the sate, etc. The Controller/Presenter should respond to such events.

I would still have other types of classes: Business entities, service agents, proxies, etc. CAB does not change this. How I get a reference to such an object can be influence by CAB however. I cab use CAB to fully initialize my objects, etc.
Dec 11, 2005 at 7:46 PM
originally posted by: headlam

Having the Controller/Presenter dependent on a particular WorkItem class is not a good (my opinion). As I stated before you should view the Controller/SmartPart combination as the greater unit of reuse. That is not to say you would deploy and reuse the Controller/SmartPart/WorkItem combination… you will. But decoupling from the WorkItem will make the Controller/Presenter much more testable. That said here is one approach.

Since the SmartPart ideally does not know where it will get displayed, you typically will cause the SmartPart to be displayed, in a particular Workspace/SmartPartPlaceholder, from the WorkItem code. When you add the SmartPart to the WorkItem collection it will get processed by the build strategy and look for any dependency injection that is needed. In this case I would consider using InjectionMethodto inject the presenter or possible create an initialization method for the view and inject the controller/presenter this way:

public partial class MyView : UserControl, IMyView
{
private MySecondPresenter _presenter;

public MySecondView( )
{
InitializeComponent();
}

MySecondPresenter Presenter
{
get
{
return this._presenter;
}
set
{
this._presenter = value;
}
}

InjectionMethod()
public void InitializeView(ComponentDependency("My Presenter", Type = typeof(MyPresenter), Required = true, CreateIfNotFound = true ) IMyPresenter presenter)
{
Presenter = presenter;
Presenter.View = this;
}
}

At the same time you could initialize the controller/presenter with a reference to the view. In the MVP model this now sets up the connection between the preenter and view (SmartPart). I preset this approach since the controller/presenter does not have any knowlede of a specific view. Again, this is just one way to do it you could use InjectionConstructor or inject via a property, etc.

As for the other business object that are required you can inject them in a similar way as appropriate. You can even ensure that all instance of a controller/.presenter get the same instance or a new instance.
Dec 13, 2005 at 6:48 AM
originally posted by: samkuehn

Great post. My only question is how would you do the business object injection so that Controllers/Presenters have a reference to the same object?
Dec 13, 2005 at 9:06 AM
originally posted by: BradWilsonMSFT

Answering the business object question has a lot to do with how you structure your business objects inside of CAB.

If your business objects are pre-registered as services, then injection is simple: use ServiceDependency.

If your business objects are used as normal objects (in the Items collection of WorkItem), then you can use ComponentDependency with the appropriate flags. The only question is whether or not to name the object. For instance, say I have this as my business object:

public class MyBusinessClass { ... }

I could do a ComponentDependency:

public class MyConsumer {
InjectionConstructor
public MyConsumer(ComponentDependency(Required=true, CreateIfNotFound=true) MyBusinessClass biz) { ... }
}

When you do an unnamed ComponentDependency like this, the rules are "the first thing I find in the collection that matches this type is what I'll give back" (and first is undefined). So this is fine if you're using a concrete type, or a specific interface that's only implemented by one class.

If you want to share a specific instance of something, you can name it by adding ID="TheName" to your ComponentDependency parameters.
Feb 25, 2006 at 2:53 PM
originally posted by: aras03k

headlam,

Very insightful thoughts in my opinion. However, I cant see how the smartparts themselves can efectively handle communication with the service agent. For instance, what happens if you have a "container" View containing 3 smartparts. The first view would be a list of customers whereas the 2 others would each display a subset of the customer object (like contact details and address). If both detail views were wired up to listen to a selected customer event they would be fighting over which one of them should call the service agent and retrieve the customer.

In other words...I see some issues surrounding the fact that Smartparts autonomusly communicates with web services and not routing their requests through the work item. Especially in "complex" real life sceneraios where a work item handles multiple smartparts operating on a large busines object model.

I know this is exactly the thing that is being done in the R1 SCBAT but then again this hardly falls under the real world complex category ;)

In my project, which is still in the startup fase, I have decided to try and make the work item an "event router" effectively forcing my smartparts to fire an event whenever they need a service request to be processed. The work item would subscribe to these events and handle them appropriately. If the state is modified it would answer back with a "statemodified" event to any smartparts listening. If the smartpart needs a more direct reply it would recieve it via a specific event topic that only that would be listening in on. This would still decouple the smart parts from the work item and the only contract between the 2 would be the event published and subscribed. How to enforce that contract is another issue entirely :) I'm not entirely "happy" with this solution either as it leads to a lot of events being fired back and forth. Can anyone offer their thoughts on this issue?

Thank you,
AR
Feb 28, 2006 at 9:24 AM
originally posted by: jrimpo

I'm trying this approach: Controlled WorkItems (as in SC-Bat) and Presented SmartParts. Currently I have a 1-1 for the controlled workitems but a 1-many on the presented smartparts (1 presenter may handle a group of smartparts). The presenters fire off events (not the smartparts). The controllers basically catch events and work with the service agents. They may pass requests/data on to presenters. Currently I have one primary controlled workitem (I think of it as the project controller) and 6 sub contolled workitems (one for each unit of work).
Feb 28, 2006 at 12:31 PM
originally posted by: aras03k

I want to clarify that in my case i use the MVP pattern and I think of the smartpart as the View and Presenter. The Presenter would also handle eventing in my case :)
Feb 28, 2006 at 12:58 PM
originally posted by: PProvost

I don't know if I understand what you mean. The MVP patterns calls for a separation of the View and the Presenter into different cohesive classes. How can the SmartPart be both the view and the presenter?

Now, perhaps if I explain how I think of it, it will help.

In my mind the SmartPart is the View. Whether or not the View is implemented using the MVP pattern, the MVC pattern, DocView or even as a monolithic view. The View is the SmartPart.

If that View uses the MVP/C pattern to get good class partitioning, then that is really an internal implementation detail within the View. People who consume the View don't need to know about the presenter. They just create the View and use it. The Presenter (or Controller) should just "happen".

Perhaps if you explain what you mean a bit better, we can help more.

Regards,

Peter Provost
Development Lead - Smart Client Program
Microsoft Patterns & Practices
Mar 1, 2006 at 10:09 AM
originally posted by: aras03k

Peter,

I understand what you are saying. I think we are on the same wave length regarding smartparts/views. The fact that I lump Smartpart and presenters together is because I think of them as 1 unit of reuse. The same presenter will follow the view in the majority of cases. My implementation calls for 2 seperate classes though, exactly like the SC-BAT.

My main concern wasn't about the smartpart/presenter relationship though, its about the autonomy of them with regards to the work item. I view the work item as the work flow controller. It controls what smartparts are displayed, in what order, and when. In order to do that effectively I feel that it must have knowledge of the information flow between smartparts. Since the purpose of smartparts is to encapsulate and reuse UI elements, they themselves of course cannot be directly dependant on each others existence.

My Web service interface will be pretty coarse grained - an example could be something like GetcustomerById(id) which retrieves customer info, accounting data and a bunch of other related objects. As such I need to centralize web service comunication...or atleast make sure that my smartparts won't fire off simultanious requests to the same web service just because they need their little part of the customer state updated.

Some service communication would naturally belong inside my Smartpart/presenters. Advanced data validation by the server or lookup requests triggered by user interaction. Even the "isolated" master/detail scenario you have in the first SC-BAT would probably be a good fit here as well..

I'm going to try the idea of letting the workitem control the information flow to the smartparts and see how it works out. If It doesn't I will have to revert to something else...I'm hoping the comming SC-BATS' will provide useful guidance in this respect.

Thanks,
Allan R
Apr 1, 2006 at 2:37 PM
originally posted by: sagi44

When initializing my WorkItem, i realized a strange thing.

What is the difference between (Where Presenter inherits from Controller):
Presenter presenter = new Presenter();
Items.Add(presenter);
and -
Presenter presenter = Items.AddNew<Presenter>(); ????????
I ask this because when using the first option i get a Null pointer reference to my
WorkItem in the Presenter.
But when using the second option, somehow the parent workitem is ok.
I'd rather use the first method because it allows me to use constructor params.
What am i missing?