Here is a collection of 6 small things that many developers forget or are unaware of while developing their Flutter apps but can substantially improve the development process.
Widgets, widgets, widgets!
You may have probably heard that Flutter is all about widgets. Widgets here, widgets there, and so on. My first piece of advice is this:
Reduce your UI elements to as many small widgets as possible.
Let me elaborate. The two common scenarios we’d like to prevent are as follows:
- A huge widget class with one huge build method (aka the worst imaginable case)
- A huge widget class with lots of build methods (better than the previous option, but still not ideal)
The reasons why these cases cause problems during development are:
- Long classes mean a bigger cognitive overload while navigating through them which then means that developers get more tired more quickly and the possibility of introducing an error while trying to modify the code is greater.
- Generally creating more widgets goes in hand with the concept of increasing reusability of your code. That way you can easily change a common aspect of your app by simply modifying one widget instead of needing to change hundreds of methods each in separate classes.
If you’re a beginner programmer, be aware that generic widgets and abstract ones will be crucial when trying to break down your UI elements into reusable widget classes.
Another small optimization concerns if statements in your Flutter code. Did you know you can use them in your build methods by placing them directly in children lists like this?
It proves to be a clean code wise way to conditionally build up your UI logic. You can also combine it together with the spread operator to conditionally append lists of widgets to a specified list. Here’s an example:
Throw in some errors
Some programmers are afraid of girls and some are of throwing errors in their code. Let’s focus on the latter. While developing your app you will sometimes find pathways the code could execute that have no current implementation. In that case, you should throw an error like UnimplementedError in the case a feature is not yet implemented or an UnsupportedError if the given operation is invalid.
You should additionally provide an explanation for the given error in the constructor. Here’s an example of throwing an error in a switch statement used to map a string to an enum:
You should use const constructors wherever possible. Why? Well.. to put it simply, it helps increase Flutter performance by telling which elements won’t change, which means Flutter doesn’t need to rebuild them.
Here’s an easy example to illustrate the procedure. Let’s say we want to build an icon that won’t change and has a top margin of 20 that is also static. We would define the method to build the widget like this:
You don’t feel like wanting to keep track of when to add the const keyword? You’re lucky because you don’t have to! Just look at the next tip below.
Another useful tool is using a lint package for your project. If you’re not familiar with lint, it’s just an automatic tool that analyzes source code to flag common programming errors, bugs, or stylistic mistakes. To include it in our flutter project we start by adding two packages to our pubspec.yaml file:
Then we create a file called analysis_options.yaml in our root directory. There we include our community package and customize any other rules.
We can exclude certain directories from being analyzed like for example our generated localization files directories. Here we can also state that we want our missing required parameters to be reported as error preventing us from running the code.
@required & assert
Let’s start off with an example of a constructor for a Product class which will illustrate what you should avoid while defining constructors and methods:
First of all, if you have multiple parameters in your methods or constructors and some of them can be optional you should mostly use named parameters instead of positional ones. That way the code is more readable and it’s easier to spot an error while doing a code review.
Additionally, you should always correctly annotate your parameters using the @required keyword if they can’t be omitted. So.. let’s do this. Here’s the effect:
If you use these lint rules I’ve shared with you, the compiler will notify you with an error if you ever forget about specifying a required parameter, which is very helpful.
An assertion is another element we can use to improve this code. By specifying that our required parameters can’t have the value of null, we’ll be faster notified of a potential bug in the app.
I hope you found at least one of the things we’ve shared as valuable. Some of the tips might seem to be petty, but in reality, a developer’s skill set is a combination of different small details that come together to form his overall competence level.
Deviniti is your guide to the universe of digital transformation and enterprise software. Check out who we are and what we can do on our website.
If you want to learn more Flutter tips and tricks, make sure to check out other articles available on Deviniti Technology-Driven Blog: