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.
- Details:
- 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.
- Details:
- 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:
- Details:
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).
- This page was last modified on 3 September 2011, at 11:11.
- This page has been accessed 3,468 times.