« [Tip] New for 2.2: ClientInfo() | Main | [Tip] How to run multiple instances of Servoy from within the same directory on Mac OSX »

May 25, 2005

[Article] Servoy Module Development Considerations and Best Practices

by Bob Cusick
Servoy USA

Beginning in Servoy 2.2 it's possible to develop solutions that can act as a "module" that can be included in one or more other solutions. Modules can be separately developed solutions - and thus are perfect ways to encapsulate, isolate and re-use business logic acoss multiple solutions. The use of modules is also great for multi-developer senarios where developers can work on their own "chunks" of an overall solution - and then can combine them into a single larger solution.

However, there are some practical issues that need to be considered when developing modules. The purpose of this document is to raise some of those issues and to offer some practical advice to keep in mind when developing modules.

Setting Up Modules

It's very easy to setup a solution to function as a module. From the File menu choose "Solution Settings" and choose "Module" from the "Type" popup menu.

Image002_5

By marking a solution as a module - it will NOT APPEAR in the "Open" dialog box in the Servoy Client. It will, however, still show up in Servoy Developer Edition so that you can modify it just like any other solution.

Including Module Solutions in Other Solutions

To include other modules in a solution - simply click the "Add" button under the "Modules" listing box in the "Solution Settings" dialog (File menu).

Image004_2

When you add one or more modules, they will show up in the "Modules" listing area in the "Solution Settings" dialog:

Image006_2

There are some limitations to which types of solutions you can include as modules:

1) The solution must be marked as a "Module" type

2) DO NOT CHANGE THE NAME OF THE MODULE. If you change the name of the module solution (in the Repository) - then NONE OF THE SOLUTIONS that use that module will be able to be loaded. To change the name of a module, first REMOVE that module from all other solutions, change the name in the Repository, and re-open the solution and go to "Solution Settings" and click the "Add" button to re-include the module in the current solution. All the functionality of the module will still work just as before (assuming no other changes have been made).

3) Form names MUST BE UNIQUE. If any modules have the same form name(s) - you will not be able to include the module in the current solution.

4) Relation names CAN be the same between multiple solutions - AS LONG AS they use the same exact primary and foreign keys on both sides of the relation. If they differ, then you won't be able to include the module in the current solution.

5) Global FIELD names CAN be the same between multiple solutions - AS LONG AS they are the same DATA TYPE. If they differ, then you won't be able to include the module in the current solution.

6) Global METHOD names MUST BE UNIQUE. If any modules have the same global method name(s) - you will not be able to include the module in the current solution.

7) "On open method" and "On close method" of module solutions WILL NOT "fire." If you require these methods to run (i.e. an initialization method in a module) - you need to have the "On open method" of the solution you're including the modules in call those module methods.

Module Behavior

When you include modules in your solution - they behave just any other form, relation, global field or global method within your solution. The important thing to remember is that the names of forms and the names of global methods MUST be unique.

If you have global variables or relations that have the same name between solutions - then in the case of global variables - they must be the same data type - or you will not be able to include the module.

Regarding relations with the same name - as long as all the primary and foreign keys are the same - you can have the same named relation. If they differ, you won't be able to include the module in the current solution.

When referencing forms or related values from a module within your solution - the syntax is exactly the same as if all the forms, global variables, global methods and relations were created from scratch in the current solution. That's why the naming conventions are so important - it is important that you can easily identify the module objects as opposed to objects you create in the enclosing solution.

In the Editor there is a new "Module" node - showing you all the modules included in the current solution. This is a great organizational help in locating forms and methods in the included modules.

Image008_1

One important thing for you to keep in mind is that although there is a new Module node - you do NOT have to include the module name when creating code. The "Modules" node is simply to help in the organization of your solution - it does not denote a new branch in the Servoy Object Model. For example, to navigate to the "customers" form that is in the module "mod_Intro_Forms" - you still use:

forms.customers.controller.show()

and you DO NOT use:

modules.mod_Intro_Forms.forms.customers.controller.show()

If you just double-click the "show" command on the controller object - you'll see that indeed the code that is inserted into your method is exactly the same as if that form were created in the current solution from scratch.

The "Forms" node still shows all of the forms created that are part of the CURRENT solution.

Calling Module Methods

As with navigational issues - you referece form methods and global methods in exactly the same way you would reference them if they were objects created in the current solution. For example, if you have a form method on the "customer" form in the module "mod_Intro_Forms" called "goto_customers" the syntax is:

forms.customers.goto_customers()

and NOT

modules.mod_Into_Forms.forms.customers.goto_customers()

Dealing with Global Variables and Methods

As mentioned earlier in this document the rules for modules and globals are:

1) Global Method names MUST be unique

2) Global Variables CAN have the same names as long as they have the same data types

You still reference global variables and methods in the same way:

globals.myVar = 'value'
globals.myMethod()

Dealing with Relations

Relations in modules and the current solution CAN have the same names IF all the primary and foreign keys are the same. For example, if you have a module called "mod_Intro_Forms" with a relation called "customers_to_orders" matching the customerID and you have another module called "mod_Orders" that has the same "customers_to_orders" relation also referencing the customerID in both tables USING THE SAME NAMED SERVER - then you'll see a single relation called "customers_to_orders". That relation will be valid on the forms from both included modules.

Naming Conventions

We've seen how critical it is to have unique names for all forms and for global methods. There are probably some cases where you will want to take care to name your global variables and relations with a specific naming convention to avoid possible conflicts in the future.

Here are some suggestions for naming conventions for objects within a module. These suggestions assume that these are in-house solutions - and NOT for modules developed for mass (generic) distribution. There are additional requirements for commerical modules that are discussed below. The suggestions below are a guildline for use as a starting place for your own naming standards:

1) Prefix all forms with "mod_" + a 2 or 3 letter abbreviation of your module's function. For example, if our module was a contacts module - one idea would be to use: "mod_cont_xxxx" for form names. You could also omit the "mod_" portion and just use "cont_xxx".

2) Prefix all methods that are specific to your module like your form names - but OMIT the prefix on global methods that can be re-used by other modules. For example, if you have a global method that takes a parameter to display an error message - then you can call the method "dialog_error" - or you'll wind up with several methods that do the same thing ("mod_cont_dialog_error", "mod_ord_dialog_error", etc.)

3) Prefix relations like forms and global methods except in cases where you think you'll re-use the same relation name (AND primary and foreign keys) in multiple modules.

4) Prefix global variable names like forms, global methods and relations except in cases where you think you'll re-use the same global name (AND data type) in multiple modules.

Coming up with a naming convetion strategy is a very important part of creating modules! Also, once you've decided on naming conventions - STICK TO THEM and DO NOT go around re-naming your ojects (unless you haven't included your module in any other solutions). If you do rename objects - then you'll have to perform "find and replace" functions for every object you renamed in every single solution you've included your module in.

Creating Commercial Modules

When you're creating a module for sale to others - it's especially important that you pay careful attention to naming conventions - or you risk "breaking" solutions that rely upon your module. Also, once you release your module - DO NOT CHANGE the name of any existing objects (forms, methods, global methods, global variables, relations) or anyone using your module in their own solution will have broken scripts.

When creating commercial modules - it's best if you ALWAYS prefix ALL your objects with some sort of name that will identify it as part of your module. Aagain, you can use the "mod_xxx_" prefix or just prefix it with your module or company name: ABCinc_Contacts_xxxx or any other method you can think of to ensure that your object names will be ABSOLUTELY UNIQUE across all the possible solutions (and other modules) that it will be included in.

You can also create modules that are NAMED the same as existing modules to replace the functionality of an existing module. For example, in the CRM example solution that ships with Servoy - there is a module called "mod_servoy_contacts". This module prefixes all the objects with "mod_cont_".

It's possible to create your own module called "mod_servoy_contacts" and prefix all your objects with "mod_cont_" and as long as you had all the SAME method names, relation names, form names, global variable names, and method names - you could add or change the functionality of the module and everyone that used the CRM solution only has to import your solution to use the enhanced functionality. BE CAREFUL: you must make sure that you include ALL objects (methods, relations, forms, global variables and global methods) - because you don't know what objects people are relying on if they re-use the module in other solutions.

You can also create modules with one or zero forms in it that can be used for helpful JavaScript routines, sample files, tip files, etc.

In general, the best types of solutions to use as commercial modules are ones that handle a certain task very well and are very comprehensive in scope. For example, FTP module, email module, bulk mail module, document management module, calendaring module, scheduling module, charting module, shipping module, etc.

Replacing an Existing Module

Replacing a module in a solution is very easy - simply import a new module solution wth the SAME NAME as an existing module solution. JUST BE SURE that you haven't renamed any objects - and the new module will work perfectly and will be available to all other solutions that use that module - without any re-coding whatsoever.

Changing A Module Name

In general - DON'T RENAME YOUR MODULE. If you just go into the Repository and rename your module solution - then any other solution that uses that module WILL NOT LOAD. Here's the correct steps to follow if you must rename your module solution:

1) Open each solution that uses your module and go into the "Solutions Settings" and REMOVE your module.

2) Open the Repository and rename your module solution

3) Open each solution that uses your module and go into the "Solutions Settings" and ADD your module back in.

As long as you haven't renamed any objects - the new module will work the same as before.

Other Considerations

There are certain features in Servoy that are specific to a solution. You need to keep in mind what will happen when you start including modules in your solutions:

1) You cannot edit a module solution directly within a solution, you must open it separately. If you have two instances of Servoy open at once you can edit the module, but then you must close and re-open the main solution to see the changes.

2) In Servoy each solution can have it's own i18n server connection and table - so a best practice would be to have a single server connection and table for all i18n entries. That way you can change and update i18n values from any solution or module.

3) "On open method" and "On exit method" that will not "fire" in modules. So it would be a good idea to include explicitly named methods that need to run in your module on startup and exit of the enclosing solution

4) Each solution can have multiple security groups that will be combined (based on name). That means if you have module A with a group called "users" that includes "ted" and "sam" and you have another module B with a group called "users" that includes "bob" - then when you have a solution that uses module A and module B - you'll have a single security group called "users" that will contain "ted", "sam" and "bob".

Conclusion

Modules in Servoy are a fantastic way to encapsulate business logic, resue functionality in multiple solutions, provide commercial solutions to common problems and more. It just takes a little planning to ensure that your naming conventions are going to work in multiple solutions.

| Posted by David Workman on May 25, 2005 at 12:31 PM in Articles | Permalink

Comments

Good News - Errata corrige

Modules now CAN contain other modules. Fabulous-Dev-Team removed the limitation!! (since 2.2 RC1)

Posted by: Automazione | May 26, 2005 3:49:10 AM

Post a comment