The internet is a big place, and getting bigger everyday. As such, if you know what you’re looking for, and if you look hard enough, 9 times out of 10 you’re going to find what you’re looking for, or at least a variation that works well enough with some modifications. Bridges built by others to traverse commonly faced problems.
Rarely though, will you turn up with not even enough to build off of, and rarer still you then proceed to build what you wanted in the first place: too much work, not enough results, and that’s without factoring in complexity. This would be the time to start considering alternatives, or workarounds. I’ve done the same more times than I can remember.
This time though, when I couldn’t turn up with anything when I searched for architectures regarding the excellent state management library MobX, and with a workaround or alternative not really being viable, I found myself with a rare choice, the choice to build a bridge for the next person, as well as solve my own problem. The project wasn’t very large, at least for a passable first version, but would compensate that more than enough with complexity.
I would be working with generics in this project, and have to design a public API that wouldn’t face breaking changes with every update. I also had to extensively test the code I had written for bugs, and do something I had absolutely zero experience with: documentation.
This code would have to be secure, relatively bug free, provide a clear, concise and most importantly consistent and intuitive public API, and also be well documented.
Furthermore it would also have to be maintainable and modular by design, one because the package had to be redundant, with errors in one module not being able to affect the functionality of other modules, and second because no two projects share the same dependencies, requirements AND implementation except in extremely unlikely scenarios, which would naturally mean modules had to be interchangeable with third party ones better suited to the project in question.
Modules would therefore have to be able to be switched out for third party ones with coding styles, guidelines and protocols that would be impossible to predict and prepare for on a per third party module basis. Fortunately, due to the limited scope of V1 of the package (an intentional decision, and a requirement learned the hard way from previous experience), modularity was not a big problem, and could easily be ignored, at least for now.
This project would be an architecture framework, helping mesh together MobX, the state management solution of the Flutter project, with the UI and integrating both into the <em>MVVM</em> architecture pattern, a pattern that is quite intuitive, and plays well with mobile app projects.
Under this architecture:
- The Model would be classes communicating with external APIs, sanitizing the data coming in, providing functionality, etc. similar if not exactly what the original pattern describes it to be
- The View Model would have some additional responsibilities, and be unified with MobX stores, therefore handling both the business logic and the state of the View it is bound to
- The View would be the UI of the Flutter project, and would also be similar if not exactly what the original pattern describes it to be, the only difference being it would have Observer widgets sprinkled in between, wherever needed, to react to state changes
Along with the above principles, the main functionality provided by the package would be (at least in V1) simply providing an elegant, clean way to “bind” these View Models to the UI.
Although quite simple on paper, as is usually the case, when I started coding, I realized this “simple” functionality housed a fair bit of things in it. I would need 6 different types of widgets, to cover all the possible scenarios of View Model binding, a fair bit larger than the 2 widgets I originally thought.
I also ended up needing to learn much more about Dart generics than I originally planned to, as I realized the functionality I required needed more complex manipulation of generics than I originally thought.
Here, a narrow vision for V1 helped me out greatly, as the project had to grow to be able to accommodate the expanding feature set I realized was quite necessary for a minimum viable product, but the growth was greatly curbed by the original narrow scope of the first version.
The Current State
Currently, that’s all the package does, but architectures aren’t that simple, incorporating everything from data persistence and dependency injection to network and cloud database communication code.
However, these aspects of projects tend to vary widely, and therein lies my problem: striking a balance between creating a maintainable and scaleable architecture (which by definition requires rigorous and strict practices in code implementation) and creating a flexible, adaptable architecture that can be fit into a wider range of projects.
This is the primary reason the architecture must be designed with modularity as a core principle, with modules for, say, data persistence and dependency injection being swappable for other packages as otherwise the number of projects this package can benefit decreases drastically.
This project is and will be very much a work in progress, with new features being added whenever required, fixes for the inevitable bugs that will slip through, etc, and I intend for this to evolve into a production ready architecture framework than any developer using MobX in Flutter will love and enjoy to use.
Check out the GitHub repo of version 1.0.0 of the project <em>here</em>!
Psst, It’s Tanzil from the future, here to let you know that version 2.0.0, which is fully null-safe, is out now, and you can find it <em>here</em>