-
Notifications
You must be signed in to change notification settings - Fork 20
Coding Guidelines
We use the following sources as coding guidelines.
- For Swift code we use the official Swift guidelines https://swift.org/documentation/api-design-guidelines/
- For Java code we use the Google Java guidelines https://google.github.io/styleguide/javaguide.html
- For Dart code we use the official Dart guidelines https://www.dartlang.org/guides/language/effective-dart/documentation
Additionally we apply the following rules.
Dart is the main programming language of this project, while Flutter is the UI framework to create all interfaces. The following general rules apply:
- No methods which return widgets should get created, create wrapper widgets instead. (Why? Please see: https://iirokrankka.com/2018/12/11/splitting-widgets-to-methods-performance-antipattern/)
- Every parameter given to a widget or within a event / state context should be named. Exceptions are only allowed with valid reasons or if the event / state / widget only has one parameter
- We always use the singular form for naming (use the suffix List or similar for a collection of items)
- This applies to classes, methods, variables and so on
- Example:
class ChatItem {}
,var chatItem
,var chatItemList
,ChatItem getChatItem()
,List<ChatItem> getChatItemList()
- Stateless and stateful widgets should get no prefix or suffix (e.g. ChatList)
- State objects should get the suffix State (e.g. ChatListState)
- Event objects should get the suffix Event (e.g. ChatListEvent)
- If components belong together the name should state that by prefixing the components with the context
- A name should be structured starting with the context, continuing with actual name and if necessary suffixed with a programming language specific word (e.g. ContactManagerMixin, context = Contact, name = Manager, programming language specific word = Mixin)
- As Flutter uses the words
build
andcreate
pretty extensively for UI handling, we should avoid those when creating methods which manage logic or states- Create / setup methods should start with setup
- Tear down / destroy methods should start with tearDown
- As Flutter uses the words
build
anddispose
for UI tasks, we should also do so when providing widgets- Create / setup methods should start with build
- Tear down / destroy methods should start with dispose
Widgets are the core component of the app, as Flutter defines every component as a Widget.
- Every widget must call super with at least the key parameter
- Widgets should be as reusable as possible
- Widgets should handle platform differences via the AdaptiveWidget approach (see the adaptiveWidgets package)
- Widgets shouldn't hold data, use the BloC approach instead (see https://bloclibrary.dev/#/gettingstarted)
Keys are required by the Flutter framework to identify if a Widget can be reused.
- Keys must reflect the build / rebuild state of a Widget
Additionally keys are used to perform tests (see https://flutter.dev/docs/cookbook/testing). To be able to test the app via integration or widget tests we needs keys for all important widgets, so the tests are able to identify the widgets.
- Every widget which allows user interaction (buttons, text fields and so on) should have a key
- Keys are defined as constants in utils/keyMapping.dart
- Use in production code Key(keyProviderSignInEmailTextField)
- Use in test code find.byValueKey(keyProviderSignInEmailTextField)
- Naming (e.g. keyProviderSignInEmailTextField)
- Starts with "key" as prefix
- Followed by the global context, so the file or class, e.g. "ProviderSignIn"
- Followed by the context within the file or class, e.g. "Email"
- Followed by the type of the widget, e.g. TextField (shortening is allowed, as long as the context is still understandable, e.g. TextField is allowed if a ValidatableTextFormField is used)
- Don't use strings directly within source files (e.g. ButtonText("Login"))
- The l10n package should get used (based on gettext, but adapted to avoid coding errors)
- Add a string in the L.dart file. It serves as key / default string, but is usable via a constant expression during development phase
- As soon as a new translation round is started, the string gets translated and the new .po files will be integrated. Everything else will be handled automatically
- Don't use dimension values directly within source files (e.g. Padding(8.0))
- The dimensions.dart file located in the ui package should get used
- Every entry in this file should be a constant
- Duplicated values are fine if the context of the constant differs
- Entries are used by importing dimensions.dart and using the constants directly (e.g. listItemPadding)
- Don't use color values directly within source files (e.g. Colors.red)
- The color.dart file located in the ui package should get used
- Every entry in this file should be a constant
- Duplicated values are fine if the context of the constant differs
- Entries are used by importing colors.dart and using the constants directly (e.g. onBackground)
- Values in this file shouldn't get altered / added / removed without prior discussion with the design team
- Don't use text styles directly within source files if multiple values are applied (e.g. TextStyle(color: Colors.red, ..., ...)), for single values (e.g. only color:) direct usage is allowed
- If possible every text style should extend existing Flutter styles. Use Theme.of(context).textTheme
- The text_styles.dart file located in the ui package should get used to extend existing Flutter styles
- Every entry in this file should be a constant
- Duplicated values are fine if the context of the constant differs
- Entries are used by importing styles.dart and using the constants directly (e.g. primaryW500)
Beside the mentioned classes other utils exists. If generic functionality is needed please check first if a utility class / method / function already provides the required functionality. If this is not the case a new utility class should be created or an existing one should get extended to avoid duplicated code.
- Stateless, stateful and state classes of one context should be located in one file
- Classes should be library private (prefixed with an underscore) if possible
- Events and states for BloC classes should be located in one file
- All files referring to a context (e.g. contacts) should be located in one package