In this post, we will discuss a simple framework to improve your Flutter application’s code quality.
The process of improving your code is incremental, therefore you need an incremental system. It’s not always clear what your next step should be during this process. That is the exact reason why teams end up with code they’ve “refactored” but it still doesn’t feel like a well-architected piece of software.
Creating structure in your Flutter code takes only 4 steps
In this post you will learn the 4-step framework for creating more structured, scalable and testable code in Flutter, by answering the following 4 questions.
- Is my UI code separate from my state code?
- Is my state code separate from my business logic?
- Is my business logic code separate from my application code?
- Can I mock dependencies that my business logic has on the application logic?
To avoid over complicating the process, these yes or no questions will allow you to immediately identify where to focus your time. The rest of the post will guide you on how to introduce structure (architecture) into your codebase.
Applying the Framework
The process to use this framework is simple.
- Answer each of the questions, yes or no
- For the first no you get, head to the question below and follow the implementation guide
If you struggle to answer the question, read each definition below to help you answer the question accurately. Now, let’s get to it.
Is UI separate from state code?
To answer this question you first need to know the difference between UI and state code.
In short, code that renders something on screen is UI (widget code), code that decides what and how to render on screen, is state code.
Refactor to apply
If the answer to this question is no, then your main focus should be the introduction of state management.
Any form of it works. We use Stacked, which uses provider to implement the MVVM pattern. The goal here being to ensure that in your UI file there is no state, and in your state file there is no UI.
Your state should be able to grow independently from your UI updates. Full implementation guide here
Is state separate from business logic?
After moving all the code besides UI code out of your view file, you should now have a dedicated file that stores your state.
At this point, you need to be able to identify the difference between business logic and state code. The short definition I use for business logic is, code that binds together what the user wants to do with the code that eventually executes the actions (Application Logic). See below for a visual representation.
Refactor to apply
If you answer no to this question, then you have to prioritize the following:
- Group together all code that performs actions into functions
- Move these functions into new files or new classes
- Similar functions should go into the same class
With this change, you should now have more concise code in your state file. You should be depending on objects to perform specific functions for you.
Is business logic separate from application code?
Application code is the code that does the “final pieces of work”, making the http request, writing to a database, reading a file from disk.
When you read your business logic you should see no application logic. If you do, it means you have a separation of concerns problem.
Refactor to apply
What you should do at this point is create single responsibility services that contain all of your application logic. These are classes that are dedicated to doing a single thing.
If you need to apply this step, here’s a full written guide to help you.
Can I mock dependencies in my business logic?
This is the final question and the most impactful one. If your answer here is no you need to apply one of the most important software engineering principles, dependency inversion.
If you’re at this point of your code, you can read a full guide here, with the code to help you see what a dependency is.
I’ve used this singular framework successfully in Flutter for many years. A lot of what I teach on my Free YouTube Series for building production apps, is based on this framework as well.
Chat next week,
Dane