plainblack.com
Username Password
search
Bookmark and Share
Subscribe

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

Since it's hard to test www_ functions, they don't need to have tests, but all others should. See Developer's Guide To Testing In WebGUI.

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.

3. Internationalization

All messages to the user should be retrieved from an i18n language package. See Internationalization.

4. Templates

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

See The Help System.

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>

13. All labels should have hover help.

14. Browser Compatibility (to do)

15. Class inside-out

It is not required to use Class::InsideOut any longer.

Keywords: api Best Practices Development pbp plugin testing

Search | Most Popular | Recent Changes | Wiki Home
© 2018 Plain Black Corporation | All Rights Reserved