Picking Mobile Technology

Developing a mobile product introduces many questions about technology. Which do you choose?

Over the last year or two, we've seen a significant increase in mobile application development projects. As companies seek to broaden product coverage, or identify unique uses cases for mobile technology, they also invite questions about the best way to build them.

As a third-party vendor, we have a responsibility not only to ship exceptional products, but also to hand-off work that a client can have success with in the future.

For us, this inevitably boils down to:

  1. Using the first-party tools Google and Apple give us for making Android and iOS apps
  2. or choosing a cross-platform solution written in JavaScript, like React Native.

At Viget, we're continuing to evaluate the best circumstances for either approach, and have had a lot of internal conversation about these options. I thought I’d share where we’re at.

To get a more in depth look at mobile technology, check out this Choosing Mobile Tech webinar recording I put together. 

Quick tech primer

First-Party Native

By first-party, I mean using the tools provided by iOS and Android to produce an app for each platform. At Viget, this means writing an iOS app in Swift and an Android app in Kotlin.

By building two applications with first-party development tools, a product benefits from:

  • Very mature tooling
  • Clear upgrade paths
  • Easier integration of the latest platform features
  • First-class access to the underlying platform, like native drawing APIs for a high degree of visual control

The tools are amazing

Android Studio and Xcode are powerful, robust application development environments designed specifically for mobile application development. Features like design previews, accessibility checks, and performance monitoring make it easy to build highly polished mobile applications.

The Xcode View Hierarchy Debugger makes it easy to figure out how a screen is constructed in a visually compelling way.

Comprehensive library support

Additionally, library support is extremely comprehensive, with solutions for common problems readily available; some have been around for a decade or more.

On Android, software suites like Android Jetpack make it easy to write applications with common architecture and patterns. This is particularly beneficial to us because it means we can pass along standard, well documented, code, instead of bespoke systems. This means developers can pick up our work more quickly and draw from existing resources when they need help.

Extra Costs

The trouble with first-party native is simple: writing two separate applications, even with the allure of easier code sharing, is expensive:

  • You’re building two applications. That means more staff with fewer developers on each app.
  • Platform-specific challenges mean more features could ship for one platform than another.
  • You need to hire an iOS and Android team or build up internal expertise.

Still a great option

At Viget, we love writing first-party native applications. We find it much easier to chase towards a highly polished application, and it’s a joy to get there (most of the time). However, in many cases, staffing, budgetary, and team requirements make it a difficult commitment.

That leads us to an alternative: cross-platform development.

Cross-Platform Development

Cross-platform development means writing an iOS and Android app with the same toolkit. This varies: spanning two separate apps within the same authoring environment, to a single application that might deviate for a handful of specific platform requirements.

Introducing React Native

At Viget, our preferred cross-platform approach is React Native. We’re long time users of React, first experimenting with it in 2014 with the 0.9 release. We've followed React and React Native for a long time: the promise of using React Native to deliver on mobile projects is alluring. By relying on React Native, a team can benefit from greater staff availability and maintain a lower number of core skills. It lets you do more in JavaScript.

When working on a React Native project:

  • Most development can happen in the preferred tool-chain of JavaScript developers: code editors like VS Code or Atom, terminals, and testing frameworks like Jest, etc.
  • Leaning heavily on JavaScript reduces the burden to pick up native application development skills (though we highly encourage it).
  • Working from a single code-base often means larger team availability and less pressure to hire additional staff.

When it works, it can be a huge boon. It is amazing how quickly you can iterate on a design with React Native. 

Still, it’s not paradise. While React remains an excellent UI abstraction, React Native does not seamlessly abstract away the underlying platform, particularly as you get into native integrations and platform specific UI behaviors. Sometimes you must pull in a React Native package that utilizes native code, either for performance, native features, or user expectations. However that can bring confusing errors that first appear daunting:

Introducing a native module from npm can some times create unexpected build errors.

What’s going on here? We’re pulling in a React Native package that is included as an Android library, but it introduces some problematic build configuration.

This actually isn’t a big deal and it’s very easy to fix, but if this is your first time seeing the error and aren’t familiar with how the package system works, or you’ve never configured Gradle before, Stack Overflow will often lead you down a rabbit hole of mismatched solutions that waste a lot of time.

Knowing the platform is still essential

Much of this can be mitigated by learning how the underlying platform tools work, and we encourage all React Native users to spend the 2-4 hours it takes to build a sample first-party native application to get comfortable with these tools. You’ll certainly spend enough time in them to justify it, and even more if you don’t. 

Doing this will greatly improve your experience, and it can be a joy:

Particularly when working with tools like styled-components and Watermelon DB, the combination of underlying platform power with a scripting language to stitch it all together is awesome:

Okay, so how do I pick one?

There are a handful of important decisions that we try to cover with every client engagement:

What is your existing developer talent? Do you want to grow your team?

This is essential background information to consider when framing an engagement. Viget usually needs to hand-off code to an existing team. For a project to be successful, we can't also pass along a new business problem. 

Team size

Small teams looking to build an MVP gravitate naturally to a cross-platform solution like React Native. Dealing with some of the pain points is fine because, ultimately, it gets them a product out the door faster with a smaller number of developers. When working with a company like Viget, this also translates into a faster timeline and smaller budget; essential for companies looking to validate an idea quickly.

Existing skills

At the same time, existing iOS or Android shops looking to extend their product to other platforms already have first-party native expertise. They aren't looking to rewrite an existing app, and transitioning skills from one platform to another is an intuitive process. It’s easier to justify ramping up internal expertise with the new platform.

In this case, going with a first-party native solution is usually the best fit. It means they can benefit from a more straightforward support story. Their native developers can do what they do best: build native apps, without having the extra burden of keeping up with upgrade hurdles and community shifts with a cross-platform approach (discussed later).

Product requirements

Every product is different, and some require custom native functionality not readily available to a cross-platform solution. That may expose challenges that push you one way one over another.

Prior tech commitments

If your team already has a heavy commitment to a particular technology, or features that lack React Native support, this can easily sway you towards going with first-party native.

While React Native Native Modules are awesome, you may not be interested in building a React Native wrapper around a library you don’t maintain, and the comparative effort to keep that up to date may be an ongoing source of frustration and time away from your core user experience.

Performance

Additionally, developers of apps with heavy performance demands will find themselves debugging issues with more layers of abstraction on a cross-platform approach. This requires you to not only need to know the underlying platform tools, but also to understand how bottlenecks are happening within the context of cross-platform framework code.

Don't sweat performance

Having said that, it’s important not to over think this. If it's hard for you to anticipate performance demands up front, chances are it isn't an issue.

A lot of apps simply load JSON, turning it into a chart, or drill down into a list. Performance issues in these circumstances are often isolated and rare.

Leaning on React Native for simpler apps can be really awesome because, chances are, you already have a web application that is written in a JS framework like React. You just want to build a satellite mobile app to support that product. Your demands aren’t great and a cross-platform approach improves your maintenance strategy, even if you have the occasional hiccups.

Project complexity

Cross platform and first-party native may be simpler and easier to maintain in their own ways. However that simplicity is balanced with other sources of complexity. 

Cross-platform: fewer apps, more moving pieces

Since React Native controls for many platform differences, it is much easier to add new features and design changes. This makes project planning simpler too — often with the same ticketing and project team for both iOS and Android. You can go a surprisingly long time without needing to worry about how one platform behaves over another. 

However, it happens. You'll encounter a case where something "looks weird" on Android, or crashes in a strange way on iOS. Fixing the problem will require either platform specific code or an alternative approach. 

Controlling for these differences will make your app more complicated, requiring coordination with developers and QA to make sure all cases are adequately covered.

Get ahead of upgrades

Compounding on this, upgrading can be tricky too. As React Native sends out updates, many community packages will cut major version releases to ensure compatibility. However, bug fixes will often only merge to the latest version. You can be on a buggy 3.x version of a package, and discover that the fix is only included in 4.x. 

This leaves you in a position to either upgrade more of your application than anticipated, fork the package, or send out a fix and hope the turnaround time meets your release cycle.

This increases the pressure to keep your application dependencies up to date, which results in more effective code churn. That means more time spent ensuring the upgrade did not also introduce new issues, requiring more coordination with the development team and QA. 

First Party Native: more apps, fewer use cases

At the same time, building two first-party native applications is fundamentally more complicated from a project planning standpoint. You are locked into building two different applications, with project timelines for each. That requires more organizational coordination, and approaches to many problems will be different on each platform. 

However from a development standpoint, you're only worried about one platform, often with very mature solutions to common problems. That makes development more straight forward. When sending out updates, QA also has a smaller testing surface area for discrete changes.

We have also found upgrading to be comparatively easier as well. Our project dependencies aren't as interconnected, resulting in less of a cascade when bumping versions.

Pick your poison

Identifying the type of simplicity you want to optimize for, or at least the complexity you are most willing to deal with, is an important part of picking an approach. While it may not sway you one way or another, being aware of it early will help you to mitigate project risks and avoid unexpected delays and costs.

A few examples

We believe both cross-platform and first-party native solutions can be used to achieve product and business goals for our clients. However, it’s important to think about the team that will maintain them and the arc of the product’s life.

The cross-platform sweet spot

A while back, we wrote a series of apps for the automated checkout company Standard Cognition

They needed to move fast, and were still in the early phases of validating the concept. With unique native feature requirements, going with the mobile web wasn't an option. React Native allowed us to move quickly to deliver consumer-facing applications for their automated checkout flow while still providing a development experience that aligned with their existing staffing goals. 

As Standard Cognition ships new features, they benefit from unity across platforms, allowing them to continue to move fast.

When more moving parts makes less sense

At the same time, when building a telemedicine mobile product for Privia Health, we didn’t feel that React Native had a sufficient support for their underlying teleconferencing vendor. Instead of writing a compatibility layer for React Native, we deemed it better for overall product health to write two first-party native applications.

Otherwise it would mean handing off a React Native app with two sophisticated React Native native integrations. For an app primarily focused on telemedicine, building a wrapper around that core functionality would effectively result in handing off three apps, instead of one.

Going with a first-party native approach allowed us to avoid this work, delivering a much simpler pair of applications that achieved their goals with an easier long term maintenance strategy.

Final thoughts

Our experience is that building native mobile applications with first-party tools provides us greater stability and allows us to achieve a higher degree of polish. Upgrade paths are clearer, and it is easier to find help. However it remains a higher cost option, both in development costs and in long term organizational change. That simply isn't tenable for many companies: a cross-platform approach like React Native provides a trade-off that is significantly higher value for their business goals.

For those considering a cross-platform approach: still invest time to learn the underlying platform. To use React Native without understanding its backbone is like using React without understanding the browser. There’s only so far you can go until you need to lean into the platform. Being able to do so can offer a wonderful blend of familiar skills with access to powerful features impossible to build with JavaScript alone.

Let's talk

At Viget, we’re excited to have these conversations with clients — to help them pick a technology that achieves their business goals, is easy to adopt, and is a pleasure to maintain. Watch our recorded webinar on this topic or contact us to see how we might help!

Nate Hunzaker

Nate is a development director working from Redwood City, where he focuses on client-side application development. Most days, you can find him neck-deep in a React app or diving into new feature on Android as he works with clients like FiscalNote and Arcadia Power.

More articles by Nate