FoswikiCodingConventions

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

Comments

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.
Topic revision: r4 - 01 Sep 2015, CrawfordCurrie
The copyright of the content on this website is held by the contributing authors, except where stated elsewhere. See Copyright Statement. Creative Commons License    Legal Imprint    Privacy Policy