Coding Conventions
Contents
- 1 General
- 2 Coding Conventions for Qt-based middleware and apps
- 2.1 Qt Coding Conventions
- 2.2 QML coding conventions
- 2.3 Additional Sailfish Qt coding conventions
- 2.4 Additional Sailfish QML coding conventions
- 2.4.1 Omit ";" behind JavaScript function lines
- 2.4.2 Put spaces between conditional statements, code, and curly braces
- 2.4.3 Write short one line functions in one line
- 2.4.4 Omit redundant property assignments
- 2.4.5 Don't define id for an element if id is not used
- 2.4.6 Use braces in one-line conditionals
- 2.4.7 Group properties together when grouped property form is available: font {}, anchors {}, border {}, etc.
- 2.4.8 Avoid unnecessary negatives
- 2.4.9 Keep similar properties close to each other
- 2.4.10 Mark private API private
- 2.5 Testing Conventions
General
As a rule of thumb follow the coding conventions of the open source project you want to contribute to. Most big projects like GStreamer, oFono and Telepathy have their own coding conventions that should be respected when contributing those frameworks.
Coding Conventions for Qt-based middleware and apps
When developing features for Sailfish applications, follow Qt C++ and QML coding conventions. Sailfish has traditionally been relatively flexible on coding style issues, leaving the decision on the enforcement of conventions to the individual teams and developers. Coding convention rules stir up a lot of opinions, but at the end are not so important as long as developers write clear, concise, readable, testable and in general high quality code they can be proud of.
Qt Coding Conventions
QML coding conventions
Additional Sailfish Qt coding conventions
Sources: Sailfish OS Middleware conventions
Prefer Qt5 Signal/Slot Connection Syntax
Write
QObject::connect(&sender, &Sender::signalName, &receiver, &Receiver::slotName);
instead of
QObject::connect(&sender, SIGNAL(signalName()), &receiver, SLOT(slotName()));
Rationale: ensures that the compiler can detect parameter mismatch issues, and provides a minor performance benefit at runtime.
Prefer C++11 Ranged-For
Write
for (const QString &str : someStringList) { ... }
or
for (const auto &str : someStringList) { ... }
instead of
for (int i = 0; i < someStringList.size(); ++i) { const QString &str(someStringList[i]); ... }
Rationale: in general we should prefer C++11 features where supported by the platform compiler.
Use CamelCase Namespace Names
As for class names, prefer camel-cased namespace names.
Write
namespace AppNamespace { /* ... */ }
instead of
namespace appnamespace { /* ... */ }
Rationale: provides consistency with class naming as specified by the Qt Coding Style.
Additional Sailfish QML coding conventions
Sources: Qt Quick examples, Qt Components conventions
Omit ";" behind JavaScript function lines
Write
x = a + b
instead of
x = a + b;
Rationale: less code, basically either style way would be fine, but one was chosen.
Put spaces between conditional statements, code, and curly braces
Write
if (a) {
instead of
if(a){
or
if ( a ) {
Rationale: criteria is mostly esthetic and thus subject to argumentation.
Write short one line functions in one line
It is ok to write
onClicked: if (a) doSomething()
instead of
onClicked: { if (a) { doSomething() } }
Rationale: less lines needed, both forms equally readable.
Omit redundant property assignments
Write
property bool propertyName property int propertyName
instead of
property bool propertyName: false property int propertyName: 0
Rationale: less code, QML developer should already know the default values.
Don't define id for an element if id is not used
Write
Image {}
instead of
Image { id: background }
if you don't need the id.
Rationale: potentially less code. Like with properties only define something if you really need that something.
Use braces in one-line conditionals
Write
if (a) { doSomething() }
instead of
if (a) doSomething()
Rationale: Agreed with the team. Goes against Qt Coding convention, but is generally considered safer.
Group properties together when grouped property form is available: font {}, anchors {}, border {}, etc.
Write
anchors { horizontalCenter: parent.horizontalCenter; horizontalCenterOffset: Theme.paddingSmall }
instead of
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenterOffset: Theme.paddingSmall
Rationale: less code, grouping communicates relation.
Avoid unnecessary negatives
It is more readable to state
if (a) .. else ..
than
if (not a) .. else ..
and
#ifdef USE_SQL .. #endif
instead of
#ifdef NO_SQL .. #endif
Rationale: negatives require more mental load to decrypt. Avoids double negatives like !NO_SOMETHING.
Keep similar properties close to each other
There is no one clear rule with this, grouping is often contextual: base element properties versus specialized properties, visual versus non-visual properties.
Rationale: proximity implies relation, code is easier to read the less you need to jump between lines when interested in particular behavior/feature.
Some rough general rules to consider :
id declaration property declarations signal declarations property bindings, functions and signal handlers - Same type items grouped together, javascript functions and signals handlers close to each other. - Attached properties after bindings. - The most important details that define the component first. For example if an interactive item sets some text label property, the bindings define the item more than a javascript expression blob. child items, visual and non-visual grouped together states transitions
Mark private API private
You can't stop developers from reading your code, and if they can't tell public symbols from private symbols their code will end up depending on something that changes in later versions. QML doesn't support for private members, however there are a couple of conventions useful for keeping symbols out of the way. The simplest and usually fastest is to prepend an underscore:
Item { property int iAmPublic property int _iAmPrivate Text { text: "Hello" } }
Testing Conventions
Sailfish app development follows Qt conventions, and autotesting is no different.
There are couple of common anti-patterns highlighted below that you should avoid.
Prefer compare() over verify() when possible
Write
compare(value, 10)
instead of
verify(value == 10)
Rationale: Compare produces more descriptive error messages and does more type checking.
Use SignalSpy instead of wait()
Write
SignalSpy { id: valueSpy; target: object; signalName: "onValueChanged" } function test_case() { signalSpy.clear() signalSpy.wait() compare(object.value, newValue) }
instead of
function test_case() { wait(100) compare(object.value, newValue) }
Rationale: Too short arbitrary wait times may fail, at worst cases irregularly. Too long wait times unnecessarily postpone the completion of the autotest.