[Short] Flutter : Let’s talk about lint rules
Recently I talked with a guy on LinkedIn, who’s name is Nicolas.
Nicolas has made some videos on youtube where he talks about dev.
Like this one (in French).
This video talks (among other things) about prettier.
Prettier · Opinionated Code Formatter
Opinionated Code Formatter
Opinionated Code Formatterprettier.io
If you are familiar with the web dev, you know prettier, if not, it is a tool that helps formatting your code well using some rules.
And there is a sentence in that video I liked a lot, I’m gonna rephrase it
In a project (in your IDE), you are like home, it is running like you want, everything is at the place it should be… for you.
How about when others join ? They eat in your bathroom, leave some toilet paper in the fridge when they are drunk and all sort of crazy stuff (yeah maybe my friends are weird).
My point is, when you are alone, in your home. It is your rules. But when you are a team (more than 1), then it is not your home, it is a flat-share.
And a flat-share needs common rules, like this one.
Dart Lint
Flutter is a framework, the language is Dart. You know that (because this article would be less interesting if you don’t).
First of all note that dart has an official recommended rules list
That being said, Flutter does not use it and has its own https://github.com/flutter/flutter/blob/master/analysis_options.yaml
When you create a Dart (Flutter) project, you can see a file called analysis_options.yaml
This file contains the rules of the flat-share. But by default, this file does not contains much.
include: package:flutter_lints/flutter.yaml
But the included file contains more
# Recommended lints for Flutter apps, packages, and plugins.
include: package:lints/recommended.yaml
linter:
rules:
- avoid_print
- avoid_unnecessary_containers
- avoid_web_libraries_in_flutter
- no_logic_in_create_state
- prefer_const_constructors
- prefer_const_constructors_in_immutables
- prefer_const_declarations
- prefer_const_literals_to_create_immutables
- sized_box_for_whitespace
- sort_child_properties_last
- use_build_context_synchronously
- use_full_hex_values_for_flutter_colors
- use_key_in_widget_constructors
And so on with the included included package that I will not paste here
Those rules are fine, but they are rules that have been decided above you. Its is more like guidelines
What should you use ?
Flame, a popular game engine has its own file https://github.com/flame-engine/flame/blob/main/packages/flame_lint/lib/analysis_options.yaml
Why not you ?
In the real world, when you share the rent, you share the rules.
It means in my opinion, every single team that works on a flutter or a dart project should take time to go through the list of rules available and pick if they want it or not.
Build your own analysis_options.yaml !
How to do so, the full list of available lints is here https://dart.dev/tools/linter-rules/all
Most of them are detailed here https://dart.dev/tools/linter-rules
Some of them has a `has fix` label, this is great because the linter will have an option to fix the issue for you.
You even can create a custom one if you want using the invertase package custom_lint.
What do I use ?
At La Mobilery, with the Flutter team, we took half a day to check the rules. Here what came out of it.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
analyzer:
exclude:
— “build/**”
— “**/*.g.dart”
— “**/*.gen.dart”
— “**/*.freezed.dart”
linter:
rules:
avoid_redundant_argument_values: true
avoid_init_to_null: true
avoid_print: true
control_flow_in_finally: true
constant_identifier_names: true
curly_braces_in_flow_control_structures: true
exhaustive_cases: true
file_names: true
library_prefixes: true
non_constant_identifier_names: true
null_check_on_nullable_type_parameter: true
prefer_const_constructors: true
prefer_contains: true
prefer_final_fields: true
prefer_is_empty: true
prefer_null_aware_operators: true
sized_box_for_whitespace: true
slash_for_doc_comments: true
unnecessary_brace_in_string_interps: true
unnecessary_constructor_name: true
unnecessary_late: true
unnecessary_parenthesis: true
unnecessary_string_escapes: true
unnecessary_string_interpolations: true
always_use_package_imports: true
depend_on_referenced_packages: true
prefer_single_quotes: true
require_trailing_commas: true
always_put_required_named_parameters_first: false
sort_pub_dependencies: false
prefer_if_elements_to_conditional_expressions: false
strong-mode:
implicit-casts: false
implicit-dynamic: false
- avoid_redundant_argument_values : if you call a method with a parameter default value it fails
- avoid_init_to_null : by default, variables are null, so doing = null is useless.
- avoid_print : print is bad in flutter, don’t do it, use a logger.
- control_flow_in_finally : if you do business logic in finally (try/catch), then it fails.
- constant_identifier_names : this is not java, constants are lowerCamelCase.
- curly_braces_in_flow_control_structures : bye bye
if(a) abc;
use{}
event for one line. - exhaustive_cases: if you switch on an enum, handle all the cases.
- file_names : file names should be lowercase_with_underscore.
- library_prefixes : when you want to prefix an import, use lowercase_with_underscores
- non_constant_identifier_names: if the object is not const, use lowerCamelCase
- null_check_on_nullable_type_parameter
- prefer_const_constructors : if you can use
const
, useconst
- prefer_contains : pref
.contains()
to.indexOf()
- prefer_final_fields : if something is never re assigned, use
final
- prefer_is_empty: pref
.isEmpty
to.length == 0
- prefer_null_aware_operators
- sized_box_for_whitespace: if you want a blank widget, use
Size
- slash_for_doc_comments : pref
///
to/*
- unnecessary_brace_in_string_interps :
'${name}'
should be'$name'
- unnecessary_constructor_name: don’t use
new
- unnecessary_late : if a var is assigned, then it is not a
late
var - unnecessary_parenthesis : don’t do more code than you should
- unnecessary_string_escapes:
"\'"
should be"'"
- unnecessary_string_interpolations:
String a = String
, no'${String}
- always_use_package_imports: Don’t import using
'../../..
- depend_on_referenced_packages: check the package you use is imported (collections I see you)
- prefer_single_quotes:
'
is better than"
- require_trailing_commas: Add
,
every where it can be added (helps a lot for reading code)
And don’t forget those we DO NOT want
- always_put_required_named_parameters_first : becase some time we want a specific ordre for clarity.
- sort_pub_dependencies : same reason, for example, firebase packages
- prefer_if_elements_to_conditional_expressions : let me do
? :
please
Strong mode is well explained here
Bonus
If you are using VSCode, please note that you can run the fixes at save :)
It will fix all the fixable detected lints for you ! Time saving like hell.
To do so, edit the User settings.json and add this
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit",
"source.fixAll": "explicit",
"quickfix.create.constructorForFinalFields": "explicit"
},
"[dart]": {
"editor.formatOnSave": true,
"editor.formatOnType": true,
}
So, I hope you will enjoy taking time with the folks you code with. No more time doing bullshit review in pull request that said, you forgot the ,
here ! What a time to be alive.
If you enjoyed this, please share it, and share your rules in comments, it is always a pleasure to discuss them.
You can also follow me on LinkedIn for more articles like this one