In 2020, CodeSignal added support for mobile assessments. This means that interviewers can ask candidates to build a mobile app using React Native or Android and even run it in an emulator, all from our unified IDE in the browser. Currently, we’re the only technical interview platform that provides this kind of realistic environment for mobile development. In this article, we’ll explain how our back-end and IDE teams built this feature, and describe some of the challenges we encountered along the way.
Requirements for mobile assessments
From the beginning, our goal was for our mobile assessments to reflect the typical development process for an app. Focusing on practical skills in a realistic interview environment tends to create the best outcomes for both candidates and hiring teams.
Mobile app development generally has a few consistent steps, supported either by a custom toolchain or an integrated environment like Android Studio or Xcode:
- There’s usually some basic template of starter code that includes the libraries and build files necessary to run the application.
- Next, the developer edits and adds files—for example, to design the data model or the UI elements.
- For testing and debugging, the developer builds the app and then either opens it directly on their mobile device or runs it in an emulator on their local machine.
When we started investigating how to support mobile assessments on CodeSignal, our infrastructure was already well-equipped to handle steps 1 and 2. CodeSignal’s IDE supports mobile development languages and frameworks like React, Java, Objective-C, and Swift, and you can easily create multi-file projects on our platform. When an interviewer is designing a task, they have complete control over customizing the starter code; they can also choose a jumping-off point from our task library.
But to be able to support mobile assessments, we needed two things:
- A way to build mobile apps in our back-end (ideally, this should also be fast)
- A way for interview participants to see the output of the code. In other words, we needed to add a mobile device emulator to our IDE—and like our IDE, it needed to work in the browser.
Supporting React Native development
As we explored how to meet our requirements for building React Native apps, we quickly ran into some obstacles. While React Native code can run anywhere, you still need to have a special environment to build React Native apps for each platform. For instance, iOS applications can only be built on machines running OSX. (Our build environment is based on Linux.) Additionally, building React apps can be very time-consuming—when testing this, we found it could take around 5 minutes to build a fully-featured React app in our back-end.
Our solution? Expo, an open-source platform for quickly building and iterating on React Native apps.
Building React Native apps with Expo
Expo’s tools were a great solution for our use case. Using the Expo SDK, you can send your code to Expo’s server and they will handle the entire building process for iOS, Android, and web, and return the standalone application. This can take a few minutes—but with Expo, you don’t actually have to build the app in order to start previewing it.
The Expo client, an app called Expo Go, is designed to make it fast and lightweight to test an Expo app. Expo Go is like a browser, in that it can render any Expo app just using the app URL. Expo Go is hooked up to the Expo SDK and can access most native libraries (with the exception of a few on-device things like Bluetooth). As a bonus, Expo will do live reload and hot reloading, meaning that if some code changes in the project, the updates will appear instantly in Expo Go. This is perfect for our interview scenario.
Expo Go would typically be installed on a physical device, but of course, that doesn’t work for our use case. Now that we had a way to quickly preview applications, we needed an emulator where we could run Expo Go. That way, the candidate and interviewer could both see the output of the React Native code right from CodeSignal’s IDE.
Running React Native apps in an emulator with Appetize
In search of a mobile device emulator that could work in the cloud, the best solution we found is Appetize, which provides a way to load an application into an iframe in the browser.
Appetize provides some useful parameters when running apps, so we can have Expo Go open immediately and go straight to the candidate’s application by deep linking into the Expo URL. Appetize also lets us specify the type of device to emulate. So we were able to build a toggle where we change out the app instance and device type whenever someone wants to switch between iOS and Android in an interview, letting them test out the app performance across both platforms. Here’s a gif that illustrates the Appetize emulator and the live reloading that we get with Expo:
Each interview participant has their own separate emulator and Expo Go app—so how do we keep them in sync? Well, the Expo clients are using the same application URL, so any changes to the app itself are instantly propagated to everyone. And when someone starts the emulator on their end and begins to interact with the UI, we have architecture designed to reflect those events back to all the other interview participants. (For more information, check out our blog post on how live collaborative editing works in CodeSignal’s IDE.)
Supporting native Android development
As we figured out a solution for React Native, we were working in parallel to support Android development.
Building Android apps with Gradle
The standard way to build Android apps is to use Gradle. We built support for this into our back-end; as a result, we need to include some extra files in the starter code for any Android mobile task, purely related to the build process (Android has a bit more machinery here than React Native).
Unfortunately, it can take around 1 minute to build an Android app with Gradle. Although this is not ideal, we decided that it was worth it to still enable native Android tasks, for a few reasons. First, we can do the initial build in the background without tying up the rest of the IDE. And second, we can really speed up the subsequent builds.
How did we do this? We recently updated our architecture to essentially spin up a separate virtual machine for each interview, enabling features like our terminal. Because we now have persistent sessions, we can cache the information used to build an Android APK. After the app has been built once, subsequent builds will happen much faster because Gradle only has to update the parts of the codebase that have changed.
Running Android apps in an emulator with Appetize
We’re using Appetize to run our Android apps, as well. The equivalent of Expo Go doesn’t exist for native Android apps, so we need to run the Android APK directly on Appetize. This isn’t much of an issue, except that there’s no way to dynamically update the APK when the candidate changes the code—we have to rebuild it.
The process works like this: The first time someone wants to run the code in the emulator, they click a button in our IDE, which builds the APK in our back-end and opens it in Appetize. Then, when the candidate changes something, they click “Run” again to view the update. We build a new APK (which happens much faster) and then we open that new app on Appetize.
As with any feature, we are continually looking at how we can improve our support for mobile development tasks. How can we make our build times faster for native Android? Can we scale with Appetize, or do we need to look for an alternative? These are questions we’re beginning to investigate.
Finally, let’s address the elephant in the room: What about supporting native iOS development? We had hoped to be able to support this right away, but unfortunately, building iOS apps can only happen on Apple’s operating system, mac OS—and our servers use Linux as an operating system. Cloud providers like AWS have recently begun to provide servers that run mac OS, so this is possible, but will require significant investigation and investment in architectural changes. Watch this space!
Our mission is to build great candidate experiences for every kind of technical interview. If you’re interested in working on full-stack projects like this one at a fast-growing startup, check out CodeSignal’s open roles.
Ruben Ashughyan is a software engineer who contributes to the IDE’s back-end infrastructure.
Hrayr Movsisyan is a software engineer focused on perfecting CodeSignal’s live interview platform.