Nobody cares about code quality... until they feel the consequences of this negligence. Keeping the quality of your code high is absolutely crucial, especially when you work on a team. Every app is built by writing individual statements first so before even discussing high-level design patterns, you should start with project cleanliness from the ground up - by configuring more advanced linting.
Insufficient defaults
Every Flutter project comes with a handful of linter rules already enabled. For example, when you have a FloatingActionButton
but you forget to specify the onPressed
callback function you get warned about it.
info_message.dart
FloatingActionButton(
child: Icon(Icons.announcement),
// onPressed is missing - we get a warning message
);
Sure, it's nice to get warned but wouldn't it be better to get a fully-blown error? As you know, omitting a positional argument results in an error popup which is very hard to ignore.
error_message.dart
Text(/*missing positional arg*/);
With omitted required named parameters though, we won't get any such helpful popups from the Dart compiler by default.
Changing severity
Fortunately, we're not limited to the default way of resolving individual linter rules! All we need to do is to edit a file called analysis_options.yaml. New Flutter projects currently don't come with this file pre-created, so let's add it to the root of the project. Inside, we'll tweak the severity of the error message to be a fully blown error.
analysis_options.yaml
analyzer:
errors:
missing_required_param: error
Now we finally get the same treatment for omitting required named arguments as we do for omitting positional arguments.
Enabling new rules
It's easy to change the severity of an already enabled lint rule. After all, we already got a squiggly line even while the rule called "missing_required_param" was just a warning message. How can we enable other rules though and where can we find which rules are available? The answer is the official linter package!
Let's for example tackle the reassignment of method parameters. In regular math, input of a function cannot be magically changed inside of it. All a function should do with the input is just to use it. And look, there's a handy lint rule that we can enable!
Enabling rules is as simple as adding them to the list inside analysis_options.yaml. Since the parameter_assignments rule will produce only info messages by default, let's also change its severity.
analysis_options.yaml
linter:
rules:
- parameter_assignments
analyzer:
errors:
missing_required_param: error
parameter_assignments: error
Finally, writing this horrible piece of code will produce a well-deserved error.
error_message.dart
void someMethod(int x) {
x = 5; // error ?
}
linter:
rules:
first_rule: false # disable
second_rule: true # enable
Lint packages
Although looking through the list of all possible linter rules can be enlightening, I think we all have other things to spend time on. Thankfully, we can utilize packages which come with some sensible defaults regarding lint rules and their severity.
There are currently 3 such packages worth mentioning.
- pedantic - used internally by Google which is both a blessing and a curse since they don't want to break their codebase by enabling certain rules which are otherwise worth enabling.
- effective_dart - a community package with rules stemming from official Dart guidelines
- lint - another community package which I personally like to use
Enabling rules from a package
Just like with any other package, even lint packages need to be added to pubspec.yaml. Because linting happens only during development, it's enough to add it to dev_dependencies.
pubspec.yaml
dev_dependencies:
lint: ^1.1.1
All of the lint packages come with a pre-configured analysis_options.yaml file. The only thing we need to do is to include it in our own file, usually in the first line.
analysis_options.yaml
include: package:lint/analysis_options.yaml
...
You can find out about the rules we just enabled by looking at the package's analysis_options.yaml. For example, we now get an info message when we use a const-capable constructor outside of a const
context. (Learn all you need to know about const
in a this tutorial.)
const_context.dart
Text('Info message here');
const Text('No issues here');
Additionally, we also get a handy quick-fix after pressing the CTRL + . in VS Code. Now you have no excuse not to use const
?
Fix Dart's unreasonable defaults
Modifying analysis_options.yaml yourself opens up possibilities to fix Dart's idiotic defaults. I mean, why does not returning a value from a method produce only an insignificant info message?! The lint package we're using bumps the severity from info to warning (more prominent message). Most of the real programming languages (sorry JavaScript ?) bombard you with an error if you forget about a return statement. Well, now you know how to bring this behavior into Dart!
analysis_options.yaml
analyzer:
errors:
missing_return: error
Be sure to tweak the rules and their severity to make your codebase as healthy as it possibly can be!
Perfect Matt