Development Best Practices

One of WebGUI's greatest strengths is that it works on many operating systems and can connect to many external resources such as LDAP, Database, and web servers. If you're planning on writing plug-ins for or making core changes to WebGUI you should follow the coding guidelines presented here to ensure maximum compatibility. In addition, WebGUI has been built with performance in mind; we try to keep our code neat and elegant, so should you.

Perl Best Practices

We, as a community have decided to adopt Perl Best Practices (PBP) as our best practices for WebGUI. As far as we are concerned you might as well scratch "Perl" off the cover and replace it with "WebGUI".

Note that you can use the CPAN module Perl::Critic to locate PBP violations in your code. Your code should pass Perl::Critic on at least the gentle setting.

The following guidelines are areas where we have decided to override the rules set forth in PBP.

1. Underscores (PBP page 44)

Do not use underscores to separate words in
multiword identifiers as defined in PBP p44. Instead use camelCase. The
reasons for this, as given by JT in the dev mailing list, are two-fold:

Firstly, people coming from other languages are more likely to be familiar with camelCase than underscore_separation.

Second, and more importantly, we can't go to underscore_separation without breaking the API, which goes against the API compatibility promise.

2. Implicit Returns (PBP page 197)

Do not use "return;" as defined in PBP. Instead
use "return undef;". This is because "return;" does different things in
different contexts, which can cause problems that are unforseeable.

3. Line Lengths (PBP page 18)

Instead of 78 characters per line, we've chosen to
go with 115 characters per line. The reason is that the lowest
resolution any of the core developers is likely to use is 1024x768, and
even on that you can view an editor with 120 characters. In addition,
we don't often print out our code, so we don't have to worry about it
fitting on a printer.

Note that if you are using Perl::Tidy to automatically format your code according to PBP pages 34-35, you can achieve this via:

perltidy --perl-best-practices -l=115

WebGUI Best Practices

The following guidelines are areas where we have decided to further clarify the rules set forth in PBP. We've created these guidelines to keep the WebGUI code clean,
self-documenting, and easy to read. If you follow the same guidelines
your code will stay easily manageable.

1. All testable functions should have tests

2. Every module and function should have POD documentation

Describe how to use the functions and what parameters can be passed to the function. See Plain Old Documentation (POD). After implementing new functionality always write/update any
relevant documentation and/or help files. Doing this as you create your
code will ensure that everything is always up to date.

Definition subroutines do not need, POD, but all other subroutines do. If you are overriding an inherited method, then tell why in the POD.

4. Templates

4.1. All template variables should be documented in a help module.

4.2. All user www_ and email views should have selectable templates.

Apart from the Operation/Profile/View, the Operation/Profile/Edit
and the Send Invitation Template almost all templates are selectable.
And almost all views are templatable.

4.3. Template Names

Never use . or any other punctuation in your template variable names. Underscore is okay.

4.4. Perl Generation of HTML/CSS

HTML and CSS that is generated from Perl creates difficulties in
creating and maintaining templates. Avoid generating HTML or CSS in
Perl code. If CSS is needed, add it to the asset's stylesheet. If an
asset does not have a stylesheet, add one.

5. Javascript

If you use javascript, use the YUI library.The Yahoo User Interface Library YUI (http://developer.yahoo.com/yui/)
is a Javascript/Ajax library that is bundled with WebGUI. Use it. Make as many reusable
parts as possible.

6. Reuse code

Don't reinvent the wheel. Save yourself a lot of time and effort by using code that someone else has already written for you.

We've built a decent sized code-base within WebGUI. Much of the
functionality needed by plug-ins has already been developed; such as
URL rewriting, database access, date math, discussions, etc. Also, you
may find that the functionality you are looking for has been written by
someone else and stored at CPAN (www.cpan.org). The easiest way to find useful modules on CPAN is to use Search CPAN.

7. Stay database agnostic

If you're careful about how you construct your database statements,
you'll be able to stay database agnostic. Here are a few hints:

All inserts should take this format: insert into table (column1,column2, column3) values (field1,field2,field3)

All updates should take this format: update table set field1='value', field2='value', field3='value' where field4='value'

Do not mix static fields with group by functions like this: select field1,count(*) from table group by field3

Be sure not to use functions that are database specific. For
instance the date functions in most databases are database specific.
Instead use a built in WebGUI library, or create your own external
methods to handle those cases.

If you get row data using hashes or hash references, always tie
your hash to Tie::CPHash. This keeps the hash case-insensitive. It's
important because some databases return column names all uppercase,
some are all lower-case, and some are mixed-case.

If you muck around with database tables for an upgrade script,
especially asset, assetData, or wobject tables, you need to test back
beyond the current upgrade to 6.8.10.

8. Methods and Subroutines

8.11 Put a horizontal separator above each "sub" statement

#-------------------------------------------------------------------

sub myMethod {..}

8.2. Keep your methods and subroutines in alphabetical order

8.3. Always mark private methods with an underscore

sub _privateMethod {

However, try never to make private methods, unless they absolutely
need to be private. You never know what someone outside your module
might need from your module, so consider making all your methods public
unless they're subject to change or be removed in the near term.

8.4. Always mark methods that are accessible to the web with www_

sub www_myMethod {

8.5. Never abbreviate anything

This means that your subroutines, variables,
table names, etc. should consistently have long meaningful names. This
keeps the code readable.

8.6. Refrain from using the default variable ($_)

Refrain from using the default variable ($_), especially in passing method parameters ($@). Instead, shift off all of the method parameters.

9. Use object-oriented design where it fits and procedurel where it fits

Use OO Design (object-oriented) where it fits and procedural design
where it fits. Contrary to popular belief one is not wholly better than
the other, and there is a need for both; especially in Perl. For
instance, objects are anywhere from 50% to 200% slower than procedural
code at runtime (depending upon the situation and the benchmark used).
However, objects typically lend themselves to more powerful and
reusable functionality. Refer to PBP p319 for further discussion.

10. Balance method granularity with code readablity

You can always
make something more granular later, but once it's granular, going back
means breaking the API.

11. Namespaces

For any plug-in you create, select a namespace that is not currently in
use by any other plug-in. Make sure that your namespace is descriptive
and useful. Use namespaces in package names, incrementers, tables,
help, internationalization, etc. Here are some examples:

package WebGUI::Asset::Wobject::MyNewWobject;

create table MyNewWobject ();

create table MyNewWobject_colateralData ();

In any of your asset collateral tables, name the primary key something
descriptive. If you need an incrementer for your key, use the table
name combined with the column name as the incrementer name. Every
incrementer should begin with the namespace to prevent overlap.

12. Accessibility

All HTML that your code produces (from your default templates or other means) has to be accessible.

12.1. XHTML 1.0 strict compatible

12.2. CSS 2 or 3 compatible

12.3. WCAG Priority 1 compatible

12.4. Section 508 (US) =~ Webrichtlijnen (NL) compatible

12.5. Links

Do not use target="_blank" to open new windows and do not use javascript unless there is an alternative to access the content.

12.6. Links to files

Links to files should offer the option to save them or to open them.

This could be reached by adding something like this to all modproxy templates:
<IfModule mod_headers.c>
<FilesMatch "\.(pdf|ppt|doc)$">
Header append Content-Disposition "attachment;"
</FilesMatch>
</IfModule>