Skip to content
This repository has been archived by the owner on Oct 22, 2021. It is now read-only.

Code style

Jonas Wanke edited this page Apr 8, 2021 · 7 revisions

Basically, code as described in the Effective Dart Style guide.

Note: We have pretty strict linter rules that are also shown in VS Code and validated when opening a PR. They help you write readable and uniform code :)

Here are some amendments specific to this project:

Imports

There are basically 3 types of imports that should be organized into four distinct groups, separated by a newline:

  • Dart-Imports like import 'dart:ui';.
  • Package imports like import 'package:flutter/flutter.dart'; or imports of other modules like import 'package:schulcloud/app/app.dart';.
  • Imports of files in the same module. To make the code more succinct, these should be relative imports like import '../bloc.dart';
Example
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:schulcloud/app/app.dart';

import '../model.dart';
import 'article_image.dart';
import 'article_screen.dart';
import 'section.dart';
import 'theme.dart';

Visibility

Only make stuff non-private if it's accessed outside of the file.

Example
class _SampleWidgetState extends State<SampleWidget> {
  void _counter = 0;

  Widget build(BuildContext context) {...}

  void _countUp() => setState(() => _counter++);
}

Unused parameters

If arguments to a function are not used by that function, they can be named _ (an underscore), __ (two underscores) etc., to indicate to the reader that their value is not relevant.

Example
StreamBuilder<Update>(
  stream: /* ... */,
  builder: (_, snapshot) => MyWidget(snapshot),
)

Widgets

The widget tree in the build function should not contain any closures that are longer than one line (or are similarly simple). Rather, move these functions out into a new method that has a descriptive name. That helps readers of the build method to quickly understanding the action without interrupting their flow (they're probably trying to figure out how the widget tree is built, not what happens if an action is taken).

If the widget tree gets very deep, consider two options:

  • If there are parts of the widget tree that don't need to rebuild if the whole widget rebuilds, consider refactoring them to standalone widgets.
  • Otherwise, consider defining helper methods (descriptively named _buildButton) for parts of the tree.

The order of functions

This should be the order of functions in a widget (note some of them are optional):

  • initState
  • didChangeDependencies
  • dispose
  • build
  • helper functions used in build
  • helper build-functions (_build...)
Example
// (inside a [StatelessWidget] or the [State] of a [StatefulWidget])

Widget build(BuildContext context) {...}
void startSleeping() { /* ... */ }
void eat(Banana banana) { /* ... */ }

Widget _buildHeader(BuildContext context, int someData) { /* ... */ }
void _onHeaderClicked() { /* ... */ }