view doc/policies.txt @ 10:4c3575400769

DefaultData largely rewritten with unittest, SDL input event handling completed with unittest, changes to Init threading. Init threads now catch own exceptions. Doc: assigned some inputID devisions. Added support for remaining SDL events. Input axes' output is now stored with a short instead of a real. Input unittest written (for SDL event handling). Rewrote most of mde.mergetag.defaultdata using generic programming to generate read & write rules for all types. As a direct result, defaultdata can now write properly. DefaultData unittest written (also provides testing for mergetag read/write). Moved mde.text.parse/format to tango.scrapple.text.convert.parseTo/parseFrom with many changes. committer: Diggory Hardy <diggory.hardy@gmail.com>
author Diggory Hardy <diggory.hardy@gmail.com>
date Mon, 18 Feb 2008 11:54:56 +0000
parents f63f4f41a2dc
children bff0d802cb7d
line wrap: on
line source

This is a collection of all coding policies for the mde engine as a whole. Policies for individual packages should be put in the individual package directory or elsewhere.

These are principles, not cast-iron rules, which I (Diggory Hardy) generally try to adhere to. If any other programmers have better principles to apply over these rules, they may do so for their own coding providing they have a good reason (i.e. not simply wanting to be a little different).

A warning: I have several times changed my mind about items I've written here. So don't expect all existing code to conform, and if you feel that a principle listed is not a good idea don't think you have to conform to it.



Coding conventions: Mostly stick to those provided in the D specification. Generally indent with four spaces and use tabs to align comments. Keep editor's tab-width at 8. Aim to break long lines at around 100 chars (particularly with documentation); this isn't essential but provides a good guide and keeps text looking reasonable. With code, however, breaking lines doesn't always produce better-looking code.

Identifiers: as for the D spec, use descriptive words for identifiers, although try to keep them from being overlong. Use capital letters to show separate words, not _s. E.g.: file, readFile; not: rdFile, read_file, readFileUsingMyMethodNow. Again, this is only really a guideline.

Module/file names: unless you have a good reason, keep names all lower-case. And if you're programming on windows, make sure you always use the correct capitalisation (yeah, of course...).

Spelling: Use british or american (or other) spellings as you like, but BE CONSISTANT at least for code symbols within packages (i.e. if you write your own package you choose the spelling, and for comments it doesn't matter, unless it's actually refering to a symbol). For text output to the user there need be no convention until internationalisation support is built-in. As far as internationalisation/localisation is concerned, does it make sense to translate log messages or not? (They are going to be seen by end-users, but will largely be used by developers.)



Package design principle: use a separate package for each module of the engine. In most packages where there is only one module (file) imported by other parts of the engine, that module should have the same name as the package and be designed to have a standardised interface to the package so that the package could be replaced with another as a drop-in replacement (written with the same interface). Of course in many cases it may not be possible to swich one package for another quite this easily, but holding to this principle should at least minimise the amount of work necessary when doing so.


Module imports: modules should publically import dependancy modules likely to be needed by dependant modules, in particular the package-level exception module (where used & use by dependants is expected).


Engine-wide initialisation and cleanup should be handled or invoked by mde.init.Init's CTOR and DTOR methods where this is viable.



Logging should be handled by tango's Logger class. A logger with the name mde.package.module or mde.package.module.X where X is a symbol within the module should be used for each module. Thrown errors should, where documented, be documented with a log message; an exception message may be used to produce the final log message but must be output via a log message.

In general the levels should be used as follows:
	Trace	Where required or thought highly useful for debugging, and only compiled in debugging mode.
	Info	Sparingly, for informational purposes (e.g. when parsing a file). Should not generally be used repetitively (within loops, etc.). Not for reporting unexpected behaviour.
	Warn	For small errors which can be overlooked, even if they MAY cause bigger problems later. I.e. something unexpected, but not necessarily a major problem, happens.
	Error	For errors which directly:
		• cut-short a (reasonably large) operation (e.g. reading a file).
		• cause a significant change in program operation, but do not directly cause the program to terminate.
	Fatal	For errors directly (i.e. definately and almost immediately) ending the program.

For all levels bar trace, messages should if possible be understandable to end users, while (for warn and above) including enough information to fix the problem, including code symbols if necessary.
Thus:
	Trace output should only be available when compiled in debug mode.
	When run by an end-user (with info-level logging enabled),
	• info messages normally occur and should be understandable to end users;
	• warn messages may occur, and may or may not indicate problems;
	• error messages indicate that something big is wrong, and if the program still runs it is unlikely to be usable as intended;
	• fatal messages indicate a problem preventing the program from running.


Thrown errors should use an exception class specific to at least the package involved to enable specific catching of errors. Exception classes should be defined within a module exception.d in the package directory. Exception classes should generally follow the conventions within mde/exception.d to aid in providing reasonable error messages.



Unittests (last block in the module where multiple unittest blocks are used) should end with:
    logger.info ("Unittest complete.");
No more logging should be needed, since if it fails whoever runs the unittest will know about it, and logging messages cannot be used to tell how complete the unittesting is. These messages just confirm that the unittests ran really.

Unittests may be defined in their own modules or other modules. Unittests should be wrapped in
    debug(mdeUnitTest)
statements (these may also be used to wrap imports only needed by the unittest). Any modules containing unittests should be imported by test.mdeTest.