I have a design problem that I don’t know how to tackle.
My class tree looks roughly like below. The problem is that I have a navigation form within each solution module and all of them have exactly the same elements, so they all inherit from base_navigation_UI (only UI) which in its turn extends base_navigation that contains some common navigation code.
I want my navigation forms to have [moduleName]_validation form on the way down the class tree, so that validate() methods are called in module-specific forms when I click ‘save’ on my navigation form. In addition, I want my validation forms to have [moduleName]_commons form on the way down the class tree so that validate() methods could re-use module-specific methods that are already in place. As long as each module form will eventually inherit from [moduleName]_commons, I cannot put my base_navigation_UI below it. And if I put it anywhere above it will be located within a module and cannot be shared by other [moduleName]_navigation_UI forms.
I think the extending forms concept to encapsulate and extend functionality is most powerful when used situationally. For example, we have a code form that is extended with smart, web, iphone, and ipad view forms. Each of the view forms can extend or override core workflow methods on the parent code form. It gives us a tidy “bottom-up” structure to modify a view for its particular idiosyncrasies without diverging too far from the core functionality by accident (or intention).
Now, applying this functionality wholesale to an entire solution like the Servoy Commons Framework (and you) is doing I’m not so sure about. Enforcing a bottom-up structure to an entire solution is too much enforced granularity too soon for my taste. You are basically coding yourself one big lumbering box when it would be better to have a lot of little boxes that you can arrange into various tidy configurations as needed.
There is probably a solution to your situation staying with the bottom-up approach but I think it will require some form/code duplication to make it happen (since you can’t create a new form by extending two source forms). Which pretty much is what extending forms is meant to avoid.
I think the better approach for entire solutions is to have a mix of top-down and bottom-up structures and use the right approach for the situation. Navigation abstractions work much better with the top-down approach in my opinion.
Of course implementing top-down structures have their own unique issues to consider. How do you write default code so that it works for all included situations? How do you programatically call an event that is typically a user event? How do you extend/override default functionality down the chain? How do you handle and manage meta data? Etc.
Thankfully, when it comes to abstracted navigation controllers there are a number of good examples out there. Servoy’s included solutions have good examples. And check out our Data Sutra application platform for some ideas at least.
Keep in mind is that using the top-down approach doesn’t mean you give up the extending/overriding advantages of the bottom-up approach. For example, your navigation abstraction can have a default “save” method that can be replaced out with a “save” method on a form lower down the chain by first checking to see if there is a “save” method down the chain:
if ( solutionModel.getForm(formName).getFormMethod(methodName) ) {
// do method down the chain
}
else {
// run this code
}
Servoy allows for tons of ways to organize and abstract big solutions. Once you start breaking business logic into multiple modules, I think you gain more than you lose to have a few top-down structures in place to manage your growing application.