Developing mobile digital key applications with ClojureScript

See how we use ClojureScript, React Native via Krell, and Storybook to manage complexity and improve workflow efficiency.

The video above by Michelle Lim (a fellow developer at Vouch.io) shows how we develop our mobile products using ClojureScript. Our interactive workflow combining simulator and on-device development allows for a higher level of conversational software development than the "hot-reloading" feature found in standard React Native, Flutter, or SwiftUI. Read on as I explain the software development philosophy behind the video.

Developing digital products for the real world is complex.

Like the faint rustling of a hidden predator, complexity lurks threateningly, awaiting a chance to drag any project back into the shadows. Too often in software and hardware development, complexity isn't given its due, and the results can be disastrous. The first step to counter the threat of complexity is recognizing and acknowledging it as part of any problem worth solving. Once the fundamental complexity is accepted, we can't eliminate it, but we can manage it.

At Vouch, one of the leading problems we face in building innovative digital car keys that run on those remarkable little computers we all carry is that the platforms driving these devices are not simple things. Each person's little computer is different from the next. Regardless, we need to deliver the same seamless experience to every user each time they approach and interact with their vehicle.

While we can build our application twice, mirroring the inherent complexities of a diverse ecosystem of platforms and devices in our product development will likely lead to inconsistencies. How will we know the experience will be the same? Will the devices implement the same security model? How will product changes be synchronized between two or more application projects?. Already we're being dragged into the shadows.

Solving the issue of complexity when developing mobile products.

To solve this problem, we use React Native through a custom tool we developed called Krell to build our mobile applications. Using Krell, we can write the core of our application once, making only minor changes for platform differences. It doesn't remove the complexity - but it makes it far more manageable. Our team still needs to understand the details of iOS and Android, but this only comes into play at essential checkpoints rather than in a constant stream - camera usage, biometric prompts, continuous integration, etc. Primary features of our product, the seamless interaction with the vehicle, and the sharing of keys remain identical regardless of the specific nuances of the device it runs on.

React Native by itself can only address the platform complexity, so what about the complexity inherent in UI projects? This complexity isn't the same as the previous example. It's self-inflicted. This complexity arises from a broken mainstream practice of coupling the development of components and business logic. Separating these two things isn't about developing reusable components but is instead about eliminating the fuel source that feeds the complexity fire.

To separate the two, we use Storybook.js to develop all of our components in total isolation from business logic. We no longer find ourselves dragged into the shadows because we're preventing coupling from the outset. Software projects have deadlines and, even experienced developers can introduce seemingly innocent coupling under pressure. Storybook.js keeps us from shooting ourselves in the foot while being extremely productive and fun to use.

With Storybook.js, our developers write all UI components as simple functions in JavaScript. Each view and its subsequent components can then be tested and verified in isolation on iOS and Android simulators and devices. Outside of React and React-like frameworks, we've found Storybook.js to be one of the most powerful tools for managing complexity in our UI software projects.

That leaves us with the business logic. We write all the business logic that ties our functional UI components together in ClojureScript. With our UI components developed in isolation from the business logic, we can shrink our applications to only what's essential. The business logic is only 1500 lines of code - a single developer can manage this or even manage multiple application projects. Other developers can jump in and learn how to make a change in thirty minutes, and a single developer can now fire up a customized application for a potential new client in only a day. By separating our components from the business logic, we're not only preventing coupling but improving efficiency too.

Building custom tooling helps us to focus on building better products.

So, what about Krell? Well, we wouldn't have arrived at Krell without first recognizing and acknowledging these complexities, but now, Krell is the wind in our sails. Two members of our core product team, Heather Haylett and Michelle Lim, are JavaScript developers with little to no experience with ClojureScript. Yet, together, they built the first iteration of our Vouch Key product in only two weeks when our initial estimate was four to six weeks. We already believed that with Krell, we could do it in record time, but Heather and Michelle said, "hold our coffees," and exceeded all expectations.

We find that our team structure and productivity reflect the complexity of the software we use. By identifying and resolving the complexities in our workflows, we can focus on doing the same for our products.

To riff on a famous Steve Jobs quote:

People think design is how it looks, but design is how we work.

About Krell

Krell is our open-source standalone, low configuration ClojureScript tool for React Native that extends the standard ClojureScript compiler to make developing React Native applications simpler.

Krell on GitHub →