Presenter Creation in the View

Topics: User Forum
Feb 19, 2007 at 7:16 PM
I am having a blast with the framework so far, but one thing irked me. It was that the Container view has a lot of power to configure and wire up objects. The only important part that concerns me is that it also creates Presenters for its container items. This means it also needs to know all the data that the presenter needs. For example, let's say I have a StoreList presenter that grabs a list of stores from my StoreRepository. My ContainerPresenter (or its parent/host presenter) needs a reference to the repository (through constructor injection) in order to grab the list. Now, each store has a list of employees. I need to also grab those from the storeRepository. So when my ContainerView creates an EmployeePresenter (in its AddView method) it needs knowledge of the StoreRepository. I have two issues with this:

1) The container now has what I consider too much knowledge of the domain, it should deal with the domain objects, not their dataSources.

2) The StoreRepository now needs to be Serializable (I don't know why, this may be a different error). With something that could be a potentially large object like a Repository, that's a bad idea.


What I have done for the time being is tow methods, each on different projects:
a) In one I made a Strategy object that takes in a View and outputs a container item presenter which the Container Presenter injects into a setter on the Container.

b) In another I created an event that takes the View in as an argument and a placeholder for a Presenter, then the ContainerPresenter has a handler that creates a new presenter, and injects it into the event arguments.


This is a slightly more complicated process to make a Container List, but I think it keeps the responsibilities in more proper locations. After all, I think that presenters should have knowledge of other presenters and views have knowledge of other views, not mix and match except when necessary.
Coordinator
Feb 22, 2007 at 2:19 AM
Gilligan you are the VIP user of the framework so far.
I see your point although I guess you are misusing the container.
Let´s see what you are trying to accomplish here:

StoreListPresenter ==> IStoreList ==> StoreListView(MvpContainer)
ok?

So in the AddView method for StoreListView I just create a new StorePresenter and a new Store (which implements IStore) ok?

I don´t fill it, I don´t get employees, nothing. Just create it. And you know why? Because the responsibility of filling it is of the StorePresenter, which will get initialized by the Container if you call the RaisePresenterAdded method in the end of the AddView method (or if you use the MvpContainer user control class as base class). The StorePresenter for each row will get it´s Init and Load methods called, thus initializing it´s own row.

Now you´ll say: Oh, and so I get 1823481824 accesses to the data store to grab the SAME bunch of employees?
Well if they are exactly the same, or if you just rather filter them in their collection (or dataset or whatever), you can use HostPresenter´s Runtime Instances support. This is rather new. I guess it appeared in version 0.3.0. This is a way for you to have your presenters communicate without they actually communicating.

Basically the HostPresenter gives you two methods:
public void AddInstance(object instance, params string[] keys)
public T GetInstance<T>(params string[] keys)

In AddInstance you pass the instance of the object you want to store (could be a dataset, a collection or anything else you need to store) and in the second parameter you pass a key (the id of the object, the parameters for the query). This key is something that uniquely identifies this Instance. It´s a params array so you can pass any number of keys (useful for Composite PKs).

The GetInstance method is the opposite. You get an object by using it´s keys. Notice that the Type of the object is part of the key as well, so you must use the same type. This way you could do something like this:

  List<Employee> employees = HostPresenter.GetInstance<List<Employee>>(string.empty);
  if (employees == null){
    employees = EmployeeFactory.GetAllEmployees();
    HostPresenter.AddInstance(employees, string.empty);
  }
  //Do something in the presenter with the employees.

You see? Now every single StorePresenter will get the item from the runtime instances collection, and not from the data store. So even if you have 10,000 stores in one web page (I wouldn´t advise on that hehehe) you will have ONE access to the data store.

But please keep the doubts coming. I crave on them since you help me improve the framework.

Thanks for all your support,
Bernardo Heynemann
Feb 22, 2007 at 1:08 PM
Edited Feb 22, 2007 at 1:13 PM
I understand what you are saying, and you are right in regard to what you are doing.

Alas, I am doing things slightly different. I may be misusing the framework, but it also may be a brittleness in the framework too. Let's explore and find out. :-)

There are two things I am doing differently:

1) I am using constructor dependency injection. I am a stickler when it comes to injection. I don't know why, but I dislike setter injection, probably because in constructor injection its clean and you have all necessary dependencies from the start. With setter injection, however, a dependency may not be set. Maybe I am being anal and an "Initialize Presenter" function is a perfect solution. But I bring this up because I inject the StoreRepository into the presenter's constructor instead of having a singleton (like the demo has). But since the Container is creating the presenter, then I would have to give the view a reference to the repository. I feel like I would be giving the view way too much knowledge of my business. I don't mind the view knowing about my business objects, but my data access layer should be off-limits to keep it clean. So I am left with setter injection. I just don't like it.

2) I am not using Host (I do implement IHost for future extension) or HostPresenter. This is because, as said in a recent feature request I added, a) I do not fully understand how it interacts with everything (too much source code browsing :-) and b) I think that using HostPresenter causes too much of a tight coupling between presenters. Ideally, I want my presenters to be independent of each other and compositional. Now having a host and host presenter makes sense, of course. I see a host as a webpage or as a child/ main window of an MDI Form in desktop apps. Now I am not sure whether Hosts are meant to be compositional or not, but thats neither here nor there. I should be able to have a host that has two presenters of two views, with those views having three views/presenters each (and none of them need to be containers). To be compositional, I feel that each of these presenters should act as a host of sorts for everything below them, therefore they would view themselves as independent hostPresenters. In order to maintain independence, they need to have all resources they will ever need to get their job done without relying on other presenters. (I do this through constructor injection currently). Having a reference to a higher-up HostPresenter goes against this compositional design, but not by a lot. Many compositional object have a "Parent" property. But the issue comes when the presenters start relying on the hostPresenter to give them resources. This, in my opinion, creates an additional dependency on something that does not help the presenter get its job done. Let the HostPresenter give the resources to its child presenters through injection. Thus you can compose complex presenter hierarchies easily. Wow this is getting long...anyway, even this second "irk" is not that big of a deal. However, the follwoing "irk" is: It looks to me as if the HostPresenter does not represent a "Parent" property in the hierarchy, but a "Root" property. I get this from the fact that the hostPresenter is tightly coupled to a configuration file. The whole configuration system is still slightly confusing to me, so I am not using a config file for now, just programmatically loading the presenters and views. However, using HosPresenter and Host seems to cause certain errors that can only be solved by using a Configuration Container.

To summarize those very long points/opinions I just gave:

I do not like the current process of creating and initializing a view and then setting its dependencies through the HostPresenter because a) i just do not like setter injection and avoid it when I can, instead using constructor injection for a cleaner interface, and b) I think the HostPresenter is treated too much like a "Root" object, and not enough like a "Parent" and is too tightly coupled to a configuration context. I also do not think that a presenter should rely on its HostPresenter for data (although practically it makes a nice cache layer for data retrieval, I think there are alternative designs that keep the presenters' compositional nature better. One example is using dataSource Command object injected into the presenter so that you can cache runtime instances within the command, keeping a simple Get() method that gets the data. I use this in a couple of my presenters. Think "Query Object").

As a last note, the framework keeps getting better and better with every source code download I make. :-)
Coordinator
Feb 22, 2007 at 5:34 PM
I do use constructor injection as well, but of the View into the presenter. Not from data sources. And as a matter of fact, I don´t think the view should see data sources in any form. The presenter should fill the view with the correct data sources.
I like the idea of composable views and presenters though. I´ll think of developing a Host/Container/View entity for NMVP in the upcoming versions. But you are absolutely correct. The Host and HostPresenter are supposed to work as Root entities, not as parent entities. We used here in a production app a Container of Containers and it worked as a charm, though. Not sure if it´s what you are looking for anyway.

Thanks for all the activity, and thanks for the bug you created. I hope that everything is working better now...

The Host and HostPresenter structure have a few advantages that will become even more apparent once I release the PersistenceProvider, which will handle persistence of your views automatically. But only if you hook it into a HostPresenter.

The Host and HostPresenter are very nice for orchestrating views and presenters.

I´ll check why the HostPresenter does not work without a ConfigurationContext though. That shouldn´t be the case.

Again, thanks for the help in improving the framework,
Bernardo Heynemann
Feb 22, 2007 at 11:02 PM
Edited Feb 22, 2007 at 11:03 PM
Knowing the Host entities are supposed to be roots makes things a lot clearer. Thanks.

What I meant concerning Constructor injection is that I inject my repositories/datasources into the presenter directly, the view does not see any datasources (minus one of my views, but thats a refactoring waiting to happen).

Here is the strategy you use in the Project sample as I recall:
The Repositories (ProjectMemberManager and ProjectManager) are Singletons. So all of your presenters do the following: retrieve data from the Singletons or from the HostPresenter (which got its data from the Singletons). They then inject this data into the views as needed. Not a bad plan, but it makes some of the presenter methods tricky to Unit Test.

Here is my strategy:
I, too have a DaoFactory Singleton, but only the Host (webpage) knows about it. The Host page then constructs its child presenters and injects repositories created by the factory into the presenters' constructors. These presenters then inject the repositories (along with other criteria information, as needed, but this may need to be refactored) into their child presenters. They also inject data into the view as needed.

Now this is why I believe my use of the framework diverges from what is expected. Since I inject datasources directly into all child and main presenters, I want the presenters to have control over child presenter creation, all the way up to the host. Thus the suggestion of the ViewCreated event, etc... (whose complexity is starting to bug me :-)

Now also I understand that my strategy is ill-fitted ot the framework because it is not yet designed to be fully composable in the sense that any presenter can potentially be a hostPresenter. I think it is definitely a direction worth considering.

For the time being I think I can simulate such a structure by using a "Special Case Pattern" hostPresenter that, when it calls its HostPresenter property, is really just calling a reference to itself, then making sure I inject all datasources through the constructor. I think this strategy will allow me to better design to the framework, while still maintaining a very compositional nature. In fact, this design may be a good way to develop that Host/Container/View entity you mentioned.

I am starting to beleive the HostPresenter not working without a configurationContext is my lack of understanding. I will have to review the source code and project sample to clarify.

Thanks for the response. :-)

P.S. A small recommendation as well may be to change the GetInstance() InstanceKey, and other similarly named propertie/method names to GetModel() and ModelKey or something similar to better reflect the intent of the methods/properties.
Coordinator
Feb 23, 2007 at 1:07 AM

Gilligan wrote:
Here is the strategy you use in the Project sample as I recall:
The Repositories (ProjectMemberManager and ProjectManager) are Singletons. So all of your presenters do the following: retrieve data from the Singletons or from the HostPresenter (which got its data from the Singletons). They then inject this data into the views as needed. Not a bad plan, but it makes some of the presenter methods tricky to Unit Test.


Gilligan, thanks a lot for being so helpful. I´m sure you´ll still contribute a lot to the framework.
On this subject, if you conform to the framework design the Presenters aren´t tough to unit test at all. Give me a sample? As far as the presenters are concerned they should ONLY implement Init, Load and Save. Anything else should be in a business rule (Like ProjectManager). I still don´t get what issue you are having. Why you need to pass on data sources... In my experience is not a very good thing for repositories to be passed along layers. If you need to pass parameters to a child presenter so it can query a repository apropriately, that´s fine by me (as long as the presenter calls the repository via a Business Manager like ProjectManager), but injecting the data source does not look very good to me at all.


Now this is why I believe my use of the framework diverges from what is expected. Since I inject datasources directly into all child and main presenters, I want the presenters to have control over child presenter creation, all the way up to the host. Thus the suggestion of the ViewCreated event, etc... (whose complexity is starting to bug me :-)

Now also I understand that my strategy is ill-fitted ot the framework because it is not yet designed to be fully composable in the sense that any presenter can potentially be a hostPresenter. I think it is definitely a direction worth considering.


I´m very glad that your use of the framework diverges from mine, since this is what will make it evolve.
I´m very much fond of this composable strategy. I´m thinking a lot about how to do it, but I haven´t come to a conclusion so far, and since I´m implementing stuff for version 0.4.0 and writing the NMVP Inside-Out book (check out the draft in my blog), I haven´t had the time to think it thoroughly.


For the time being I think I can simulate such a structure by using a "Special Case Pattern" hostPresenter that, when it calls its HostPresenter property, is really just calling a reference to itself, then making sure I inject all datasources through the constructor. I think this strategy will allow me to better design to the framework, while still maintaining a very compositional nature. In fact, this design may be a good way to develop that Host/Container/View entity you mentioned.


If you are successfull in doing this, please share with me how you did it so we can create an example of a different usage of the framework.


I am starting to beleive the HostPresenter not working without a configurationContext is my lack of understanding. I will have to review the source code and project sample to clarify.


Probably it does work, but I´ll check it out.


P.S. A small recommendation as well may be to change the GetInstance() InstanceKey, and other similarly named propertie/method names to GetModel() and ModelKey or something similar to better reflect the intent of the methods/properties.


I thought of that as well, but I´m worried about backwards compatibility. Since it´s not a huge issue, I´ll leave it like that for now.

Hope to be hearing from you soon,
Bernardo Heynemann
Feb 23, 2007 at 1:32 PM
I do not have a lot of experience in practical design in multi-layered applications, so you may be right about injecting repositories instead of using manager singletons. However, I have seen them in use by people who are more knowledgable on application development than I, so it may be a matter of preference. An example is Billy McAfferty's MVP project on www.thecodeproject.com. Look at his enterprise MVP example. His design ideas is where I got a good chunk of my MVP knowledge. It does not seem to be a major issues because it is only a reference to the repository. Only the top-level application actually calls the factory method.

That's awesome that you like the composability idea. I know you are very busy with other things so I will be happy to explore how to make it work and let you know of any design breakthroughs.

Currently, the plan I have for it is as such:

1) Have all presenters (containerPresenter, presenter, and HostPresenter) implement the composite pattern by implementing the same methods as the current HostPresenter. (like addInstance, getInstance, etc.).

2) Whenever a presenter wants a resource, it asks its HostPresenter property for it (HostPresenter.GetInstance())
a) if the presenter IS NOT a root presenter, then the root presenter calls its GetInstance() method. If the
HostPresenter does not have the information, then the presenter calls its own GetInstance() method. If the
information is not there, throw an exception.
b) If the presenter IS a root presenter, then the HostPresenter property will simply skip step 1 of part a and
call the presenter's own GetInstance() method. If the inforamtion is not there, throw an exception or do
whatever.

I know there are some hidden flaws in this plan, but until I find them this is what I'll go with. I'll let you know of the issues that arise. I will probably use a wrapper class that takes in a parent presenter and the current presenter and is created inside the HostPresenter property setter. This way any calls to GetInstance() will actually make two calls: one to the parent presenter then, if unsuccessful, one to the current presenter without the current presenter knowing about it. I hope that makes sense, it sounds a little confusing even to me.

Talk to you soon. :-)

Coordinator
Feb 23, 2007 at 4:37 PM
I´ll write an article today or tomorrow in my Blog about the layers we use and the responsibilities that each of them must undertake. I hope that after that you can get some clarification on what you are trying to achieve.

Anyway, get my MSN: bernardo@perlink.com.br and let´s discuss later the implementation of the composable pattern. I believe the framework supports it as of now, but it could help making it easier to implement.

Bernardo Heynemann
Feb 23, 2007 at 4:40 PM
I won't be able to access MSN until either Sunday afternoon or monday evening, but I will add you when I get the chance.
Mar 1, 2007 at 1:45 PM
I made a mistake in my previous posts.

First off, the HostPresenter does work fine for me (well, except when adding Iterators to the runtiemInstances, but thats a different story).

I was wrong when I said you used a Singleton for your data access. Let me deomonstrate the difference in approaches between our data accessing strategies:

Mine:
 
public class WizardNeedsDataBadly : Presenter<WizardView>
{
  private IBadlyNeededRepository _repo;
 
  public WizardNeedsDataBadly(IBadlyNeededDataRepository repo, WizardView view) : base(view)
  {
    _repo = repo; //Repository is given from the Host/HostPresenter
  }
 
  public override void LoadCore(bool isFirstCall)
  {
     Wizard wiz = _repo.GetById(HostPresenter.InstanceKey);
     view.WizardName = wiz.Name;
  }
}

Yours:
  public class WizardNeedsDataBadly : Presenter<WizardView>
  {
    public WizardNeedsDataBadly(WizardView view) : base(view)
    {
    }
 
    public override void LoadCore(bool isFirstCall)
    {
      //your managers are the equivalent of my repositories, more or less
 
      IBadlyNeededDataManager manager = new BadlyNeededDataManagerImpl(); //Gets an instance of the manager itself;
      Wizard wiz = manager.GetById(HostPresenter.InstanceKey);
      View.WizardName = wiz.Name;
    }
  }

I hope this helps clarifies the differences in how we access data.
Now I remember you saying that you thought this made the datasources unchangeable, but this is not true. All the repository is is an interface that defines some CRUD operations. Beneath that is the Session/Workspace/third-party framework. For example, I have a ContactRepository that grabs Contact information from an Act! Premium For Workgroups database.
Now lets say my company decides that they want to drop Act because the upgrade prices are too high and create a custom database with SQL Server 2005. Well, all I have to do is create create the proper mapping files and make a StoreRepository implementation that uses NHibernate (this change would take mere minutes, since i have a Generic NhibernateRepository base class and usually only have a few convenience methods in addition to the base class). If my mapping files are embedded, then yes I do have to recompile the source code, but we can also load the mapping files dynamically if needed (although why no one ever does beats me). And lets say my company is fickle and says "well now we want to use Act again until next January", then all I have to do is change the RepositoryFactory to Create the Act implementation instead of the NHibernate implementation. This can be done dynamically in our Windsor Container.
Coordinator
Mar 1, 2007 at 3:21 PM
As I said in earlier posts Gilligan, your logic is flawless.
The reason I worry about the thing that you are doing is that if I have 200 different business managers, that means 200 different Data Store Contracts. You see the problem with that?

Now to the problem of getting data from ACT or from Database (I worked with ACT! I know the pain! hehehe). In my implementation it would be actually a matter of changing the business objects tier, since they are the ones that map the Relational World (whether it´s ACT!, Database, XML files or whatever) to a Object-Oriented World.

I´m not saying the way you´re doing doesn´t work. I´m just saying that for large to very large projects it could be an addition in cost that´s not very welcome.

Automating the injection you do for stores isn´t very easy as well, since they don´t have a common base interface right? So how would you add this in the framework:
public WizardNeedsDataBadly(IBadlyNeededDataRepository repo, WizardView view) : base(view)

I have all sorts of programmers in my teams, with very unique levels of knowledge and expertise. So I tend to reject error-prone methods. Not that if I´d do the way you are saying there would be errors. But explaining to a developer with little experience how to build contracts for each data store implementation and then get them from a Dependency Injection Container wouldn´t be very easy. Now multiply it for several teams and applications. The company I work for has just turned Certified Partner Gold, and we manage the Law Management System for the biggest Communications Company in Latin America. This application is HUGE. Can you imagine having contracts for every single business rule manager? I do agree with you that you are achieving a VERY interesting level of decoupling, since you can inject implementations of business rules implementations.
What I´m trying to say is that I got your data store contract and split it in two entities: a Business Objects and a Business Manager. The managers are coupled to the objects. Now if I must change the origin of my business objects, then I´ll change them. The Business Manager tier is untouched, because it only understands Business Objects, and their contract (their properties) won´t be changed when you switch databases (at least I hope hehehe).

I hope I´m making sense here. Let´s keep this discussion going. I do believe you would like to read a series I´m writing in my blog on N-Tier Development using MVP. The url is this:
http://manicprogrammer.com/cs/blogs/heynemann/archive/2007/02/27/n-tier-development-with-model-view-presenter-and-testability-part-1.aspx

Thanks for all the help with the Framework, Gilligan!
Bernardo Heynemann
Mar 2, 2007 at 12:56 PM
I will definitely read your blog. I believe we are both doing very similar things actually, but I may be wrong. I do need a couple of clarifications concerning the nature of the Business Manager (like what its API looks like), but perhaps I will find the answer in your blog. I love these discussions.