Development guidelines

De Organic Design
Info.svg This document is for developers getting getting on board with an Organic Design project, or working with Organic Design on a client project.


Over the years Organic Design has developed a lot of MediaWiki extensions and accumulated a lot of useful MediaWiki code snippets, as well as writing some useful (and some not so useful!) tools and utilities in other programming languages. While some of this code is hosted right here in the wiki, our most commonly used and actively developed code is in our Git repository which can be viewed either locally at code.organicdesign.co.nz, or on Github at github.com/OrganicDesign.

Coding style

It's important to have tidy, uniform, well-commented code so that it's clear and readable, easy for newcomers to understand and integrate with, and is something all the team are happy being associated with since it's all open source and public. Most programmers have their own style which they are often quite attached to, but when working on a collaborative project they have to put aside these attachments and conform to the style the project uses so that the code style remains uniform across the whole project.

Nearly all of our projects are MediaWiki-based projects, and we like to adhere strictly to the general MediaWiki coding conventions and to the language-specific conventions, the most important for us being the PHP coding conventions and the JavaScript coding conventions. But apart from these conventions we also have a number of important points concerning the general methodology of working on a project.

It's useful to set the interpreter to strict parsing because many of the strict warnings are about things that may become mandatory in future versions, or about deprecated features being used that will be removed in later versions of the language, and also some servers may have more strict standards enforced which would mean that the code would fail to run in these more strict environments. Overall, having code that conforms to strict standards is more reliable code that's less prone to bugs, and is usually easier to track down bugs in when they do occur. In PHP strict standards can be used by setting the E_STRICT flag set in the error logging, and in JavaScript you add "use strict"; (quotes included) to the file or scope you want to apply it to.

Independent code

It's a fact of life that coders come and go - usually due to other work commitments rather than being hit by buses. For this reason it's extremely important when working on a project, to ensure that you haven't done anything in a way that requires you to be contactable should it ever break, or changes need to be made to it. All code should be written in a way that makes as few assumptions about the environment as possible, as it may have to run under a variety of different operating systems or domains.

Code should be written in a way that is independent of what else might be running in the environment, which means avoiding the global namespace where possible by encapsulating functionality into classes, and when essential use a name that is based on the extension name such as $wgFooUseAjax for telling extension "Foo" to use its Ajax functionality. In Javascript all functionality should be wrapped within a closure. If you're unfamiliar with closures or still find them a bit of a mystery, please read JavaScript#Closure and some of the further reading it recommends.

Including other code

When including extensions or dependencies we normally use the include directive rather than require, require_once or include_once. The reason for this is that include only raises a warning rather than a fatal error which means that if there are many items that fail to be found the errors will all show at once if using include instead of require. We prefer not to use the _once form because we prefer an error to be raised when functions or classes attempt to be redeclared from a double include so we are aware it's doubled up and can remove the redundant statement.

An exception is that require should be used if more serious problems may be encountered if the item is not found such as uncommitted database writes or other data inconsistencies. This should never be the case with the inclusion of extensions, but might occur in the case of libraries and other dependencies within an extension.

Another exception is that the _once type should be used when more than one extension may possibly include the same class or library, however the dependencies are usually packaged with the extension's code, so it may be best to check if the class already exists first rather than relying on a require_once directive.

The Wikimedia project is now using Phabricator to handle extension and dependency installation, but Organic Design hasn't yet migrated it's workflow and procedures to this methodology. The Wikimedia project has also migrated its bug reporting system from Bugzilla to Phabricator and is in the process of migrating its code-review system from Gerrit and Jenkins to Phabricator as well.

Code-base hacks

Probably the most important point to raise is about code-base hacks. This is where in the process of working on a feature or bug-fix, the developer decides to modify the code in a third-party extension, or in the MediaWiki code-base itself.

This is extremely bad form and should be avoided at all costs! Once a code-base hack has been made, it means that this code is no longer able to be updated without re-implementing the code-base hack again. This means that details about the hack must be added to the upgrade procedure and the hack will need to be tested every time and perhaps modified depending on what changes have been made to the third-party code. In practice such a rigorous procedure is never followed and so either the code breaks on upgrade, or the upgrade of that code is avoided and it no longer benefits from the new features or security updates made by the authors.

When the functionality of third-party code is required, you can usually achieve it using the hooks provided in the code, or if there are none provided for your requirements, you can write another extension that overrides the third-party extension's instances at run-time. This latter approach can require ongoing maintenance, but is a far better approach than the code-base hack. Please add the Voodoo template to the documentation if you've had to override instances at runtime.

Documenting and maintaining procedures

Sometimes the development of certain aspects of the project may require the installation of new components into the operating system, or require configuration changes to existing components. When this is required it is imperative that these changes to the environment be added to the appropriate documentation in the project's wiki. Usually the project will have more than one server which the alterations will need to be replicated on after they've been reviewed and tested. Also the alterations will need to be included when new servers are installed or when reinstalling existing servers during upgrades of operating system or hardware.

Please ensure you follow the existing style when editing documentation including the use of nowiki and tt tags when describing things which need to be entered into the computer or will be displayed on the screen, using italics when specifying path locations or identifiers, and using source code blocks with the appropriate language attribute.

Logging and charging time

Please keep a record of your work sessions and email me when each session is complete with start time, end time and a description of the items done during the session. Remember that you don't get paid to watch progress bars! If the tasks you're doing involve a lot of time waiting, for example for things to compile, then either do another part of the job at the same time, or account for the down-time by adding to the logged start time. The same goes for spending time inefficiently if you're doing other things at the same time like watching youtube or working on other jobs, or you're just generally unfocussed, then please try and log an amount of time for the session that reflects how long it should have taken. If you log a lot of time and achieve little, then in the long run you make yourself look bad and are less likely to be asked to work on future projects.

Another issue that comes up with regard to charging concerns learning new skills and setting up or refining your development environment, for example learning to use Git or Subversion or installing a local web-server. It's not right to charge for the time it takes to do these things that are almost a prerequisite these days, and are expanding your opportunity space. It's equivalent to a tradesman buying a new machine for his workshop so that he can take on more jobs and compete more effectively with the other providers of his trade, and then invoicing the next client with an extra thousand dollars for the cost of his new machine! It's a similar situation with learning new skills. You'll take a lot longer to achieve a task if it involves a lot of learning along the way, and the final amount you charge for the work should be based on what a professional who knows the area would charge for that same task.

The extra hours you're putting in for learning a new area or installing new tools are your business expenses, because you're the one that has the potential to benefit from them over and over again in the future. The benefit that your client receives from your extra skills or tools is the same as he'd receive if he were to pay another professional with those skills to do the same work, so where's the justification for the extra charges he gets?

Resources

If you're new to MediaWiki development, here are some useful resource that you should check out to become more familiar:

MediaWiki deprecations and new features

If you are familiar with MediaWiki development, then you may find this list of recent developments useful.

  • 2015-11: 1.21 is giving errors in MagicWord.php about regex group having to start with a non-digit on recent versions of PHP, this can be fixed by using 1.25's version of the getBaseRegex function.
  • 2015-06: 1.25 has a new way of loading extensions, see MW:Manual:Developing extensions and MW:Manual:Extension registration
  • 2015-03: The Ajax dispatcher is deprecated now, you should write an API module to handle Ajax requests, see Extension:AjaxComments for code sample
  • 2015-02: Mustach templates for 1.25
  • 2015-01: wfRunHooks deprecation (use Hooks::register and Hooks::run now)
  • 2014-06: wfMsg(key) is deprecated now (use wfMessage(key)->text instead)

Comentários