» » Keeping code clean in a Flutter app

Keeping code clean in a Flutter app

Each of you is probably familiar with the situation when, after six months of working on a project with a team of several people, you suddenly find that different coding rules are used in different parts of the project, tests are written, but reports on them are not collected or analyzed, business is found in widgets -logic and computationally complex tasks are called directly in the build method. In addition, giant classes and methods have appeared, there is an excessive use of the dynamic type in the code, or there is no return type in functions. And you have a desire to unscrew the flywheel of time at the beginning of the project and do everything necessary so that the likelihood of such chaos is minimal. In this article, we will look at some convenient mechanisms for analyzing code and test results for Flutter.


One of the important advantages of Dart tool support is the presence of built-in utilities (previously they were presented as independent applications, now all features are added as commands of the main dart tool), which allow not only to perform basic tasks (compiling, running tests), but also help in migration between versions (for example, dart migrate offers and implements automatic modification of the project to use the syntax with sound null safety), fix potential problems and eliminate the use of deprecated syntax or class (dart fix). But of greatest interest for automation are two possibilities:

  • dart format (formerly dartfmt) - performs formatting of source texts in accordance with generally accepted rules;

  • dart analyze - checks the code for compliance with rule sets (defined in analysis_options.yaml).

It is important to note that the analysis tool is implemented from the Dart point of view as a package (analyzer, current version 4.0.0 released on 04/14/2022) that interacts with an autonomous long-lived process (analysis_server) that implements support for the LSP (Language Server Protocol), which in particular used in Visual Studio Code to implement auto-completion and display the results of source code analysis. Processes interact through a special Analysis Server API protocol , which provides not only mechanisms for checking source texts for compliance with rules, but also methods for auto-completion in accordance with the generated context. Currently, the creation of specialized server extensions is not yet provided, but work in this direction is underway and you can look at the architectureanalysis server plugin )

The rules include requirements for avoiding bad practices (avoid*), recommendations for the mandatory use of syntax elements (for example, a mandatory comma at the end of the require_trailing_commas parameter list or a group of prefer* or always* rules), for the design of imports (for example, implementation_imports to exclude imports src files from packages), potentially incorrect use of asynchronous functions ( avoid_slow_async_io to avoid calling slow operations from dart:io, use_build_context_synchronously to detect a call to asynchronous functions in build, such as a gesture reaction), avoid resource leaks ( cancel_subscriptionsto detect if a Stream subscription has not been removed). In addition, there may be cases of bad use of widgets ( sized_box_for_whitespace when using Container instead of SizedBox to create empty spaces).

There are several pre-configured rule sets, such as Flutter , and the rules can be included in analysis_options.yaml using the include directive:

include: package:flutter_lints/flutter.yaml

for connecting general rules for Flutter applications or Effective Dart rules for checking against official recommendations , as well as the lints package , which describes both a more free and strict version of code checking.

Some developers publish their rule sets, so you can connect the rules from Very Good Ventures:

include: package:very_good_analysis/analysis_options.yaml

In addition to the built-in code analysis tool, there are many community developments available on pub.dev:

  • dart_code_metrics - analyzer extension, adds some rules and capabilities for calculating numerical code metrics (average number of code lines in a method and class, number of methods in a class, cyclomatic complexity, etc.), makes it possible to detect very long methods or methods with a large number of parameters and look for unused dart files and localization. The rules are written to the object dart_code_metricsin analysis_options.yaml, the command is used to run them dart run dart_code_metrics:metrics analyze lib;

  • lakos - a dependency graph visualization and circular dependency detection tool;

  • null_safety_percentage allows you to numerically evaluate the use of Sound Null Safety by source texts;

  • code_quality_report creates a json file based on the results of the analysis, which can be used in conjunction with the Code Quality feature in Gitlab (also present in the free version);

  • coverage uses data published through the Dart VM debugging API to generate reports on source code coverage with tests;

  • test_cov_console generates a report on test coverage in the console (for example, it can be used in the CI / CD pipeline for output to a report);

  • better_test_reporter or testreport generate reports for JUnit on test results (dart test).

    Any of these tools can be run inside a CI/CD build script by first installing the console application's executable image via pub global activate.

    With each new version of Dart/Flutter, the analyzer's capabilities become more and more significant and already now include a number of checks for the appropriate use of widgets and the use of their context. And with the potential to create plug-ins for the analysis server, it will be possible to create more intelligent tools that will allow you to detect violations at other levels of abstraction (for example, errors and bad practices when using MobX or Redux state management frameworks).

Related Articles

Add Your Comment

reload, if the code cannot be seen

All comments will be moderated before being published.