Lazy-loading of modules

Topics: CAB & Smart Client Software Factory
May 10, 2007 at 7:24 PM
Hi there,

I am working on a very large CAB application and one thing that might be a concern in our application is the number of modules that have to be loaded on startup.

In our scenario, we would probably have a single module loaded at startup time (in the profilecatalog). Obviously, the inherent problem to this is how can another module be loaded on-demand? Let`s say that Module 1 as an event publisher and module #2 (not loaded) has a subscriber to this event. The subscriber in module 2 is going to be executed because it is not loaded into memory.

I found an article about a custom implementation of the IModuleLoaderService using a ProfileCatalogOnDemand.xml file but this solution only address half of the problem. You still need a logic to determine what modules need to be loaded and when based on specific criterions.

Does anyone figured a way to handle this problem yet? I can think of 2 solutions but i am curious to see what has been done in the community about it.

thx.
-Jonathan G.
May 10, 2007 at 8:36 PM

Does anyone figured a way to handle this problem yet?


Yes: don't load modules on-demand.

I mean, you have to first ask yourself what problem you're trying to solve. The root of the problem is memory footprint. You're worried about your application being too big. But if during the course of operation your application needs module A, B & C loaded into memory then you're not going to solve the memory footprint problem by lazy-loading modules. You're just going to delay an Out of Memory exception. And you can't unload modules, so what's the point of delaying loading until an exception occurs?

This is the red herring of CAB development problems.

If Module 1 publishes an event that Module 2 has to listen for, then both of those modules need to be loaded in memory. They're both related to the same use case, so why aren't they being loaded together?

The better solution (imo) is to figure out what use cases you have and code your application so that dependent use cases reside in the same module or in modules that can be loaded together. Then associate use cases with user roles. In this way you can modularize your application such that when a particular user logs in, only the parts of the application that they require will load. Thus, you could have a giant CAB application that, if all modules were loaded on startup, might exceed the bounds of your memory capacity, but you can prevent that from ever happening because you have wisely coded your use cases to match user roles, and so no user role will ever require the entire application to be loaded at one time.

That's just my 2 cents.

-Chris



May 11, 2007 at 1:30 AM
Chris,

The problem i am trying to solve is not memory footprint but performance at start-up of the application. I simply don't want to load 250 modules with well defined Use case boundaries before the user can do any action. This is not the first time I see the all related use cases in a same modules, but at the end of the day, you always end up with first-level use cases that need to be triggered somewhere. It could be from a presenter in another module or from a UIExtension site in an infrastructure module or else, but it has to have a hook somewhere. I could have a UIExtensionSite corresponding to a menu entry that needs to initiate a new Use case (usually done with a Command but still an event) from a new module. The current documentation would tend to say that such uiextensionsite should actually be registered from the module with its corresponding Use Case, but I don't think such design is good for very large applications, because you will have no choice but load all modules at start-up, each one responsible to register their UIExtensionsites and menu items.

Thanks.
-JonathanG

May 11, 2007 at 8:22 AM
There are 2 possible solutions for this.

1. By hand.
You create a new Moduleloader, which is interpreting a new entry in the profilecatalog that has all the
Events a module should react on.
Here you are responsible for the entries you are reacting on.

2.
You create this type of list at startup by reading all modules and getting the EventSubscripers from your WorkItems.
Here you have a delay at startup, that is smaller than the actual loading of the module, but prop. noticable.

The moduleloader than can register a stub for all events, and react on them by loading the/all modules.
May 11, 2007 at 12:03 PM
Edited May 11, 2007 at 12:06 PM
First I would like to state that it is difficult to come up with a creative and good solution to your specific issue without having more knowledge about the application. That being said, my gut feeling is that this is partially a module separation problem and partially a CAB specific problem. Loading the code for 250 "modules" is going to take time and memory no matter what framework you are using unless you have some lazy loading built in. I agree with Chris on putting related things together, and for your specific case it doesn't seem to matter if the issue is memory or performance. I am going to set a few assumptions and propose another solution in addition to what have been said already.
1) You deploy all your modules together. (eg. you know at deployment time what modules are installed)
2) Startup time is more important than code maintainability and some additional dev time. (think of it as the price you pay when you de-normalize a table to avoid a join for performance reasons. You get added performance, but you need to manage data redundancy etc.)
3) The majority of your 250 modules are not first level use cases.
If these three assumptions don't match your scenario you should feel free to skip the remaining part. :-)
With those out of the way I would consider the following:

1) As part of your build process generate a dependecy tree reflecting which modules subscribes to events published by what other modules. Save this dependency tree as an xml file that is deployed with your application. The reason for doing this at build time is to avoid iterating over all modules and reflecting over them their dependencies every time the app is started.
2) Include only the modules you always want to load in the profile catalog.
3) After the CAB has loaded whatever modules that were listed in the profile catalog, check the list of loaded modules against the dependency tree created during build time.
4) Send a request that all loaded modules report if their dependencies are loaded.
5) Start loading depenedent modules
6) At this point any module that gets loaded will check if its dependencies are loaded or not. If they are not, the module will request that these modules get loaded as well. The loader "service" will of course check if the requested module is loaded or not...

I'm not sure I like this approach, but I don't like to denormalize either. I am willing to pay the price when I have to though.
I've never worked on a project with that many modules, and there may be aspects I'm not aware of.

Good Luck.