years ago in the realm of software engineering, an architectural design pattern named Micro-Frontend architecture emerged. This term is rumored to have been mentioned for the first time in 2016 by ThoughtWorks Technology Radar. This architectural design pattern is very interesting. A lighter version of it is what I call Modular Components. Today, let’s see how to implement Modular Components with Flutter_bloc.
What is the Modular Component architecture?
Have you ever built a complex app (mobile or web), that talks to one or more remote APIs, and contains a good chunk of your business logic? If you have, then I’m sure there are sections of the app that contain too much business logic. For example, the code behind certain pages (The page’s bloc, the page’s ViewModel) displayed to the user might contain hundreds or thousands of lines of code, and business logic that can become confusing and difficult to maintain in the long run, especially when working in a team. The modular frontend architecture is just a simple architectural design pattern that solves these problems.
The modular component is a modular architecture that breaks down your app into smaller more manageable pieces, and each piece is responsible for its business logic, and API calls. As simple as that. If you’re using flutter and flutter_bloc, this architecture will be handy when you’re building complex pages with blocs full of business logic that can be split down into smaller modules. Here’s a diagrammatic representation of it.
If you find this article useful, please follow me on Twitter, Github, Linkedin, or like my Facebook page to stay updated.Follow me on social media and stay updated
Implementing Modular components with Flutter_bloc
My favorite way of building apps with Flutter is by using the Bloc pattern as state management. For DI, I use get_it, and I use the clean architecture to separate my code into layers, then split the front end into modular components only when necessary! I think using the right tool only when necessary is the best approach. The most popular package used to implement bloc is flutter_bloc of course, and we’re going to use it.
NOTE: If you want to see what an app built with the “Clean architecture” looks like, I strongly recommend browsing and reading this source code. It depicts how to separate your app into layers, using the concept of Clean architecture.
Identifying Which components should be a Modular Component
As a use case, I’ll take a real-world app I’ve built for a company called YouScribe (The Netflix for books). I lead a team of 3 engineers in re-building the YouScribe app, in no time. First, there are portions of your app that are shared. These include navigation bars, menus, etc. The first step we took was to plan how we’d build the app one page at a time. We first listed each component of the app, page after page. We identified the UI components that were unique and those that were re-used in different areas of the app. We then identified the components that carried a lot of business logic, and API calls, and labeled them as modules. The other simple components were just made to be reusable widgets in Flutter. Some other components were turned into modules during the development process, based on the amount of business logic that was accumulated in each bloc.
To illustrate this in a very simple example, below is one component we made as a modular component, because of the amount of functionalities it contained. You can see that each item (Book in a page) has each of these features:
- Download (It should be able to launch the download of a book)
- Read, when the image is clicked, the user should be able to read the book
- Delete
- Add and remove from your favorites
- Show details (When the item is clicked, the detail page should be shown)
The page’s bloc could handle all of these functionalities, but it’s not ideal! Packing too much responsibility in one bloc is not the best approach. You should always favor the separation of concerns. For each items in the page’s bloc, we created a cubit, responsible for managing its business logic, and making API calls. This implies that, each book in the list above, can download its self, delete its self, call the appropriate API, handle its state changes etc. The page containing it handles its own business logic and serves only as a container to the books in it. How do you do that ? Very simple.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | child: _buildRefreshView( ListView.builder( controller: widget.scrollController, itemCount: totalItems, itemBuilder: (context, index) { if (index == widget.products.length) { return const Center( child: SizedBox( height: 50, child: Center(child: CircularProgressIndicator())), ); } //Create each cubit, and assign it to its widget final productListItemCubit = ProductListItemCubit(widget.products[index]); return BlocProvider.value( value: productListItemCubit, child: ProductListItemModule( isInOfflineList: widget.isInOfflineList, isInFavoriteList: widget.isInFavoriteList, cubit: productListItemCubit, ), ); }, ), |
Conclusion
When coding, always remember these: YAGNI, SOLID, DRY!!! these principles should guide you in the realm of software engineering. If you remember these simple concepts, you’ll easily grasp the rest. Modularizing your app, forces you to respect these principles. I hope this article is useful. If it is, please, don’t forget to share and follow me on social media for more.
Follow me on social media and stay updated