Skip to main content

Improving Code Reviews - Tools and Practices for Dart and Flutter Projects

· 10 min read
Majid Hajian
Google Developer Expert

Cover

Code reviews are integral to the software development lifecycle, crucial in maintaining code quality and promoting team collaboration. In this blog, I want to explore the importance of code reviews, tools, and practices to enhance the code review process and emphasize best practices specific to Dart and Flutter development. We will also discuss advanced concepts like "Shifting Left" to integrate reviews earlier in the development cycle, minimizing issues before they propagate.

Shifting Left: Integrating Reviews Earlier

Let’s start with the “Shifting Left” concept in software building.

The software development lifecycle (SDLC) typically consists of several phases, each with specific tasks and deliverables.

SDLCSDLC

"Shifting Left" refers to identifying and addressing issues earlier in development. The earlier you catch the bug and have a consistent code base, the lower the cost. Therefore, by integrating code reviews at earlier stages, teams can catch potential problems before they become more complex and expensive.

Shifting LeftShifting Left

The Importance of Code Reviews

Several factors play essential roles in the “shifting left” concept, such as code review, static analysis, and automated tests and analysis, especially on CI platforms.

Though code review is the most important one, others will help code review significantly. For example, having a proper static analyzer setup and running on CI can significantly improve code review and even make it faster to get it done. Let’s me summarize the three main reasons behind it:

Ensuring Code Quality and Reducing Bugs

By catching issues early, code reviews help maintain high standards and reduce the number of bugs that reach production. This proactive approach saves time and resources in the long run.

Facilitating Team Learning and Cohesion

Code reviews promote knowledge sharing among team members, helping them learn from each other and understand different parts of the codebase. This practice enables a collaborative environment and enhances team cohesion.

Maintaining Coding Standards

Consistent coding standards are crucial for maintaining a codebase. Code reviews ensure all team members adhere to these standards, creating a uniform and clean codebase.

Tools and Practices to Enhance Code Reviews

Enhancing the code review process involves leveraging various tools and practices. In my opinion, there are several tools and practices:

  • Automated Testing
  • Linting Tools
  • Pre-Commit Hooks
  • Continuous Integration (CI)

Automated Testing

Automated testing is a critical component that enables teams to validate their code and continuously catch defects early in development, which promotes the “Shifting Left” concept.

You may be familiar with multiple tests, such as unit tests, Widgets, and integration tests in Flutter. Running these tests, especially before sending an implementation to review, can help identify potential bugs and give the code reviewer more confidence.

Linting Tools

These tools are necessary for ensuring code quality before and during code reviews, especially for Dart and Flutter projects. There are four reasons essentially why I think having linting tools is pretty important in any project:

  1. Error Detection: Linting tools automatically detect a wide range of potential errors in the code, from syntax errors to more complex issues like potential bugs and code smells. This proactive detection helps developers fix issues before they become bigger problems.
  2. Enforcing Coding Standards: Consistent coding standards are vital for maintaining a clean and readable codebase. Linting tools enforce these standards by checking the code against predefined rules and guidelines, ensuring all team members adhere to the same practices.
  3. Improving Readability and Maintainability: Linting tools help improve the readability and maintainability of code by enforcing coding standards and highlighting potential issues. Clean, consistent code is easier to understand, review, and extend.
  4. Supporting Code Reviews: Linting tools assist in the code review process by automatically flagging issues, allowing reviewers to focus on more complex and subjective aspects of the code. This automation reduces the cognitive load on reviewers and speeds up the review process.

Let’s see in action.

The "Dart Analyzer" tool is part of the Dart SDK and is used to analyze Dart code. The good thing is that it is integrated with Dart SDK, which is widely used and supports a variety of rules and configurations.

By all means, this needs to be enabled and set up properly for any Flutter and Dart project. Leveraging the rules and configuration in your benefits and enhancing project standards, especially improving code review, is important, so pay attention closely to the analysis_options.yaml configuration file.

# Example 
analyzer:
strong-mode:
implicit-casts: false
implicit-dynamic: false
errors:
unused_local_variable: warning
dead_code: error

linter:
rules:
- avoid_print
- prefer_const_constructors
- annotate_overrides
- avoid_init_to_null

These rules are a great help in code review and enforcing code quality and consistency in your project. For example, avoid_print can simply throw a lint error in your editor, and even if not in the editor, in your CI or pre-commit hooks.

However, based on my experiences on larger and more complex projects, especially with several developers involved, it may not cover a project's specific needs.

That’s where professional tools such as DCM come in place.

DCM.dev stands out in the ecosystem of linting tools for Dart and Flutter due to its comprehensive features and advanced capabilities, with over 300+ rules that will cover a wider range of performance and styling issues.

DCM offers flexible configuration options, allowing teams to customize the linting rules to fit their needs. This flexibility ensures the tool can adapt to different project requirements and coding styles and, more importantly, comprehensive reporting with different output supports. I will show you an example later in this blog on leveraging this reporting in your CI or git-hooks setup.

Pre-Commit Hooks

Hooks are a great source to enhance code review. Pre-commit hooks are scripts that run automatically before a commit is made in a version control system like Git. These hooks ensure that code meets certain standards and passes predefined checks before it is committed to the repository.

Pre-CommitPre-Commit

Pre-commit hooks are great for running early checks before you even send a PR. Let’s see one example of how you can leverage the pre-commit hook with JSON output from the DCM analyze command.

Here's a Dart-based pre-commit hook implementation along with a simple code review flag system, designed to be placed in a hooks/pre-commit.dart file:

import 'dart:io';
import 'dart:convert';

void main() async {
final processResult = await Process.run(
'dcm',
['run', '--analyze', '--json-path=./dcm-report.json', 'lib'],
);

final reportJson = File('./dcm-report.json').readAsStringSync();
final report = json.decode(reportJson);

// Navigate to analyzeResults array within the report
final List<dynamic> analyzeResults = report['analyzeResults'];

final reviewFlags = <String>[];

for (final result in analyzeResults) {
final path = result['path'];
final issues = (result['issues'] as List).cast<Map<String, dynamic>>();
final issueCount = issues.length;

if (issueCount > 0) {
reviewFlags.add("$path has $issueCount issue${issueCount > 1 ? 's' : ''}");
}
}

if (reviewFlags.isNotEmpty) {
stdout.write("\nCode review flags:\n");
reviewFlags.forEach(stdout.writeln);
stdout.write("\n");
}

// If everything is good, just exit
exit(0);
}

Let me explain how this works:

  1. Runs DCM Analysis: The script executes the dcm run command to analyze your lib directory and generate a JSON report with --json-path= or -a
  2. Error Handling: If the DCM analysis fails (exit code != 0), the script prints the error message to the console and fails the pre-commit hook.
  3. Report Parsing: It reads the JSON report and extracts the relevant information about the issues found.
  4. Code Review Flags: It constructs a list of messages (review flags) highlighting which files have issues and how many.
  5. Output: If there are code review flags, they are printed to the console to inform the developer. Otherwise, the script exits successfully.

Then you need to create .git/hooks/pre-commit in your project; the only thing this hook does is run the following script

#!/bin/sh
dart run hooks/pre-commit.dart

That’s pretty much it.

Pre-Commit ResultPre-Commit Result

This is very powerful because you can now aggregate multiple outputs from several other tools and the command line and then show a custom code review message before committing or sending a PR.

Another feature that enhances code review and can also be incorporated in recommit is the usage of DCM Metrics or integration with Code Quality Checks with CLI, including:

It depends on what you want to achieve in your project, but just imagine having all of these metrics and analyses under your control and aggregate data before running a PR and that can act as an initial code reviewer.

Continuous Integration (CI)

Linting tools or automated testing can be run in a pre-commit hook or even before sending a PR, which helps to apply the concept of shifting lift. But there is one more way that can help with code review and improve code quality and consistency: running automated tasks and tests on your CI platform.

There are many CI tools, and you can select any of them as long as they work for you. What is important is to set up the CI to properly help code review and encode your team's code standards. That’s where I think a great tool can come in handy; if you have tools that can help you integrate tightly with the CI platform, annotate errors, and highlight potential issues, that would be fantastic.

That’s where I must say that DCM has great reach and support. Thanks to CLI, it supports almost all major CI tools and helps you return different output formats.

dcm run --analyze --reporter=json lib 

The reporter supports console (default), JSON, code climate, GitLab, check style, and GitHub. The DCM documentation shows all of this integration in action.

Azure DevOps ResultAzure DevOps Result bitbucket Resultbitbucket Result github Resultgithub Result Gilab ResultGilab Result

As you can see, the CI analysis step can potentially act as an initial code reviewer.

Conclusion

In conclusion, code reviews are vital to maintaining high-quality software and encouraging team collaboration, especially in Dart and Flutter projects.

By integrating code reviews earlier in the development cycle through the "Shifting Left" approach, teams can identify and resolve issues more efficiently. Leveraging automated testing, linting tools, pre-commit hooks, and continuous integration can significantly enhance the code review process. By adopting these strategies and tools, development teams can achieve a more effective code review process, ultimately leading to better software outcomes.

For more detailed information on DCM.dev and its features, you can explore the official DCM documentation, and you can also try DCM for Free today.