Catalin Ciubotaru avatar

When to use NativeScript? Learn from my mistakes.

Intro 📖

Set up the scene

I work at SnappCar. A peer to peer car sharing company for the Netherlands 🇳🇱. Our mission is to remove a bunch of cars from the streets. We are achieving this by having a platform that allows car owners to rent out their cars, and allowing users without a car to find one on their street when needed, without going through a car rental agency 🚗.

It’s quite a small company, having only 6 developers running a full BackEnd with Node and .NET, an Angular Web client, a Swift iOS Client and a Kotlin Android client.

Yes, you counted ok, that’s a lot of technology for 6 developers 👩‍💻.

The Problem

So, too much technology is a problem. We realized that in an ideal world, we should be able to move faster. When we want to introduce a new feature, we shouldn’t have to build it 3 times, with 3 different technologies. Also, when we want to expand our developer team, we can expand in a +1 manner, not a +3 people at a time. This makes everything quite expensive 💸.

The investigation 🔎

With this information, we thought that there might be an opportunity into unifying the clients under one technology. Translation: use a hybrid technology to write code once, and deliver 3 clients.

We looked in Ionic, NativeScript, React Native and Flutter.

If the title didn’t give it away, we went with NativeScript, but here are the highlights why the other ones were not considered a viable option:

  • Ionic was too “web”. It was difficult to create the feel of a native experience. We value that quite a lot at SnappCar.
  • React Native was ok, but it would have meant we can’t reuse the existing code from our Angular client. Something that was a big bonus with NativeScript
  • Flutter felt like a too young of a technology. A lot of promise, but seemed too early to bet on it. It was an inchoate technology.

The initial journey

We started working on our new NativeScript Client. Our Swift and Kotlin developers picked up Angular quite fast, so within a few months we were actually shipping (internally) features into our new NativeScript app. What a frabjous start! 🤩

We were surprised by how smooth it integrated with Angular, and how easy it was to reuse most of the already existing code. We already had “2 clients” for WEB: the BrowserClient and the ServerClient. This is because of Angular Universal, but I digress. Long story short, we had a really good start.

Two things of note:

  1. If you want decent performance, your whole app needs to use ChangeDetection.OnPush. This was ok for us since the WEB client does that already(most components at least)
  2. You had to go out of your way to make sure you use as few DOMNode as possible. This also for performance reasons. The way to achieve this was basically to have your components work in a “directive” way. This is what I mean 👇️

GridLayout is a Component provided by NativeScript. If you want to have a component that shows all the cars, in Angular you would do something like this:

@Component(
selector: 'app-cars',
template: '<GridLayout><Text *ngFor='let car of cars' value='car'></Text></GridLayout>'
);
export class CarsComponent {}

This is fine, but at render time, this will generate 2 nodes:

<app-cars>
<GridLayout>
...
</GridLayout>
<app-cars>

So, the more components you use on a screen, the more nodes you introduce. Mobile phones don’t like this.

The solution was something like this:

@Component(
selector: 'GridLayout[cars]',
template: '<GridLayout><Text *ngFor='let car of cars' value='car'></Text></GridLayout>'
);
export class CarsComponent {}

Only the selector changed. Not a big change, but when you use it like this, it does not generate the extra app-cars node:

<GridLayout cars></GridLayout>

So, every time you use a custom component, you save 1 DOMNode. This is good ✅.

One year later 🗓️

We were way behind schedule, having delivered more or less half of the product when we should have been done by now. We were wrong. Main reasons why we were wrong are

  1. Our product is way more complicated than we thought
  2. Exceptions ‼️. A LOT of exceptions.

First point being pretty straight forward, you live you learn 📚.

The second point though became a pain. What I mean by exception is that quite often

  • things were not working like specified in the Docs,
  • or there were no docs,
  • or we had to update and the update completely revamped the API,
  • or, there were memory leaks in the NativeScript implementation of a component, which required us to implement our own TypeScript wrapper over some native API.

We were lucky that we had the Swift and Kotlin knowledge in house, but man did it become tedious. Every week, there was a new exception that we needed to write our own implementation for.

Debugging experience was also spotty. Sometimes you would have to install everything all over again to get it to work.

It started feeling like we were going deeper and deeper into a bog. The further we got, the slower we moved, and we weren't even trying to reach the acme of mobile apps. We weren’t even done, and our passion for Software Development was slowly fading away.

The turning point

After a couple of really poor sprints, we thought that maybe we should re-assess our decision to go with NativeScript. A very painful decision. 😥

With careful thinking and analysis, we realized that we should kill the project. Sunk cost and all that, it was better late than never. It was not a great feeling. Throwing away your hard work it’s not fun. I can talk more about this in a different post if people are interested. You did feel like a failure to some degree. But hey, that’s how you grow.

MAJOR learning here: when you do something like this, setup some check points for your team. Moments in time when you re-evaluate, ask the difficult questions, and not end up like us, doing this only 1 year later.

So much money and time could have been saved.

What’s next

For SnappCar, we went back to the idea that to deliver the best experience on all platforms, you unfortunately have to use their native languages, if your product is complex enough. Again, IF your product is complex enough. This means CRUD applications, ToDo apps, Movie Lists apps are perfectly fine with a Hybrid technology.

Who is NativeScript for 🤔

I don’t want to revile NativeScript. It does have its purpose and I strongly believe that it can be a very useful tool. The problem is, figuring out when to use it and when not to.

I also think that this applies to all hybrid technologies. There are limitations and exceptions that you’ll encounter if your use-case is complex enough. And sometimes, sometimes it’s too many of them to justify the cost. Make sure you check the community of the project, the maturity of it and how is the growth in terms of npm installs for example. Make sure the app size still meets your requirements, since these technologies make your app quite large. You’ll have to find the balance for yourself.

I just hope this long wall of text will help you make an informed decision.

Want more?

If you want to know more about this, or something doesn't make any sense, please let me know.

Also, if you have questions, you know where to find me… On the internet!

Be kind to each other! 🧡

Over and out

My Twitter avatar
Catalin Ciubotaru 🚀

I tried #NativeScript at work and here's my story. Learn from my mistakes and properly assess what technology will work for you https://catalincodes.com/posts/when-to-use-nativescript #HybridTechnologies #MobileDevelopment

Dec 1, 2022
36 people are talking about this

Wanna read more?

Updates delivered to your inbox!

A periodic update about my life, recent blog posts, how-tos, and discoveries.

No spam - unsubscribe at any time!