DEVELOPERS, FEEL FREE TO ADD TO THIS DOCUMENT
Foswiki is a large and complex system, combining contributions from many different individuals. Coding conventions have had to be learned from existing code, developed by iterative evolution, or have been ignored. This topic aims to address that by describing some of the standard memes used in Foswiki. Note: we don't claim that the Foswiki way is the best way! This is just the result of experience.
This topic is aimed mainly at
core developers, but the same principles described here can be applied to extensions as well.
Code modules
We use
perltidy
(with no options) to ensure consistent code layout.
- Always
use strict; use warnings;
- Usually
use Assert
- Do not use module exports.
use
statements should always be followed by ()
and references to functions and variables in other modules should be fully qualified.
- Inheritance should be done using
use Baseclass; our @ISA = ( 'Baseclass' )
-
use
any modules explicitly at the top of each file, even if you know you can implicitly assume the module is already loaded. It's important for documentation.
- Use
our
for static variables. Avoid global variables wherever practical (but don't go over the top with accessors). Comment global and static variables clearly, and use a POD comment (see below) for those that are intended to be visible outside the module.
- Use
use constant
for constants
When you are writing code and comments, try to think like a reader, rather than a writer. Imagine you are coming to the code for the first time, and trying to understand it. What comments will help you understand the code? Is the code readable? Do the comments enhance, or detract from, the code?
- All code modules should have a copyright and license notice. It is best to place this after an
__END__
and add a single line comment at the top See end of file for license and copyright information
(perl is very, very, slightly, barely-measurably faster if it doesn't have to skip comments at the head of files).
- Externally visible functions/methods/variables should have a POD comment, between
begin TML
and cut
.
- OO methods should use the
ClassMethod
, ObjectMethod
descriptors for the external API (see any core module for how these are used)
- Use
#
comments for private, internal methods (do not use POD comments for these)
- Delete comments that are not applicable. Do not leave large amounts of comment cruft (e.g. inherited from EmptyPlugin.pm) - it just confuses the reader.
- Use SMELL and TODO comments to mark things you think need refactoring. Make sure SMELLs and TODOs are clear enough that other people can understand them, and preferably leave your initials!
Naming
- Private functions (those that are not callable outside the module) should have an underscore prepended to their name. NEVER call a private method outside the module where it is defined. If you have to, the method should not be private, so refactor it!
- Use English
- Function/method/variable/constant names should always be meaningful and consistent - if another module defines a method which provides the same functionality as a method you are writing, then use the same name (or, if appropriate, define a base-class)
- Function (and variable) names should start with a lower-case character. Use camel-case to separate words in the name e.g.
$useCamelCase
APIs
It may seem obvious, but
use the internal APIs. Don't under
any circumstances, kick down, through, around, over or below an API and (for example) access the filestore directly, or bypass the Foswiki engine. If an API doesn't do what you want, then
fix the API (and, of course, all the modules that implement it).
CPAN
Foswiki has a number of dependencies on CPAN modules. These dependencies are a compromise; we don't control CPAN modules, but on the other hand, we don't have to maintain them either.
- Don't add dependencies on CPAN modules (other than those shipped by default with the perl core) without discussing it first.
- If you find that Foswiki duplicates a CPAN module unnecessarily, then consider refactoring the Foswiki code to leverage CPAN.
- Don't assume CPAN modules are better than Foswiki code! The quality (and efficiency) of many CPAN modules leaves a lot to be desired.
The Foswiki Engine
The Foswiki engine is designed to allow easy portability between different calling environments e.g. command-line, CGI, mod_perl, fcgi etc. For this portability to work:
- Never call
exit
- Avoid
die
(call it only if you're sure that it will be caught by the exception mechanism)
- Call
Foswiki::Response
methods instead of print
- Call
Foswiki::Request
methods instead of reading %ENV
or from stdin
- Take great care with circular references, as they can result in memory leaks (perl GC does not detect disconnected subgraphs)
- Don't assume that some particular engine is been used
- Always close file handles (if you must open files, we recommend the use of
IO::Handle
, so handles are closed when out of scope)
- Always be sure that forked applications terminate
Debugging and Testing
- Write debug information using
Foswiki::writeDebug
- don't rely on print STDERR
, as it is often captured and redirected.
- Use
DEBUG
and ASSERT
freely.
Unit testing is described in depth elsewhere. Suffice it to say that any new code you add should come with unit tests. These are very, very important for a number of reasons:
- Unit tests give us early warning if anything breaks.
- Unit tests protect your investment; if anyone changes your code, the tests will fail and you can tell them to fix it.
- Unit tests make code development significantly easier (for example, you can use the debugger with them)
- Unit tests are an important part of the specification, enhancing and clarifying documentation.