Rebuilding a Native Mobile App in Flutter From the Inside Out: Part I
This is the first in a series of articles detailing the conversion of one of our mobile apps to Flutter, Google's framework for building natively compiled mobile applications from a single codebase. We share why WWT switched to Flutter by outlining the history of the project, the steps we made to validate the decision and the approach we are taking. Read on to find out whether Flutter is right for your team.
Our mobile app development team is using the downtime from in-person visits to rewrite the ATC Connect app. The app was originally written in Swift for Apple iOS and Kotlin for Google Android, as that was the best approach when its development began a few years ago. We are rewriting it using Google's relatively new, cross-platform mobile framework, Flutter. We expect that Flutter will allow us to develop more efficiently as we continue growing and evolving the ATC Connect app to add new and exciting capabilities.
ATC Connect was built to power our interactions with our customers and partners by facilitating and enhancing in-person meetings and providing access to our articles and thought leadership. The ATC of ATC Connect refers to our Advanced Technology Center, a space we offer both in-person and via wwt.com that allows our customers to review and test our partners' technologies via labs, proofs of concept and other insights that our technology experts prepare.
This first article in the series will cover many of the reasons why the decision to change frameworks was made, from a practical and personal perspective. You'll also learn the unique approach we are taking and see why Flutter was the right choice for us.
We formed the idea and original team structure.
I’ve been a part of the development of WWT’s platform and events app on and off since the beginning. I was even part of the ideation session in August of 2016 where we came up with the foundational features that would drive the existence of the app, decided what technologies to use, determined the technologies to build and outlined the team structure. The video below presents what we set out to do and why, and it’s representative of our approach to many of our customer engagements.
At the time, we made the choice to go with native mobile application development tools because we wanted an app that looked amazing and felt “right” to users. We also wanted to take advantage of mobile platform features such as location awareness and notifications. We knew we needed to target both iOS and Android because ignoring either segment would have left some customers feeling left out.
We started developing the app with a small team on iOS a month or so before we started the Android app. We did this in an attempt to reduce the impact of being blocked by missing services, and to hopefully give the designer enough time to get ahead. It was a good agile project where we used our time effectively and adapted to changing requirements to reduce waste. Once the basic elements were in place, we spun up both the iOS and Android teams to full capacity at around 4 developers each, and we built the full apps in parallel. Things went relatively smoothly, and each app was progressing at around the same pace.
Problems began emerging.
As we got closer and closer to a releasable product, our demos each week were making it obvious that what we thought would be a temporary head-start for the iOS app was turning into an ongoing trend of the iOS app being consistently ahead by a few features. The team and leadership tried many things to address this.
First, we attempted to give the iOS team a few weeks to focus on tech debt and visual design enhancements. Removing the tech debt only exacerbated the problem by allowing the iOS team to move even faster. Eventually more developers were added to the Android side so that there were 5 to 6 Android developers, compared to 4 on iOS. That didn’t seem to help either, as adding more people meant more time spent onboarding. It did allow part of the Android team to focus on tech-debt, making the codebase easier to work with.
One might think that iOS development is just easier than Android, but having worked in both, I know from experience that that’s not the case. And anyway, that’s irrelevant, as we believe the needs of users are always more important than a platform that developers may prefer. With two great teams, something else had to change.
Eventually, by smartly prioritizing the work around the higher impact features, both apps were able to launch day-and-date with feature sets that were identical in the ways that mattered most. There were still a few smaller enhancements that had to make their way back for true feature parity, but nothing major.
After the app was released, both teams continued to enhance the app by adding analytics, adding in content and features similar to those found on wwt.com and building additional features for internal users. The remaining bits of “Android catch-up work” — as we referred to it — kept getting pushed down in priority, so the team and stakeholders always felt a sense that the Android app still needed a little more work.
It’s debatable whether or not that’s true, since work that actual users don’t notice is intrinsically lower value, but the reputation and backlog still followed the team around.
Motivation and ownership were hurting.
In one of our whole-team retros it became obvious that the Android team’s morale was falling. Their work amounted to a port of the iOS app. Many of the big decisions and hard problems were naturally shifting to the team that was further ahead, so the Android team ended up getting stuck with a lot of API and design decisions they didn’t agree with.
One of the goals of ATC Connect is to be a showcase for innovative ideas and technology, but that goal is difficult to keep in mind when the team’s focus is just on getting tasks done. Even features that should be fun and are largely a showcase — like an augmented reality (AR) version of the ATC’s server rooms — ended up being more of a chore to do than an opportunity to flex the team’s skills.
Team members on both sides also came and went frequently because of how the staffing was structured. By the time somebody got up-to-speed and could really start contributing, they were being moved on to other projects. Because we pair program, this isn’t a problem on the technical side, but it does mean that understanding how the app fits into the larger company’s goals and mission is entirely in the hands of the stakeholders, since an ongoing sense of ownership within the overall team is diminished.
Eventually both teams stopped taking on larger features and began doing almost exclusively maintenance work or tweaks to existing features. The desire and resources to really innovate on the mobile side never really went away, but the investment and weight of making changes across both platforms made it harder to entertain features that would have a high impact. This happened so gradually that nobody noticed.
It was time for a change.
To make the app easier to maintain long term, the decision was made to pull the development of ATC Connect into an internal team that could be formed in one of three ways:
- A large team with multiple iOS developers and multiple Android developers.
- A team of highly experienced developers who can work in both iOS and Android.
- A team working on a single codebase that deploys to both iOS and Android using one of the recent cross-platform technologies, such as React Native or Flutter.
In order to determine whether the third option was even viable, some mobile and web developers across the ATC did a two week proof-of-concept to try to remake as much of the app as they could. One group comprised of mostly mobile developers used Flutter, while another group of mostly web developers used React Native. By the end of the two weeks, the web developers had given up on React Native and ended up switching over to the other side and helping the Flutter developers.
The primary takeaway from the proof of concept was that React Native had a very thin core framework and most of the functionality seemed to be coming from third party libraries that were of vastly different levels of quality. Flutter has a similar ecosystem, but the core framework is much more solid and the different approaches to solving the cross-platform problem means that Flutter is faster and creates a more consistent experience between the two platforms.
Getting the basic site up-and-running in React Native was even a bit more difficult than with Flutter. The team was able to get the basic elements of the site working, but the build was unstable, possibly due to some misconfiguration. On top of that, when it came time to integrate some of the other features, such as location awareness, deep links and persistent authentication, the libraries used just felt much more solid and easy-to-use in the Flutter version.
Since everybody involved strongly preferred Flutter based on the proof of concept experience, the choice was clear: we would begin rewriting the app in Flutter and eventually do a big-bang release once we’d reached a certain level of feature parity with the existing app. Some features would have to go away, and any new feature request would have to be built in iOS, Android and Flutter until the Flutter version of the app was finally ready to be released.
We created a new, more agile approach.
It was around this time, near the end of 2019, that Flutter launched the add-to-app feature. This feature allows you to embed a Flutter app or parts of a Flutter app into an existing mobile app in a seamless, high-performance way. Using this feature, we would no longer have to wait until we had completely migrated the app over to Flutter in order to release.
Our agile software development background inspires us to value getting working software in the hands of users as soon as possible. By using the add-to-app feature we were able to quickly spike out integrating a screen from the proof of concept app we did into the existing native apps on both iOS and Android.
With this approach validated, we were able to allow the existing iOS and Android teams to move on to other projects and take over full mobile development within a new team that is dedicated to Flutter, but has enough prior mobile experience to update and integrate with the existing native app code when necessary.
Because we didn't have to wait until the full app was released to build new features in Flutter, we were able to pick and choose which screens we migrated over and integrate new features into those screens as they were developed. For our first screen we migrated over the articles page — the one where you'd find this exact article in the ATC Connect app. While creating the new screen we were able to add a “reactions” feature, which lets you give it a thumbs up.
With the new team in place, turning the single screen proof-of-concept screen from an experiment to an actual production integration took a bit more doing.
In our next installment of this series, we are planning on talking about how to migrate an app over to Flutter, highlighting some of the unique challenges we have faced from a more technical perspective.
Over time, our plan is to migrate the whole app over to Flutter, but even if that takes a long time, we don't have to wait to deliver the most valuable features to our users. By removing the friction and overhead of keeping two teams and products in sync across different languages, we have extra time to experiment and innovate in between larger platform initiatives. Eventually, the team also plans to write our own APIs so that we can be a true, full-stack mobile team.
At the time of this writing, both the Event list and Article pages of ATC Connect have been converted over to Flutter. To download ATC Connect, click on one of the links below and sign in by requesting a magic link using your work or personal email address.
If your organization has made shifts in your approach to mobile application development — whether using Flutter or other technologies — we'd enjoy learning about your experiences. Let us know in the comments below.