Native mobile development is dead. Long live React Native, Xamarin and the new kid on the block, Flutter. Why write twice, when you can write once, run anywhere — or at least, "Learn once, write anywhere"? Cross-platform solutions seem like an ideal solution to a number of issues, but are they really?
Here at Novoda we work with a range of partners, big and small, from multinational corporations to disruptive startups. In recent years we've seen a trend where larger organisations are considering a move away from native development to cross-platform solutions like React Native or Xamarin. However, often we find that the reasons behind these technical solutions are not of a technical nature.
Your product may have issues…
In our experience when a cross-platform framework is considered for adoption it is because of a set of issues that the team — or, more often, management — wishes to address. In no particular order, we have:
"We're reinventing the wheel and wasting money"
Often management perceives there is an inefficiency in having several teams implement the same features over and over again on all the supported platforms, and the promise of "write once run anywhere" is a very intriguing promise that is hard to ignore. This might manifest itself in reasonings such as:
In our corporation we ship several different apps under several different brands. Each of these brands might have an app on iOS and Android, as well as a web presence. But we keep solving the same problem, in marginally different ways, on each platform. This means we end up with several different implementations of each feature. For example, we have twenty different takes on the login screen, all of them talking to the same backend. Maybe if our mobile teams used a cross-platform framework they wouldn't need to reinvent the wheel. We can simply implement things once and start reusing each implementation across all apps.
In the end this often comes down to cold, hard cash too. It's no secret that staffing several specialist teams is expensive and often recruitment-intensive, as experienced, qualified mobile developers can be hard to find. The idea goes that using a single language and platform allows to have a smaller team, since every feature need only be implemented once and all redundant developers can either be used to increase velocity, or let go.
"We need more velocity to deliver on time"
Tying in to the previous issue we have the common "we're moving too slow". The idea is that cross-platform frameworks by default increase the throughput of a team since you can share code, and almost every single keystroke a developer hits will count towards getting a given feature across the finish line for all platforms.
We have very tight deadlines that are dictated by marketing and depend on five other teams. We're outputting at a constant high velocity on all our teams, but they're split across all platforms. If we keep this velocity it will still not be sufficient to deliver on time. Maybe if we used a cross-platform solution like React Native, our frontend web and mobile teams could become one team, and ship features faster on all platforms.
The reasoning in this case is that velocity is an extensive property, which means its magnitude is additive for subteams. Hence if three teams each have a given velocity, if they're fused in a single team their velocity will be near the sum of the three velocities. Cross-platform frameworks seem a natural for this kind of "agile hack".
"Our teams are moving at different paces"
Sometimes the symptom that managers want to address is that teams move at different paces:
How comes that our desktop team implemented this in a day, iOS takes a week and Android two weeks and a half? It's exactly the same feature on all platforms, it even looks the same. I'd imagine it should take the same time for them all. Maybe if we used Xamarin, we could have everyone doing their implementation with the same basic APIs, possibly sharing their code too.
It would seem logical at a first glance that implementing the same feature should take approximately the same time for any two teams of a comparable size, but that is often not the case. Projects that have interlocked releases across-platform cannot help but adapt to the slowest team, and working around the problem by making the code and implementation the same for all teams seems to be a good idea.
...but are you addressing the root cause?
As you put each of those issues under closer scrutiny, you'll probably feel a tingling at the back at your mind that tells you those are just symptoms of bigger underlying problems.
Whenever a team output is seen as too slow — often just a gut feeling, but sometimes backed by data — management will start looking at solutions that should increase velocity. The actual problem is often laying a bit deeper underground, and might not be seen or understood by those calling the shots in this sort of drastic changes. A senior manager might not be aware, for whatever reasons, that the teams are moving slowly because of process or staffing issues, so they assume that it is a technical problem.
In our experience though, technical issues are rarely the root cause of such inefficiencies. What we see more often is that the issue lies somewhere else. It's extremely common in such cases to see "human" causes triggering the cascade that is behind the symptoms.
Sometimes it's plain simple human nature: someone is too proud, or too scared, to admit they're wrong and something they (or someone else) do is hurting the team. Other times it's lack of coordination amongst interdependent teams, or maybe broken communication. Or maybe the people working in one or more teams is exhausted after burning out because some arbitrary or tight deadline forced them into a death march and crunch mode.
Team leads, middle management and developers aren't infallible. That is why, for example, we run retrospectives in all our projects and insist on everyone in teams to take part in them; the first step in fixing problems is to talk about them. The sooner the better, too: a post-mortem after things crashed and burned can provide useful insight, but we should do everything we can to correct course as soon as possible whenever we feel something is not working.
But sometimes, when a job is at risk, or when the surrounding organisation has a culture of finger-pointing, the problems are swept under the rug and (un)willingly misrepresented. This means technical issues get blamed for what amounts to very non-technical causes. Unsurprisingly, this leads to unhappy teams having to adopt technologies they don't necessarily like, in addition to the initial problems.
Cross-platform tools are often misunderstood in their scope and capabilities, and this creates a distorted perception that they can help in these situations. Unfortunately some (want to) believe that a culture and a process problem can be solved by a tool, and that it's the current business and language differences that are holding back cross-team collaboration. However, if multiple teams across a corporation who are writing Swift for iOS, or Java for Android, are failing to share code — and, more importantly, share domain knowledge — it's unlikely that introducing a cross-platform framework or any other technology change will fix it.
Improve your structure
Instead, the problem may lay in several other places. The company environment might discourage effectiveness, because of a high degree of bureaucracy or because of indirect, delayed communication. The broken window theory formulated by criminology translates very well to development teams and working environments too. If a team fails to take care of the small things, then eventually it will neglect the big things too. If your TODOs are never addressed, if the code style is incoherent, if issues disappear in a sea of other tickets when they're added to your tracker, if corners are cut on a regular basis to "save time" and tech debt is continuously accrued but never addressed, your teams will struggle to be passionate, be productive and be efficient. They'll produce bad code, bad designs, bad processes which will compound each other and make matters worse, in a self-reinforcing cycle in which team members care less and less about what and how they work on.
The solutions to these problems are not as easy as just adopting a new tech stack, and may involve going through a painful process before things become better. Take inspiration from how other companies addressed their issues. Team and productivity pains are extremely common and every single organisation hits them at some point. There is no shame in having growing pains, as long as we admit there are pains and try to address them.
One of the most famous reorganisation strategies is Spotify's agile restructuring in tribes, squads, chapters, and guilds. Squads are vertical teams and chapters are horizontal specialisations inside of a tribe, while a guild is a cross-tribe organism that leads the way with regards to a specific topic (e.g., security). We adopted the guilds system in Novoda when facing our own growth process pains, and it's working very well. You can learn more about it on Spotify's blog. What worked for Spotify and Novoda might not work for your company, though. It's very important that you choose a structure and processes that fit your environment, rather than trying to force an alien structure on it.
Coordinate teams and their throughputs
One of the symptoms we mentioned is the different paces at which development teams move on different platforms. While this is perceived as a problem, it is somewhat intrinsically linked to how different teams and platforms work. The most common reason why teams work at different paces is that they have to deal with different codebases, architectures, and tech debt levels.
A common case is that the iOS app has a well-maintained codebase and is leading the feature set, whereas the Android codebase has been hastily thrown together and has never seen a coherent architecture — or the other way around. The latter team is likely dealing with massive amounts of tech debt that slows them down, tight coupling and low testability of the code which makes any change complicated and risky, and a lack of architectural clarity. Making any changes to it is going to be a monumental task, and the velocity will be extremely low.
Listen to your developers. They will raise such issues whenever you ask them for estimates on a feature. Make sure you build into your process and schedules enough time for them to get to an acceptable level of tech debt before moving to the next big chunk of work. For example, allow them to schedule a set amount of maintenance in each sprint or dev cycle, and define low-risk timeframes — such as right after a release — to do bigger tasks, such as improving the architecture and fill in the gaps left by cutting corners to get to release.
Remember that crunch modes can only be sustained in short, rare burst and only should happen in exceptional circumstances. Death marches are the best way to alienate your team, make them unproductive, and risk their health, all while still missing deadlines and features. Setting realistic expectations while planning is vital to be able to deliver on time and on scope, and this is why the whole team should be part of the planning. Imposing arbitrary deadlines is just as detrimental as changing scopes without allowing for different deadlines; even if your teams are following agile practices it doesn't mean they can deliver arbitrary features at arbitrary time. It means they can either deliver a given feature with a well defined, immutable scope on time, or deliver vaguely defined features with changing scope eventually, possibly sooner than with a waterfall process.
Focus on value
Another common fallacy that brings managers and teams to look at cross-platform frameworks is that it'll allow them to save money. Unfortunately, that is rarely the case. We really appreciate the frameworks that don't focus their marketing message on the (often false) promise of saving money, but rather on the fact that they can bring value.
The Flutter team for example often says that what they bring to the table is the ability to deliver more value for the users, and hence for businesses. With Flutter, their theory goes, developers can attain increased velocity. With a higher velocity, the customer and user is getting more value for the same amount of money, in the form of more features, more experimentation, and more solutions for users. They never focus their message on sharing code, or on lowering costs. In reality, programming languages and tech stacks are one small piece of building an app.
No cross-platform solution will isolate your team from the complexities and subtleties of the platforms they run on. Anything beyond trivial apps, and your team will inevitably have to deal with the quirks of the OS that's hosting them. Where that line of triviality lies, depends on the framework and how they're employed. For example Xamarin can have that line further or closer to zero, depending if you use Xamarin.Forms or not. For others, it varies on the APIs you have to use.
As a result, you will still need to have at least one developer that is an expert on each platform in the team to be able to be fully productive. Depending on the specific framework, you might have difficulties staffing a team. This might turn out to be more expensive than anticipated, nullifying any theoretical gains from sharing code. It's a careful balance to be found and it is not for everyone.
We don't believe the need for platform experts will ever go away, considering how no cross-platform solution so far has ever found a way to get rid of that. Consider the 20 years run of Java, the poster child of "Write Once, Run Everywhere", or Mono — the ancestor of Xamarin, or any other technology. There is always a situation in which you need to, directly or indirectly, interact with the underlying platform outside of the "safe space" of the framework.
What this all means is that choosing a cross-platform SDK because it is supposed to save you money is very likely to be a bad idea. What you should aim to get out of a cross-platform team is value for your users and, by extension, to your business. To obtain value, you need to be aware of your teams' processes and state of mind, and still be aware of what kind of value a framework can bring, and in which conditions.
Get value out of cross-platform
This does not mean that all those cross-platform frameworks have no place in our toolboxes. What it means is that we need to treat them like tools — which is what they are — rather than solutions. If you have a problem that can be solved with such a tool, and a team that can pick up the new framework and be proficient with it, and you are aware of the compromises your choice involves, then you can get great value out of these tools and get to a satisfactory solution.
The mere existence of these frameworks shows that someone thought they could be the right tool to solve their problems. Facebook created React Native because they had a lot of web frontend developers that were familiar with ReactJS, and couldn't staff mobile teams quickly enough for their enormous growth. They created mixed teams of ReactJS and mobile developers, and gave them a tool that allowed them all to work on mobile apps.
This is why React Native works so well for them. Besides having orders of magnitude more engineers than most companies out there that they can throw at problems, they have troves of developers that are familiar with the paradigm and language, or familiar with the underlying platforms. The same goes for AirBnb which is using it heavily and to great success. AirBnb managed to find problems that fit the strengths of the tool; Facebook had built the tool to work in their specific situation. The dozens of corporates that successfully employed Xamarin to build tools and projects had many .Net developers at their disposal. The agency that developed the Hamilton app in Flutter didn't actually have much in the way of Dart developers, but they had the perfect kind of project for the framework: relatively low complexity, heavily branded UI, using Firebase, to deliver very quickly.
And they all have one thing in common: they used the right tool for their problems — or, in Facebook's case, they made a tool that fit their problems. Since almost nobody is Facebook and we cannot afford to create tools from scratch every time we have a problem, all we can do is to be sure that we need a new tool in the first place, and then only in that case pick the one that works best for us. If you don't have the know-how in house for this sort of decisions, you can reach out to an agency like Novoda. We have helped several of our clients understand all the ramifications of their choices over the years, and would be happy to work with you on finding the best solution.
Before choosing a tool, no matter what its nature is, it's important to first thoroughly understand the problems and pain points that you are trying to alleviate. If and only if your problem is of a technical nature, then you should proceed to pick the tool that best helps solving it. But if your issue is rooted elsewhere, then no matter what technology you adopt, you'll be doomed to repeat the mistakes of the past. After all, technologies can't create a process or a team.