Ensure High Code Quality in Flutter

Being one-man-army working on an app has some advantages. There is no deliberation about code formatting, libraries or frameworks used in the project. This is why migrating from react-native to Flutter was an easy decision, I just didn’t need to convince anyone apart from myself ;).

Of course all of those pros are also the cons. There is one that could prevent me from making bad decisions, checking in a bad code or braking old features while implementing new one. There is no one to deliberate about algorithmic, implementation and architectural choices in code review… you get the point?

There are some ways how some of those down sides may be overcome. For example writing unit and functional/integration tests is one of them. Code formatter and analyzer are another two.

Thankfully Flutter comes with all of the bells and whistles. There is flutter format, to automatically format your code, and flutter analyze to analyze code and enforce quality. Even more, both tools comes with awesome pre-build configurations that are used by Flutter team.

Unfortunately there is nothing that would automatically write test for you ;). But fortunately there are high quality and performant test frameworks that lets test your code on:

  • unit,
  • widget (functionality),
  • widget (presentation),
  • integration

levels.

One thing is to have the tools, but another is to use them… When you are part of a bigger team, someone will configure a build and CI/CD system for you, that probably will be running in the cloud. Or you can use something like CodeMagic… But in my situation I try to limit external services that I use with HabitChallenge.

One thing that I loved in my react-native times, was husky project. That lets you easily define and manage git hooks, especially pre-commit hook. This way I was able to run google typescript and unit tests before each commit.

Back in August 2019, there was nothing that may be compared to husky in dart/flutter ecosystem. So I decided to go with a general solution, the pre-commit project. Lets see how we can leverage pre-commit to ensure our code is properly formatted, doesn’t break any analyzer rules and do not break existing unit tests.

First of all we need to install pre-commit in our system, this is as simple as:
$ curl https://pre-commit.com/install-local.py | python –
or
$ brew install pre-commit

Secondly, we need to create a file called .pre-commit-config.yaml in our repository root with following content:

repos:
- repo: https://github.com/Cretezy/flutter-format-pre-commit
rev: 4a1df675bb74dea371c17934933e257e46f8dd98
hooks:
- id: flutter-format
- repo: https://github.com/dluksza/flutter-analyze-pre-commit
rev: 0bfdb7415bb2d02794a884bf2b763a92772001eb
hooks:
- id: flutter-analyze
- repo: https://github.com/dluksza/flutter-test-pre-commit
rev: ed4387d1e32d655e8f5cf58b410c9b4768f2950f
hooks:
- id: flutter-test

Finally run pre-commit install in the repository root and we are done!

OK, but what it is actually doing? Whenever you modify any dart file and decide to commit your changes to git repository, pre-commit will automatically run flutter format, flutter analyze and flutter test for you. If any of those command fails you will not be able to commit your changes. First you need to fix what have you broke then call git commit again. The good part is that when you modify any other file none of those commands are run!

This approach has two downsides. First of all, flutter format will automatically fix any formatting issues for you… but because of limitation in pre-commit you can’t modify files during pre-commit hook. This means that after files are properly formatted you need to run git commit again. Secondly, depending on your hardware, amount of code and number of unit tests it can take considerable amount of time to execute all those checks. You have been warned!

Hope you learned something 😉