Miniature/Development/CodingStyle

Miniature - Play chess everywhere you go!
.: Home : Releases : Wish list : Development : Coding style :.

Contents

[edit] General

We mostly try to follow the offical Qt Coding Guidelines, but with some exceptions. follow mikhas' personal coding style for Qt:

  • We use whitespaces over tabs.
  • Max. length of a source code line is 120 characters.
  • We use (nested) namespaces.
  • Type names are in CamelCase
  • Method names are in mixedCase (= lowerCamelCase).
  • Opening braces for code blocks before newlines, *except* opening braces for classes and methods.
  • Variables use under_scores and are lower_cases, to make them stand out from other symbols.
    • Member variables are prefixed with "m_*" if there is no private data class (PIMPL). In the latter case, "d->" already serves as a prefix. In the same sense, member variables in *Private classes have no prefix at all.
  • Use initializer list and call construct each member explicitly.
  • No boolean method parameters, unless it's a boolean property. Use enums instead.
  • Use Q_SLOT, Q_SIGNAL as a method prefix.
  • Impl files have a .cc extensions, header files use .h
  • Use Qt containers over std containers.
  • No explicit delete statements. Use QScopedPointer or C++'s inbuilt resource cleanup of member variables.
  • Avoid QObject parent ownership - with C++ inbuilt mechanism, smart pointers and the concept of RAII, there is rarely need for it. It makes memory management more explicit and avoids another constant source of bugs.
    • Try to use copyable value types instead of full-blown QObjects.
  • Avoid singletons
    • Singletons often become hidden dependencies of a class, making the class less reusable, as it increases coupling.
    • Prefer dependency injection instead, this also increases testability.
  • Public methods should be virtual.
    • Makes classes easier to reuse, increases testability.
    • Does not apply for structs.

[edit] Naming conventions

  • Methods *do* something, that's why their names should always contain a verb (slots and signals count as methods, too).
   connect(this,  SIGNAL(someSignalChanged()),
           other, SLOT(onSomeSignalChanged()));
  • typedef'd types *might* hint at their composed types (to emphasize their intended use), but avoid directly including the type information in the name:
 typedef QSharedPointer<SomeClass> SomeSharedClass; // Good! Sharing a resource is a concept.
 typedef QSharedPointer<SomeClass> SomeClassPtr; // Bad! What is a "SomeClassPtr *some_variable" now?
 typedef QList<SomeClass> SomeClassList; // still OK, since "List" is a concept, too.
  • Avoid hungarian variable names.
  • If in doubt, name slot "onSomeSignalChanged". This makes for nice connection code:
 connect(some_signal_source, SIGNAL(theSignalWasEmitted()),
         some_receiver,      SLOT(onTheSignalWasEmitted()),
         Qt::UniqueConnection);
    • Use normalized signal/slot signatures (no const keyword, no &).

[edit] Advanced

  • Method parameters should be easy to read:
 class SomeClass
 {
     void someMethod(SomeType arg1,
                     SomeOtherType arg2,
                     ...);
    • Details:
      • Move each argument to a new line. This serves two goals: header files will be easier to scan (for humans), and you'll spot those ugly methods that scream "refactor me!" faster because they have more than 3 arguments. Also, because it *is* ugly, you might just go and refactor it, which will help everyone.
  • Use const refs for arguments when possible, even if the type is COW (copy-on-write, for example QString).
  • Don't return const refs for value types. Leave the decision to the caller.
  • Conditionals
 if ((something && somethingElse)
      || orPerhapsThis) {
     ...
 }
    • Details:
      • Conditionals often contain bugs. Especially when the surrounding code gets refactored, those bugs simply slip in.
      • If a conditional needs to be wrapped, it starts to look ugly. Good! It might lead you to refactor the code, moving the condition itself into a predicate function (which has the nice effect to serve as a comment, if it has a good name).
      • Nested conditionals quickly start to look ugly with all those line separators, but you probably guessed it already: It's just another sign that this code might need some cleanup! Nested conditionals should be used rarely or hidden within dedicated methods.
  • One space after keywords that could be mistaken as functions (if, for, ...).
  • If you store a pointer to an object over which you do not intend to take ownership, then wrap this pointer in a QWeakPointer:
 class SomeOtherClass
 {
     QWeakPointer<SomeType> m_member;
 };
    • Details:
      • QWeakPointers keep track of QObject deletion and set all referring QWeakPointers to zero, preventing dangling pointers. Especially when using signals & slots, this is an often (and sometimes hard to spot!) source of bugs. With QWeakPointers, you can wrap your code with conditional guards like so:
 if (SomeType *var = m_member.data()) {
     // Do sth with var
     // This block *never* gets executed even if m_member was deleted elsewhere.
 }
  • Assign 0 to pointers after deletion (or use QPointers).
  • Always initialize type primitives (e.g., pointers) in the constructor's initializer list.
  • Don't use forward declaration unless necessary. It is not your task to optimize the compiler. Also, Qt Creator gets confused by them.

[edit] How to keep code testable (and hopefully, mostly bugfree)

We want to have testable code, therefore we also want to follow some advanced coding standards.

For that, I will try to list some really really useful advice from this document: http://www.research.att.com/~bs/JSF-AV-rules.pdf, a coding style document for C++. Bjarne Stroustrup worked on that one, yes.

  • Keep methods at a reasonable length. In general: If it doesn't fit on a screen page it's probably too long. More precise: Every method longer than 200 lines of code (including comments, yes) is too long.
  • Within a method, avoid a cyclomatic complexity higher than 20 (see Appendix A regarding AV Rule 3, pp. 65, "Cyclomatic complexity measures the amount of decision logic in a single software module.", and the example).
  • Avoid cyclic dependencies between classes/modules (Rationale: it's mostly an indicator for layer violations).