Feature composition by bootstrap Command
My project is modular. There's a main application - an e-learning environment - which varies according to which mix of modules each user has.
There are also a couple of toolsets - again modular - which the managers and administrators use to change stuff and view reports etc.
In the admin tool we added a feature which lets the administrator launch the personal-learning report for any user.
The feature has been well received and they've decided that they want any user who 'manages' other users to be able to use this within the main application - to launch reports for the people they manage as well as themselves. These user/manager relationships are already part of the system, so bringing in a list of managed users to populate this stuff isn't a problem.
In fishing through the admin module to work out what I need to bring over into the main application menu module (where this will live) I've realised that I can extract the required robotlegs wirings into a single bootstrap Command, and then just include that in the main menu module.
Normally I bootstrap by 'type' - I'll have bootstraps for Commands, Services, Models and so on. But I realised that it must be possible to bootstrap by 'feature'.
This 'managed users reports' bootstrap now contains:
- A mediator mapping for the view/mediator that lets them select a user and launch the report
- A command mapping for the command that picks up the event dispatched by this mediator and makes the url request
- A singleton service mapping for the factory that creates the list of user VOs from the xml
To include the feature in the main menu module I now just have to include this bootstrap command and hook up to use the factory for this data and add the correct view.
It really brings home the value of coding to interface contracts as well - if I want to vary the factory then I just switch in a different concrete implementation.
Is anyone else using bootstrap-by-feature? I'm thinking that I might play with this being my default approach to bootstrapping. Are there any gotchas?
Comments are currently closed for this discussion. You can start a new one.
Keyboard shortcuts
Generic
? | Show this help |
---|---|
ESC | Blurs the current field |
Comment Form
r | Focus the comment reply box |
---|---|
^ + ↩ | Submit the comment |
You can use Command ⌘
instead of Control ^
on Mac
Support Staff 1 Posted by Till Schneidere... on 17 Jan, 2011 04:40 PM
Thanks for the interesting discussion of bootstrapping, Stray!
This meshes nicely with the ideas that were brought up in
http://knowledge.robotlegs.org/discussions/suggestions/36-postmortem-mvcs-folder-structure-sucks-suggestion-use-a-modular-folder-structure-tied-to-your-project
The more I ponder these structuring-issues, the more structuring by
type instead of feature reminds me of using Hungarian Notation as a
variable naming convention. Including the bad taste that leaves in my
mouth ...
2 Posted by squeedee on 17 Jan, 2011 05:45 PM
I love by-module-by-type-by-feature! So Nyer... Or to put it another way:
Meanwhile, as for bootstrapping, for the same reason as my preference for module/type/feature (in that order), I bootstrap much the same way. Here comes the freakshow, I mean code:
That is the bootstrap sequence code for a single module.
Each step added, bootstraps a "by-type-by-feature". Of which, there are many :P
If you wanted to 'pull out a feature' then I'd imagine it'd either be a candidate for 'Extract Module/Component' or simpler, something that just needs five minutes of bootstrap cherry picking.
3 Posted by Stray on 17 Jan, 2011 06:18 PM
Nice!
While we're sharing freakshows... I mean code... in the small strategy game I just built the main context has:
// Map some Commands to Events
commandMap.mapEvent(ContextEvent.STARTUP_COMPLETE, BootstrapGameStartup, ContextEvent, true);
commandMap.mapEvent(ContextEvent.STARTUP_COMPLETE, StartGameCommand, ContextEvent, true);
And then BootstrapGameStartup does...
commandMap.mapEvent(GameEvent.GAME_STARTED, BootstrapModels, GameEvent, true);
commandMap.mapEvent(GameEvent.GAME_STARTED, BootstrapViewMediators, GameEvent, true);
commandMap.mapEvent(GameEvent.GAME_STARTED, BootstrapDayCycleCommands, GameEvent, true);
commandMap.mapEvent(GameEvent.GAME_STARTED, BootstrapGameEndingsCommand, GameEvent, true);
commandMap.mapEvent(GameEvent.GAME_STARTED, StartViewCommand, GameEvent, true);
commandMap.mapEvent(GameEvent.GAME_STARTED, ConfigureModelsCommand, GameEvent, true);
commandMap.mapEvent(GameEvent.GAME_STARTED, ProcessDayStartCommand, GameEvent, true);
And then the various Bootstraps in there each do their thang.
But boy, I can't believe I missed the need for a sugar method!
addStep(CommandToBeBootstrapped)
FTW!
I shall be stealing that in approximately 2 minutes.
Thank god this board isn't troll-tastic, or we'd be inundated with statements about how much "more code" this kind of solution is.
4 Posted by squeedee on 17 Jan, 2011 06:52 PM
If you want it: https://gist.github.com/783251
5 Posted by Stray on 17 Jan, 2011 07:07 PM
Thanks - that's nice!
I was even thinking of just adding an addStep(... ) sugar function to my bootstrapper to take care of mapping against the STARTUP_COMPLETE event or whatever - but your abstract sequencer is even nicer.
Cheers!
6 Posted by Weyert on 17 Jan, 2011 11:26 PM
You could even make distinction between mandatory and optional features where failing mandatory features will stop the application running. While failing optional features silently get ignored by the application. This way you can have a feature which loads configuration files optionally and a mandatory feature which deals with asset management.
Even you could then add some sugar and define at which moment the feature needs to be prepared. For example, during the preloading part or when during application launch time.
A simple feature could be:
The features could then be configured in the application context or something:
Not sure yet, what the best way is to deal with services because in this cause you would like to continue to the next step when the service is loaded and the model is ready prepared. I guess you can map it as a singleton after you manually instantiated it via injector. Something like:
Stray closed this discussion on 13 Feb, 2011 04:46 PM.