In our consultancy, we’ve decided to specialise in a few technologies which we believe are the best tool for their respective jobs. Or will be in the future:
No- and low- code
These are a higher level of abstraction, for apps that fit within their constraints. 80% of development is accidental complexity: details that you shouldn’t have to worry about. One sign of accidental complexity is businesspeople asking why it’s taking so long.
For the frontend, we prefer Vue, since it has less complexity than React and especially Angular. Vue was designed by an engineer who worked on Angular and took just the good bits from Angular to create Vue. Vue is therefore more productive to work in, for small teams like ours, and to build MVPs quickly. On the other hand, Angular and React were designed for Google’s and Facebook’s scale, respectively. We don’t have 20 frontend engineers on our team. We’re not Google, so we shouldn’t cargo-cult them.
The downside to Vue is fewer engineers available who know it, but that’s offset by its ease of learning. Ramp-up is a factor that should be given less weightage, since it’s only a one-time cost. If we’re very productive after paying the one-time cost, it’s worth it.
Why not Angular
Of Vue, React and Angular, Angular is the easiest to dismiss. It’s on the decline compared to React:
Technologies move in cycles: A new technology is built, takes off, becomes the default option, and then slowly declines. Betting on a technology like Angular that’s at best stagnant makes no sense unless there are countervailing factors.
Angular is also even more complex than React (which itself is more complex than Vue).
Finally, only 58% of Angular developers would use it again, while 74% of Vue and React developers would .
For these reasons, Angular is worse than Vue or React.
Mobile: Flutter (or PWA)
The first decision to make is whether to build a progressive web app. We should in the following cases:
- Desktop is a first-class platform. It’s not a mobile-only service.
- It’s important to cater to users on mobile who don’t want to install an app, at least not yet. Every company has an app, but that doesn’t mean users are willing to install it, particularly for infrequently used apps or transactional services (like car repair). If that’s a critical factor for the app we’re building, we need a PWA.
- We already have a desktop app whose code we want to reuse to build the mobile app.
- We’re okay with a slightly worse user experience than hybrid apps, and instead want some other benefits, like time to market, lesser overhead of planning and running one project instead of two, cross-platform consistency, and cost .
Hybrid vs Native:
Assuming we’re not going with a PWA, we then need to decide whether to go with native apps written in Swift and Kotlin.
Hybrid app frameworks like Flutter or React Native take you from 0 to 90. Pure native apps built in Swift or Java/Kotlin take you from 90 to 100. If you’re not already at 90, it’s premature optimisation to choose pure native apps. For most startups, reaching product-market fit, understanding users, building something users want, breaking even, etc are the more immediate problems.
And going from 90 to 100 costs a lot more. This is no different from any other market where, as performance increases, cost increases even faster. If you want to buy a car that can reach 300km/hr, it doesn’t cost twice as much as one that can reach 150km/hr. It costs ten times as much.
There are a few exceptions where pure native is called for:
- You work closely with the hardware, like Futurecam, or you require the maximum performance, like processing 1GB/s locally, as Futurecam does.
- You don’t mind spending hundreds of thousands of dollars a year staffing up an iOS team, and hundreds of thousands of dollars staffing up an Android team, instead of just one.
- You have 100 million users.
- Getting the last bit of responsiveness and UX fidelity is more important than the speed of iteration.
Flutter vs React Native:
We prefer Flutter. Why Flutter?
75% of Flutter developers would use it again, while only 62% of React Native developers.
One major startup moved from (among other technologies) React Native to Flutter. So did another early-stage startup I was advising; the founder said that Flutter is more solid structurally and faster to develop for.
I read that with React Native, half the time you’re amazed at how productive it is, while the remaining half the time, you’re fighting with the framework. Facebook doesn’t care about bugs that don’t affect them, and have even locked a bug on the bug tracker where too many people were requesting a fix. That’s not a responsible attitude from the maintainer of important infrastructure that you depend on.
Flutter has better documentation. It also has more built-in widgets.
React Native has some advantages as well:
- If you also use React, you can share knowledge and/or code. But we don’t use React, so this reason in favor of React Native doesn’t apply.
- It has a bigger community.
- React Native has more APIs that work with the hardware, and over time, more building blocks like SQLite that are available to native apps are being plumbed through to React Native.
In my opinion, the cons of React Native don’t outweigh its pros, so we’ll go with Flutter.
… so that we can spend time delivering business value rather than reinventing the wheel.
If we need backend logic, it can be in the form of Cloud Functions, which is FaaS / serverless.
This architecture is appropriate when you have lots of small and independent pieces of business logic that don’t interact with each other. For example, one of our clients has a cloud function to send the user an email when he uninstalls our app. This function doesn’t interact with the rest of the backend logic. FaaS works well for this kind of broad and shallow backend architecture, where you may have dozens or hundreds of independent functions. By contrast, if you have a narrow and deep architecture, with complex pipelines, machine learning, etc, FaaS would not be the right fit, in which case we’d use Rails .
Our General Approach
The above are general recommendations. For a particular client, the right choice may be different, depending on their situation.
We always recommend what’s best for the client, not what we want to develop expertise in. And we’re always transparent. For example, yesterday I was telling a lead, “We can either build an iOS app in Swift, which will take a month, or use Flutter, which will take two months, since we need to ramp up on Flutter. The advantage with Flutter is that you’ll get an Android app. But if we build in Swift, we won’t be able to reuse its code to build an Android app later.” She asked me, “By not investing now in cross-platform, we might end up investing more later… Which would you recommend?” I replied, “Flutter.” This is how we’re transparent about tradeoffs.
Clients can always override our choices, because they are the ones paying, at the end of the day. I clearly explain the tradeoffs, like “This may take twice the time”. Once the client understands and accepts the tradeoffs, and takes responsibility for the outcome, any choice is fine with us.
 This number — the percentage of developers who would use it again among those who used it once — is more important than the raw number of developers. Technology is not majority-driven like voting. Better to use a technology with a 100K happy developers than one with 200K unhappy ones.
 If we want to be in the app stores, that’s not an argument against PWAs: we can build a PWA and use a wrapper like Cordova to put it in the stores.
 Why Rails and not something else? Rails is still more productive than Nodejs. It’s quicker to set up.
We also don’t want to wrestle with NPM and incompatible API changes.
Django is a less productive version of Rails that’s suited to bigger teams. Django doesn’t use convention over configuration and so makes you write more code.
We also want an all-in-one framework like Rails or Django in preference to Flask or Node. We don’t want to investigate say three libraries for authentication, understand their pros and cons, pick one, spend significant time implementing it, find that it doesn’t work well with some other library we chose, and start all over again. I want to buy a car, not an engine, wheels and seats and assemble them myself.
72% of Node developers would use it again, while only 62% of Django developers would, and only 57% of Rails developers.