Suggested Code Naming & Documentation Guidelines
for Servoy Developers

 

compiled by

 



Servoy Training & Consulting
San Francisco, CA, USA
Website:    www.mcgilly.com
E-mail:       info@mcgilly.com

v 1.0 Copyright 2007, All Rights Reserved

 

 


1        Introduction

 

 

This article contains code naming and documentation conventions that I have found useful in my Servoy development practice. These are not hard and fast rules, just some ideas I have found helpful. Thank you to Sean Devlin, James Garfield, Bob Cusick and John Allen for their contributions to this document.

 

 

 

2         Naming Conventions

It is important to adopt a naming convention for all named objects in your solution. This helps make code more readable and will help you or someone else who comes after you understand your code more easily. Here are my recommendations:

 

Category

Object

Naming convention

Examples

Notes

Dataproviders

tables

lower case with underscores.

purchase_orders
po_line_items

 

 

db columns

lower case with underscores

first_name

credit_limit

 

 

calcs

clc_ + lower case with underscores

clc_total_cost
clc_customer_name

 

 

aggregates

agg_ + lower case with underscores

agg_total_cost

 

 

globals

lower case with underscores

 

 

sales_tax

in the editor, you need to put "globals." in front of these vars anyway, so there seems little point in adding another prefix

Presentation Objects

forms

a prefix indicating what kind of form it is:

dlg_   dialog
frm_  data entry form
lst_    list view
tbl_    table view
rpt_   report

followed by camel case.

 

It's also a good idea to prefix temporary forms that are for development purposes only with something like dev_ or _dev so that it's easy to find and delete them before putting the solution into production

frm_customers
lst_purchaseOrders

tbl_POLineItems
dlg_confirmImport
rpt_inventoryControl
dev_allCustomers

Note that camel case starts with lower case (e.g. purchaseOrder) unless the first letter is part of an abbreviation, in which case first letter may be capitalized (e.g. POLineItems)

 

fields

fld_ + camel case

fld_firstName
fld_city

Remember it is not necessary or desirable to name all objects on the form - only name the ones that require run-time manipulation such as enabling/disabling, show/hide, etc.

 

buttons

btn_ + camel case

btn_add
btn_closePO

 

 

labels

lbl_ + camel case

lbl_firstName
lbl_POStatus

 

 

checkboxes

chk_ + camel case

chk_orderClosed

 

 

dropdowns

drp_ + camel case

drp_status

 

 

radios

rad_ + camel case

 

 

 

html areas

html_ + camel case

 

 

 

tabpanels

tab_ + camel case

 

 

 

beans

bn_ + camel case

 

 

Business Logic Objects

relations

sourcetable_to_destinationtable

customers_to_orders

 

 

global relations

globalname_to_destinationtable

g_current_job_to_job_items

 

 

methods

camel case

closePO
getPOStatus
omitCancelledItems

- Don't be afraid of long names.
- Try to use a verb that describes the action the method performs

 

vars

camel case

var firstName
var nameList
var leadTime

 

3         Other Method Naming Conventions

When looking at a list of methods in the method editor, it is helpful to be able to to easily identify which ones are triggered directly by user-initiated events in the UI (as opposed to methods which are called from other methods). The following naming conventions achieve that result:

 

Form Event Methods

Methods attached to the form event properties such as onShow, onLoad, onRecordSelection, onNextRecordCmd, etc. should be named after the event itself. So for example the method attached to onShow should be called onShow. 

onAction Methods

Methods attached to the onAction event properties of an element should be named after the form element itself. So the method attached to the Save button called "btn_save" should also be called "btnSave". 

Other Event Methods

Methods attached to other event properties of form elements (e.g. onDataChange, onFocusLost) should be named after the element + the event name. E.g. the method attached to the onDataChange property of the fld_customerID field should be called fldCustomerIDOnDataChange or fldCustomerIDOnDC for short.

 

These "event handler" methods should never be called from other methods. If as you are coding you find that Method A wants to invoke the code behind some button, then put that code in its own Method B and call Method B from both the button and from Method A.


4         Naming Conventions for Modules

Servoy solutions can be broken up into modules, and a master solution can pull in at startup any modules it depends on. The master solution and its modules are all combined at run-time and act as one big solution. Solution A can call on any object (form, relation, method, calc, global var, valuelist, etc.) in Module B as if that object were a part of Solution A.

 

4.1      Pros and cons of using modules:

 

Pros

Cons

If several solutions rely on certain common objects (forms, relations, methods, calcs, global vars, etc.) you can avoid duplicating these in all the solutions by consolidating these objects in a module and invoking the module in said solutions.

You need to watch out for conflicts between the master and the module. If Servoy sees two identically-named objects of the same type (e.g. two forms named customers, two relations named customers_to_orders) it compares the two and if they aren't identical Servoy throws up an error message at startup.

Unless you buy the Multi_dev server from Servoy, if several developers need to work on a solution at the same time this is very difficult in Servoy, and not really recommended. Breaking the solution up into modules can facilitate multi-developer teamwork if each member works on a separate module.

 

 

4.2      Naming Convention Considerations When Using Modules

 

One way to avoid having name collisions among your solutions and modules is to prefix all object names with a something that identifies the module it belongs to.  So if you have a module called "CoreFunctions" consider prefixing all names of all objects with "CF_".  Of course this is only necessary for the high-level objects which can cause collisions (e.g. global vars, calcs, aggregates, global methods, forms, valuelists, relations, etc.)  It does not apply to lcal vars, form methods or form elements.  (Thank you to Sean Devlin for this suggestion)

5         Documentation Conventions

 

It is important to properly document your solution so that you can easily understand it later, and so that others who may have to maintain it after you can find their way around.  Here are some guidelines for achieving that.

5.1      Method Commenting conventions

Every method should begin with a header block that includes the following information:

§        what argument(s) it accepts (if any),

§        what value(s) it returns (if any),

§        who wrote it and what it's change history has been.

§        sometimes it doesn't hurt to put a short description in plain english of what the method does

 

Here are a couple examples.

 

/******************************************************************************************

 

      method name : getRecentAppointments

      usage: getRecentAppointments(nEmployeeID, [nNumberOfAppointments])

 

      input: nEmployeeID: an integer corresponding to a valid employee ID

             nNumberOfAppointments (opt): a positive integer specifying

                          The number of recent appointments to return

                          If none specified, then only the most recent

                          appointment is returned                     

     

      output: returns an array of recent appointments sorted in descending order by date.

              array columns are: start (datetime), end (datetime), description (text, max len 200)

     

     

      note:

     

      Change history:

      10/19/06                Adrian McGilly          Created method

      11/5/06                 Adrian McGilly          added optional parameter

 ******************************************************************************************/

 

 

This next example was provided by James Garfield. It documents a more advanced method called getDatasetAsArray which converts a dataset into an associative array.  Even if it's not clear to you what a dataset or an associative array are, the basic documentation format should still make sense.

 


/******************************************************************************************

 

      method name : getDatasetAsArray

      usage: getDatasetAsArray(oDataset, [bPKIndexed])

 

      input: oDataset: A dataset

             bPKIndexed (opt): if true is specified getDatasetAsArray will attempt to send

                               back a named array, indexed by PK. For this to work the PK must

                               be the first column in the dataset, as well as being distinct.

     

      output: returns the dataset transformed into an associative array

     

      description: Array is indexed as such  oDS[i]['colname']; i being the row index, and

                         'colname' being the DB column

     

      note:

     

      Change history:

      10/19/05                James Garfield          Created getDatasetAsArray method

 ******************************************************************************************/

 

Note that to achieve the desired indentation you can make use of the "indent" command in Servoy's editor: select the line(s) you want to indent and hit tab to indent, shift-tab to un-indent.

 

There should also be comments imbedded thoughout the body of the code that explain what is being done. Sometimes this can be a simple comment next to a line of code using the '//' to start the single-line comment. Other times it may be necessary to put a short paragraph (using "/*   comments   */)  of text ahead  of a block of code explaining the overall logic of the block, and to supplement this with in-line comments.

 

To make a self-reminder of something in the code that still needs to be done, people often put a comment beginning with //TODO.  Not only does Servoy highlight any comment-line that begins with TODO in red, making these comments easy to spot. but you can oc course search your code for the word 'TODO' and locate all tasks that still need your attention.

5.2      Method for documenting the solution: _docSolutionName 

Each solution should contain a method called "_doc" followed by the solution name (e.g. _docPOSystem or _docCoreFunctions) which provides information about the solution as a whole. This should include version info, overall purpose of the solution/module, revision history, etc. Including the solution's name in the name of this method ensures that you won't have collisions among these standard documentation-only methods if several solutions/modules are open at once.

5.3      Method for documenting global vars: _docGlobalsSolutionName

Global variables should all be declared in the Globals tab of the Dataproviders window. Because there is no place in that window to put any comments about each global, you should create a global method called "_docGlobals" followed by the solution name. There you should list each global var and explain its purpose

5.4      Method for documenting each form: _doc or _docFormName

Each form should have a method called _doc whose purpose is to explain the overall purpose of the form, how it is used (e.g. is it used as a main form or in a tabpanel(s) or both) who designed it, any important revision history regarding the layout, etc. If you prefer, you can name this method _doc + the name of the form it documents.