Today I’m going to discuss some pros and cons of Realm and Room for Android data persistence. Room was introduced at Google I/O 2017 as part of the Android Architecture Components. Realm is a mobile database solution that was launched for Android in May 2014 and has become a feature-rich choice for data persistence. While both serve a similar purpose, they are very different in implementation and their effectiveness may vary depending on your projects needs.

Room is just a layer over the native SQLite that comes stock with Android. As such there is a large amount of customizability in the queries (you write your queries in SQL and they are validated at compile time). However, Room also requires that relationships be created using foreign keys and the like, so complicated object graphs can be a bit of a pain to implement. Realm on the other hand requires no SQL knowledge. You do not have to write any SQL statements and object relationships are incredibly simple to implement. Referencing one object (or a list of them) from another object creates the relationship automatically.

Realm is a much larger library than Room because it includes a separate database. It adds somewhere around 3-4 MB to your app’s apk. Because Room is just a layer on top of SQLite, it only adds a few dozen KB to the APK. Room also contains far fewer methods if you are concerned about dex method limit.

Realm requires that objects not be passed between threads. Realm data objects are views into the data that respond to database changes so they are tied to whatever thread the Realm instance that they were retrieved from exists in (if that Realm instance is closed, any objects retrieved from it become invalid). In my experience this isn’t generally much of an issue if you are careful about it, but if you find yourself switching threads a lot you’ll have to create new Realm instances and re-query to get your objects. No such thread limitations exist for Room.

Room is officially supported by Google, so it should remain well supported and will likely have good community support. On the other hand, Realm has been around for a while (officially released about 4 years ago for Android) and has undergone tons of bug fixes and improvements and has an active community. Additionally, Realm supports iOS as well as Android, so developing for both platforms with virtually the same data persistence layer can allow for similar app architectures.

Both libraries support reactive queries, allowing you to subscribe to updates on a view of your data. Room achieves this using LiveData, another part of the Android Architecture Components, which can be linked to an app component (Activity, Fragment, etc.) and update intelligently based on the lifecycle of the component (i.e. not causing UI updates when an Activity is in the background). This is a nice feature to have out of the box and allows you to avoid keeping track of unsubscribing listeners in backgrounded app components. Realm objects, lists, and query results can all be directly subscribed to in order to monitor for changes, convenient features not entirely present in Room. Realm also has an additional library for an auto-updating Recyclerview adapter. While something similar isn’t too complicated to implement with LiveData, Realm’s library comes for free and works well.

Depending on your app’s data model complexity, APK size concerns, and personal experience/preference both Realm and Room are viable options for data persistence. Let us know in the comments which one you prefer.

At Oak City Labs, we rely heavily on unit testing in our quality software process. Unit testing is the safety net that lets us reliably improve existing code. Our testing suite double checks that modified code still behaves the way we expect. I’ve written before (here and here) about how we use dependency injection (DI) which makes unit testing easier. DI helps us wrap code we need to test in a special environment. By controlling the environment, we can make sure that the code being tested gives the correct output for a given set of conditions. This works very well for pieces of the application that we can encase in a layer that we control. Unfortunately, we can’t wrap everything.

Consider our API layer. This is the part of our application that talks to the server over the internet. It makes network calls, processes replies and handles errors like slow network responses or no network at all. In testing this code, we want it to behave as normally as possible for accurate testing, so we still want it to make API requests and interpret the results. At the same time, these are unit tests, so they should be fast and not depend on external resources. We don’t want to make requests to a real server on the internet. If that test failed, it wouldn’t be obvious if our code was broken, the server was down or the network cable was mistakenly unplugged. It’s important that our unit tests be self contained so when something fails, we know that a specific section of code has failed and we can fix it ASAP.

Back in the old days, before Swift, we wrote in Objective-C. Swift is a strongly typed language where Objective-C is weakly typed. While weak typing in Objective-C often gave a developer enough rope to hang themselves, it was flexible enough to do interesting things like easily mock pieces of software. Using mocks, fakes and stubs, you could (with some effort) replace pieces of the system software with substitute code that behaved differently.  We could use this to test our API code by changing the way the system network routines worked. Instead of actually contacting a server on the internet, a certain call just might always return a canned response. Our API code wouldn’t change, but when it asked the system to contact the server for new data, our mocked code would run instead and just return the contents of a local file. By building a library of expected calls and prepared responses, we could create a controlled environment to test all our API code.

Swift, on the other hand, brought us strong typing, which wiped out whole classes of bugs and insured that objects were always the type we expected. We paid for this safety with the loss of the ability to easily mock, fake or stub things. Someday, Swift might gain new features that make this possible (maybe even easy) but for now, this is difficult to do with any efficiency. So, we need a new approach for testing Swift API code.

Like we said earlier, we don’t want to use external network resources to test our code because too many things are out of our control. But what if the test server were running on the development machine? In fact, what if the test server were running inside our application? Enter two open source projects — Ambassador and Embassy from the fine folks at  Embassy is a lightweight, dependency free web server written in Swift. Ambassador is a web framework that sits on top of Embassy and makes it easy to write a mock API server.  

In this new approach to testing our API layer, we’ll write some Ambassador code to define our mock endpoints. We’ll declare what URL path they’ll respond to and what response the endpoint will return. Now, inside our unit test, we’ll fire up the mock server and run it on a background thread.  Since you’re controlling both the client and server side of the request, you can make asserts on both ends of the exchange. On the server side, you can validate the data submitted by the client. On the client side, you can ensure that the response from the server was interpreted correctly. Ambassador has some nice conveniences as well for working with JSON data, introducing delayed responses from the server and other common testings needs.

In order to use our freshly built API mock server, all you need to do is change the server name used by the API layer. This is important because we don’t want to make significant changes to our code in order to test it. We want to test as close as we can to production code. By switching our base URL from “” to “http://localhost:8080”, we can test all our network requests with no external dependencies. Since we’re using dependency injection, this change is very simple to implement in our unit testing routines.

The move from Objective-C to Swift has allowed us to write cleaner and safer code, but the price we pay is the loss of the fast and loose, über permissive Objective-C runtime environment. Fast and loose always caused more problems than it solved, so I’m happy to see it go. A few of our existing solutions have gone with it, but with a bit of ingenuity, we can move forward with better and safer new solutions.


A few weeks ago at the All Things Open conference I was introduced to a term I had heard a few times but had not done much research on: “Progressive Web Apps”. Wikipedia describes Progressive Web Apps (PWAs) as “regular web pages or websites but can appear to the user like traditional applications or native mobile applications. In other words, PWAs are websites that look and behave like mobile apps. Now, isn’t that interesting?

It appears that the main priority of PWAs is to combine the benefits of modern browsers and web development with the benefits of a mobile experience. Several checklists by Google Developers contain the requirements for being considered a baseline PWA as well as an exemplary PWA. They also suggest using the Lighthouse tool for “improving the performance, quality, and correctness of your webapps.”

The baseline PWA requirements are:

  • Site is served over HTTPS
  • Pages are responsive on tablets & mobile devices
  • All app URLs load while offline
  • Metadata provided for Add to Home screen
  • First load fast even on 3G
  • Site works cross-browser
  • Page transitions don’t feel like they block on the network
  • Each page has a URL

It is evident from this list of requirements that Progressive Web Apps are really aimed at providing a secure, modern online and offline experience, much like mobile apps. Let’s look at some reasons why people might prefer a PWA to a native mobile app.

Preferring PWAs


PWAs allow developers to leverage the search engine benefits of SEO practices. In this way, existing search engine SEO strategies can be employed in order to promote an app rather than App Store Optimization techniques.


One of the requirements for classification as a PWA is that is works across different browsers. This rule means that not only can PWAs be used on computers across operating systems, but on mobile web browsers as well.

Additionally, users don’t need to go through the process of grabbing an app install from the app store. This implies that developers also don’t need to go through the process of uploading apps to be reviewed by Google and Apple before releasing any updates. This, in turn, means instant updates for developers and end users.

Caching / Offline Usage

One of the typical benefits of mobile apps over web apps are the amount of storage you have access to. With modern Cache APIs, users can install their PWAs to their home screen and access the app offline without needing to download any additional data. This functionality mimics that of a mobile app and unlike most websites, allows users to use the app even without internet.

Push Notifications

The age of notifications is upon us. Hardly an hour goes by without receiving a handful of notifications from various social media networks, emails, messages, etc. PWAs bring this functionality to the web, allowing you to receive notifications straight to your device, whatever it may be.

Hesitations about PWAs

While there are many upsides to the growth of Progressive Web Apps, upsides I am personally excited about, I would be remiss if I didn’t address their potential downsides as well.


Because PWAs don’t receive the same sort of App Store review that Google and Apple require, developers can stick anything they want into their apps. This means that if a developer chooses to be secretly malicious, they could, and there’s no review process stopping them from doing so.


Web apps can do a lot, but they can’t do everything. There is a lot of functionality only able to be utilized by native mobile apps still. PWAs are gaining ground every day, and as such are growing in the number of previously native-only features offered. Despite their gains, however, native apps still have many features that PWAs simply don’t have the ability to accomplish yet. Check this site to see if the functionality you want to add can be done with a PWA!

Platform Limitations

Plain and simple, iOS likes iOS apps. PWAs are only as successful as the platform that they are to be used on. As stated above, PWAs are gaining support every day. Within a few years I fully expect PWAs to have a majority of the functionality normally afforded solely to native apps.

Final Thoughts

Progressive Web Apps are a wave. Whether they are the wave of the future is yet to be seen. The fact that Google is pushing PWAs should be a sign of things to come, as they are often at the forefront of web development technologies (See: Angular, Vue). It will be awhile before PWAs gain all the functionality that native apps currently have, but they are on their way. Batten down the hatches and ignore the naysayers – viva la Progressive Web App!

At Oak City Labs, we love our continuous integration (CI). In our world, CI means that we have a trusty assistant sitting in the shadows that watches for new additions to our code repository.  Any updates get compiled, tested, packaged and shipped off for user consumption. If something goes wrong, the team is alerted immediately so we can get the train back on the tracks.

Let’s dive a little deeper at the toolset we use for CI. For iOS and Mac development, it might seem like a natural choice to use Xcode Server and we did, for a time. However, as our project load grew and our need for reliable automation increased, we found that Xcode Server wasn’t meeting our needs. We switched to TeamCity with very good results.

Xcode Server, after several years of evolution, has become a solid CI server and has some advanced features like integrated unit testing, performance testing and reporting. The great thing about Xcode Server is the integration right into Xcode. You don’t have to bounce out to a website to see the build status and any errors or failing tests link directly to your code. Unfortunately, that’s where Xcode Server runs out of steam. It doesn’t go beyond the immediate build/test cycle to handle things like provisioning profile management, git tagging, or delivery to the App Store.

Enter Fastlane. When we first adopted Xcode Server, Fastlane was in its infancy, only partially able to cover the iOS build cycle. In the years since, Fastlane has grown to be a full and robust set of automation tools that blanket the iOS and Mac build cycle, reaching far beyond the basic build/test routine. As Fastlane developed, we pulled more and more features into our CI setup. We built python scripts to integrate various Fastlane pieces with Xcode Server. Eventually, we were spending a good deal of time maintaining these scripts. Fastlane, on the other hand, handled all the maintenance internally, if we would embrace Fastlane fully. There were also some pieces we had built by hand (Slack integration, git tagging) that Fastlane included out of the box. It was clear that it was time to wholeheartedly jump on the Fastlane bandwagon to drive our automated build system.

One hiccup — Fastlane really wants to drive the whole build process. This is a great feature, but it means we can’t realistically do that from Xcode Server. We were already using TeamCity for CI with our other projects (Python, Angular, Android) and it seemed like a good fit. TeamCity is great at running and monitoring command line tools and now with Fastlane, our iOS and Mac builds are easily driven from the command line. Fastlane also creates TeamCity compatible output for tests, so our unit test reports are displayed nicely in the TeamCity dashboard.  

Now that our build system is fully Fastlane-ed, we benefit from their rich library of plugins and utilities. It’s simple to compute a build number for each build and push that as a git tag. Success and errors are reported to the team via Sack. We can easily publish beta builds to Crashlytics and send production builds right to Apple’s App Store. Fastlane’s ‘match’ tool keeps our provisioning profiles synced across machines. There are even utilities to sync our DSYM files from iTunes Connect to our crash reporting service.

Having the CI for all our projects under the TeamCity roof also comes with some nice benefits. There’s a single dashboard that shows the status for all the projects. There’s one login system to manage. The TeamCity server queues all the builds, so if an Android project is building when an iOS project updates, the iOS build is queued until the Android project finishes. With separate CI servers before on a single machine, you might have projects building in parallel which push the memory and cpu limits of the build machine. Also, the artificially elongated build times could confuse the build server system that monitors build time.

Our fully automated iOS and Mac build configurations have been running in the TeamCity / Fastlane environment for almost a year now and we’re delighted with the results. The Fastlane team does such a great job keeping up with changes in Apple’s environment. On the few occasions that things have broken, usually due to changes on Apple’s end, Fastlane’s team has a fix almost immediately and a simple ‘gem update’ on our end sets everything right. Going forward, Fastlane and TeamCity are our tools of choice for continuous integration.

Hurricane season may be tapering off as we enter the last week of October, but the use of technology during all sorts of natural disasters shows no signs of stopping. As we all know, the United States experienced three powerful hurricanes in August and September (Harvey, Irma and Maria), each delivering an unprecedented amount of flooding and damage to the areas impacted. Then deadly wildfires ripped through the California wine country. Earthquakes shook Mexico.

Enter technology.

More than ever before, we witnessed mobile apps at work during these disasters connecting victims with the aid they desperately needed.

Zello, a free app that turns your iPhone into a walkie-talkie by using a WiFi signal when cell service was down, shot to the top of the App Store. And it was used by the “Cajun Navy” to rescue hundreds in Texas following the flooding by Hurricane Harvey.

Ride-sharing apps Uber and Lyft offered free rides to shelters for evacuees, while AirBnB used their platform to arrange free shelter for victims in the homes of hosts.

In Florida with Hurricane Irma approaching, residents were urged to flee north and as roads jammed with traffic, gas was in short supply and high demand. Florida Governor Rick Scott urged citizens to utilize GasBuddy, an iOS and Android app which typically crowdsources pump prices from users, to track fuel availability. Elsewhere in Florida, Tesla gave drivers of certain models an extra boost on their batteries allowing for additional mileage before needing to recharge.

More than a month after Hurricane Maria made landfall in Puerto Rico, the island is still largely without power and cellular service. But efforts from Google, Apple and AT&T within the past week have allowed some users to reconnect to cellular service through Alphabet X’s Project Loon balloons. Yes, balloons are currently helping provide internet to the island.

Both Apple and Android released collections of apps tailored for the disasters at hand, such as the Google Play Store’s Hurricane Irma collection.

In Mexico, two devastating earthquakes shook the nation and took hundreds of lives. But a new early warning app called SkyAlert has seen 5.8 million user downloads.

As wildfires ripped across California, iOS and Android app CAL FIRE helped residents prepare and provided real-time updates on the fire’s latest status.

Like most things in life, technology’s presence in natural disaster recoveries is not without blemish as CEOs of major tech giants are known to make a blunderor twoor three. However, it’s obvious that blemishes and all, technology will now always play a vital part in how we respond to devastation. In this article, former FEMA spokesperson Rafael Lemaitre admitted that in a post-Katrina world there is a part for citizens’ and the private sector’s involvement in recovery efforts. No longer do we expect or count on the government to handle it all. And, according to Lemaitre, tech companies…“could be a big help.”

Your Android app’s visibility in the Google Play Store can be just as important as building the app itself. Today we’re sharing a few tips to optimize your Android app’s Google Play Store listing and improve its visibility for users.

Of course, total installs and positive reviews are extremely helpful for your app’s visibility, but there are also steps you can take to ensure that Google’s search algorithm will prioritize your app as highly as possible in the search results.

Keywords in the Application Title

Use keywords in your application title. Google takes app title into account when ranking your app in search results, so adding a few relevant and descriptive keywords to your app’s title can help it rank higher. There are 50 characters (recently upped from 30) to work with, so come up with a name that succinctly summarizes your app. For example, the GrubHub Google Play Store listing’s title is not just “Grubhub” it is “Grubhub Food Delivery/Takeout”.

Keywords in the App Description

Use keywords in the app description. In the Google Play Store, description greatly affects your app’s ranking (unlike Apple’s App Store, which provides a separate keyword field and does not take the description into account when ranking). Repeat your chosen keywords several times in your description, but use them in a way that sounds natural (Google has policies against spamming keywords, see here).

Long-tail Keywords

Long-tail keywords refer to phrases that are specific enough to target users that are in the later stages of their search for an app. These users are more likely to find what they are looking for in your app, and thus are more likely to install. Long-tail keywords also face less competition than more generic keywords in search results. Think “local used car shopping” vs. just “shopping”. An app that helps users find used cars for sale in their area is more likely to show up in a search for “local used car shopping” than in a search for “shopping” because fewer apps are using that same combination of keywords. Keep this concept in mind when determining what keywords to include in your app’s store listing.

External Links

Use external links that send users to your app’s Google Play Store page. External links to your app’s listing cause Google to rank your app a bit higher in search results. You should encourage reputable sites, blogs, etc. to include links to your app’s store listing.

These few tips are easy to implement and are great options for optimizing your Android app for the Google Play Store. If you need help launching your Android App to the Google Play Store, let us know!


Apple’s latest operating system iOS 11 released earlier this week! Ever since the features were announced at WWDC this past summer, our CTO Jay has been excited for the release. Top features he’s excited about? ARKit (look for this to make a big impact on the way we think about and build apps over the next five years), iPad productivity updates that will allow more users to abandon their desktops for the tablet and Apple Pay integration with Messages – coming “this Fall” – lowering the barrier to entry for many users who have yet to adapt the technology.

The release of iOS 11 also brought about a notable change that is worth sharing.

With its release, iOS 11 will drop support for some of your existing apps causing those apps to stop working altogether. What does that mean? Older apps that are still running with 32-bit architecture will no longer open or work once you upgrade to iOS 11. Only apps using a 64-bit architecture will work in iOS 11.

That may seem harsh, but the reality is that Apple has required all apps since June 2015 to be submitted using 64-bit architecture, so if you have an app that is still 32-bit, that means it hasn’t been updated in at least two years – yikes! Additionally, Apple knows that 32-bit apps occupy a very, very small percentage of App Store income so they have no real incentive to continue providing support for them.

What should you do if you suspect you might have an older 32-bit app? Before upgrading to iOS 11, check in your Settings to see. Then you can decide how to proceed. If you have a 32-bit app that needs to be updated and you’re in need of assistance, you know who to call.

As with any new OS release, it’s important to check your own iOS app thoroughly to ensure all features are working as intended. (Tip: use this article to help guide your testing and make sure you’re covering all the bases.) It is not uncommon to find small (or even large!) features here and there that didn’t fare as well as others in the upgrade. Providing bug fixes and sending a new release out to the App Store is always a welcomed solution to your users.

What are you most excited about with iOS 11? Let us know in the comments below!


Case study for vitaflo health app and website development

Today we’re sharing an overview of the Xively platform. Xively is an IoT platform that utilizes the MQTT protocol (Message Queuing Telemetry Transport) to allow devices to communicate in a lightweight and efficient manner. For instance, one might use Xively to connect a network of temperature sensors in a factory. There are a plethora of tutorials and documentation on the Xively site, but today we’ll focus on an overview of the core concepts.

As mentioned, Xively utilizes the MQTT protocol, which uses the publish-subscribe pattern to allow devices to communicate with each other. Devices are represented in the Xively platform as “reflections,” which consist of fields that store device state. Devices in Xively have the default properties listed here, four default custom fields (deviceVersion, location, name, and purchaseDate) and additional custom fields that you define. You can create device templates, devices, users and groups using the Xively web app or using the Xively HTTP API.

The Xively MQTT broker handles communications, allowing devices to publish updates to device state and subscribe to be notified of changes in device state. Devices connect to this broker with device credentials to publish and subscribe. The four default topics for each device in Xively are _set/fields, _updates/fields, _rejected, and _log. The full topic names are set up using the following template:


Publish to the _set/fields topic on a device to change the device reflection. Your message should be in JSON format, with a “state” field in an enclosing JSON object like so:

Subscribe to the _updates/fields topic on a device to receive changes in its reflection. Upon subscribing, you will receive all of the device state in the state JSON object in a message on _updates/fields. After that, changes in state will send only the changed fields in the state JSON object.

Subscribe to the _rejected topic to be notified when an attempted update to the device’s reflection fails.

To connect to the Xively broker, use the Xively device id you would like the connecting client to identify as (there needs to be an existing device in the Xively platform with that ID) as your username and your clientId and use the password for the device in the Xively platform (needs to be generated) as the password. The client will also need the Xively account id to construct topic names. The Xively HTTP API isn’t the focus of this article, but administrative tasks like creating new devices and generating device credentials (as you might do when registering a new device) can be done using that API, which is documented here.

We’re currently in the process of working on a client project that utilizes the Xively platform. We’d love to hear from you if you’ve worked with Xively before! What has your experience been? And if you’re a client looking for support with your IoT solution, be sure to contact us today!

At Oak City Labs, potential clients often ask if we write apps using React Native. Why not? Isn’t that the fastest way to market — write one app for both iOS and Android? That’s the crux of React Native’s pitch. Don’t spend time writing two apps when you can write a single React Native app instead. As CTO of a mobile dev shop, I should be able to answer that, so I’ve started doing some research on what it takes to be a React Native developer. How does React Native compare to Swift/Java development in terms of efficiency, stability and maintainability? I’ll walk through some of the things I’ve found.

Just a note before we dive in: this article addresses the idea of writing apps for iOS and Android in JavaScript, focusing on Facebook’s React Native implementation, not to be confused with the reactive programming model, which may be a compelling alternative to the traditional declarative programming style.  Reactive programming is a topic definitely worth following.  


How many tools does a developer need to build an app? As an iOS developer, I live in Xcode, provided by Apple and designed to build apps for the Apple platforms. Well over 95% of my development time is spent in Xcode. Apple also provides Instruments, a suite of testing tools to examine memory, CPU, etc in your app. Occasionally, I use Instruments to track down a particularly difficult bug. That’s it — Xcode and a little bit of Instruments.

The situation for Android is even a little easier. Android developers use Android Studio, a tool provided by Google with the sole purpose of creating Android Apps. Features like memory analysis and CPU monitoring are built in, so there’s really just one hammer in the toolbox. Android developers live in Android Studio.

Now onto React Native. It’s hard to find data on the amount of shared code in React Native apps, but conversations like this one suggest it can be 80% or 90%. That’s still a significant amount of platform specific code. Let’s assume we’re building an average app that has at least 15% platform specific code.

React Native developers have a bigger hill to climb just to get started. According to their instructions, here’s the list of software to install to build a cross platform app.

  • Homebrew — A package manager that makes it easier open source tools on your Mac
  • Watchman — A utility from Facebook to watch the filesystem for changes and run commands in response to those changes
  • Node — A javascript runtime built on Chrome’s V8 JavaScript engine, often used for server-side JavaScript
  • NPM — Part of Node, this is another package manager for managing JavaScript components
  • react-native-cli — Command line interface for for interacting with the React Native environment
  • Xcode — Necessary for various iOS tools
  • Android Studio — Necessary for various Android tools

In this article, Tony Mann suggests you’ll need these other tools as well.

  • Flow — A static type checker for JavaScript
  • Chrome Debugger — Chrome’s JavaScript debugger which can attach to your React Native application
  • Babel — A JavaScript to Javascript compiler

Now you’ve got everything you need to build a React Native app… except a text editor, so find one of those too.

So here’s the rundown for setup requirements

Platform Number of Tools Required
iOS 2
Android 1
React Native 10+


Right out of the gate, the bar is set relatively high for a React Native developer to get up and running. If this were a one-time penalty, it would be easy to write off. One day lost to setup on a six-month project isn’t significant, but this represents a whole dependency tree. Any update in one component can have a cascade effect that forces upgrading other components. Maintaining this whole setup now becomes overhead that the React Native developer must deal with. This kind of yak shaving can regularly consume a day of developer time.

Writing Code

I’m an iOS developer, so I’ll address the writing of code as a discussion of Swift vs JavaScript. For the sake of brevity, let’s assume Java (or Kotlin) developers make similar arguments.

JavaScript is not a nice language. It’s stone aged tech compared to Swift. Ariel Elkin does a fantastic job in this article walking through the many technical shortfalls of the language. Some of the highlights include

  • Weak typing
  • Lack of optionals
  • Lack of functions signatures

Issues like weak typing and lack of optionals are specific issues from Objective-C that Swift was designed to solve. In my experience, we always struggled with nil pointer exceptions in Objective-C. A rogue nil was the root cause of the vast majority of crashes in our applications. These have all but disappeared with Swift. A whole class of very common crashes has been fixed by using a language that simply doesn’t allow it. The rare nil pointer crash now usually has to do with interacting with legacy Objective-C.

Strong typing, optionals, and other features of Swift let me quickly write expressive, memory safe code that won’t crash. The compiler makes sure of that. As Elkin points out, these crashes happen frequently with React Native. JavaScript for app development is a step (or leap?) backward technically. If our goal is efficient developers, we should empower them with the best tools available.

Testing is an integral part of our app development process at Oak City Labs. One of the best ways to encourage developers to embrace testing is making it as painless as possible. With React Native, developers get another stack of dependencies to maintain just to get the unit testing framework running. In this article, Carlo Francisco goes over the testing stack they use at Refinery29 to unit test their React Native code. It’s based on Jest and Calabash / Cucumber. Jest is a JavaScript unit testing frame. Calabash and Cucumber are used together for application level acceptance testing. Calabash and Cucumber (and any customizations) are written in Ruby. The actual Cucumber tests cases are written in another language called Gherkin, one of those terrible languages for non-developers which are still too difficult for non-developers and too weird and restrictive for developers.

It’s great that there are testing mechanisms for React Native, but in order to accomplish real testing, we’ve got to add another few rooms on to the house of cards we’ve built so far. Not only do we add more 3rd party JavaScript frameworks, but we can also tack on extra languages — Ruby and Gherkin — in order to implement application level testing.

Compare this to iOS development in Xcode, which provides XCTest for unit testing and XCUITest for application testing, all written in Swift. Likewise, Android developers have JUnit and Espresso for unit testing and application testing respectively.

Stability is definitely a casualty here, mostly because of the limitations of JavaScript. React Native also loses ground on maintainability as testing tools require more third party components be placed in our growing dependency tree. I worry about efficiency too since testing now requires a React Native developer to know even more languages.

Debugging Code

Finally, once the code is written and running, there’s always debugging to do. According to React Native’s documentation, there’s no one stop shop for React Native debugging. There’s an in-app developer menu that opens the door to turn on/off some debug features and provide an onboard inspector. Using the Chrome browser’s remote debug feature seems to be the most powerful way to connect to the React Native app and view internals. There’s also a standalone version of the React Dev Tools to use when you can’t connect with Chrome’s debugger. And finally, there are the native debuggers in Xcode and Android Studio when you need to debug pieces of native code.

Debugging apps written in the native language is much more straightforward. To debug a Swift app in iOS, run it from Xcode and debug. For an Android app, run it from the Android studio and debug. It’s such an integrated part of the development cycle with the native tools, it’s easy to take it for granted.

With no one definitive debugging environment, I worry about a React Native developer’s ability to efficiently track down a bug. I assume one would start debugging in one of the JavaScript console tools, but then you might have to jump to a native tool. As context switching goes up, efficiency goes down.

Tool Quality

I’d also like to comment on the tool quality. Much of React Native’s tool chain, react-native, npm, etc, is executed at the command line. While some developers will praise the hard core grit of the command line, (“Real developers type, not click!!”), I find that it increases the entry-level barrier for new developers and generally causes friction for developers at any level. Trying to remember the flags for subcommands of the react command line tool isn’t going to help ship an app faster. Compare that to a button or menu item in a more robust tool like Xcode or Android Studio. The cognitive load added by a bunch of command line tools is just another stone weighing down the React Native developer and causing efficiency to sink.

Adding It All Up

At the end of the day, the React Native developer needs quite a big toolbox to fit all their tools in. Here’s the list:

  • Homebrew
  • Node
  • Watchman
  • NPM
  • react-native-cli
  • Flow
  • Chrome-Debugger
  • Babel
  • Xcode
  • Android Studio
  • Standalone React Dev Tools
  • Jest
  • Calabash
  • Cucumber

In order to use all these effectively, the React Native developer also needs to have a working knowledge of these programming languages:

  • JavaScript
  • Swift/Objective-C (iOS native components)
  • Kotlin/Java (Android native components)
  • Ruby (Cucumber testing)
  • Gherkin (Cucumber testing)

The single platform iOS developer needs Xcode (and maybe Instruments) to write, test and debug applications in Swift. Likewise, the Android developer needs Android Studio to write, test and debug apps in Java and/or Kotlin.

For a shop that has experienced Swift/Java developers, it’s very clear to me that there is zero reason to switch to the React Native development stack. We’re concerned about efficiency, stability and maintainability. The enormous number of tools required for React Native along with the piecemeal nature of programming environment are going to tank the efficiency of an React Native developer. Even the world’s best JavaScript developer is going to face an uphill battle on this unlevel playing field. JavaScript as a language is the biggest barrier to stability. JavaScript, by itself, is a deal breaker for us. Maintainability is another worry with so many dependencies from so many sources and keeping it all playing well together. (Not to mention dependency on Facebook’s ongoing support after the incident.)

I believe in using the right tool for the right job. Writing mobile apps in Swift/Java is the quickest, most friction free path to shipping apps to customers. I can understand how React Native appeals to web developers, offering to turn their JavaScript experience into mobile apps, but there is no free lunch. It may work in the end, but JavaScript (plus a lot of frameworks) can’t match apps written in the native toolsets when it comes to quickly and efficiently shipping a high quality, maintainable native app.

Oak City Labs is thrilled to announce the launch of CurEat’s Android app to the Google Play store this month! CurEat, a restaurant discovery tool, is the vision of entrepreneur Steve Mangano. We are honored to have partnered with Mangano to also develop both the CurEat iOS app and cloud server, which launched earlier this year.

The CurEat team will celebrate the launch, along with the introduction of their new CurEat Experience Program, this Friday, September 1 from 6-9 pm in Raleigh at the offices of Google Fiber. The Oak City Labs team will be there and we hope you’ll join too! More information can be found here.

Want to know more about this project? Download the CurEat case study below and we’ll serve up all the details!

CurEat is available in both the Apple App Store and Google Play Store now!