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.
(with no options) to ensure consistent code layout.
use strict; use warnings;
- 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.
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 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
- OO methods should use the
ObjectMethod descriptors for the external API (see any core module for how these are used)
# 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!
- 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.
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).
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
die (call it only if you're sure that it will be caught by the exception mechanism)
Foswiki::Response methods instead of
Foswiki::Request methods instead of reading
%ENV or from
- 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
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.