I'm just wrapping up an evening of mild celebration. After two weeks of heads-down development in a totally new programming language, a port of my product Skate Dice has emerged. There were laughs, a few frustrations, plenty of simulator woes, and a surprising explosion of development acceleration to cap it all off.
In January when I started this, I really thought it was going to be harder than it was. And if the beginning of the project were any gauge of its longterm viability, I would have forecast the ship date some time this summer. Yet here we are, nearing the middle of March, with a finished project that only took a few of the spare hours I had on some of my less busy weeks.
Lesson learned. I need to be a little more optimistic.
All of this new experience comes off the heels of finishing my first React Native app for a beloved client of mine. That's two new languages and frameworks in the span of a handful of months.
And so it would seem that at this very moment, I might be poised to offer some sort of unique insight into the current state of affairs of mobile development.
For me, the choice to go purely native on my own apps was rooted in a desire to turn this mysterious black box called 'Android' into something more familiar, to slay the beast and confidently walk into meetings (just kidding I work remotely 😉) with the swagger of someone who has seen the sort of work it takes to support a fully cross-platform product.
After all, the original Skate Dice app is fully native iOS, so it would have been weird to rebuild it in React Native or some other framework. Why not go all native and see what happens? Experimentation is how we gain knowledge.
Kotlin and Swift have many things in common, so most of my learning time wasn't spent on the new language. Sure, I frequently Googled things like, "how to do delegation in Kotlin" or "implicitly unwrapped optional Kotlin," but I'd always end up at the one page summary of Kotlin's syntax and that would be enough. Not too much was all that new.
Nope, where I really struggled was just getting a single custom view to render to the screen in exactly the way I wanted it to. I had no idea what a ConstraintLayout was or how Android resources work, so I poked and prodded for a few hours until I finally got to my first self-contained View component that could be reused throughout the codebase.
That was the first major turning point in the project. After that, I was able to build more view components nested inside of other layouts. I could hook them up to code too, giving me all of the frontend tools I'd need to make the Android version of my apps just as beautiful (and functional) as they are on iOS.
Not once did I feel 'deprived' of some favorite tool I use in iOS development. Granted, the Android Studio IDE's visual layout editor isn't the most intuitive. I had to abandon the notion of doing my layout visually, choosing to go 100% XML instead.
And don't get me started on the rather shoddy simulation options available to Android developers. The Android simulators run so slowly on my absurdly fast MacBook Pro that I had to leave animations to the very end of the project, once I received my Samsung Galaxy S6 test device.
By the way, if you are starting Android development, I would highly recommend buying a used Android device off of Amazon or Ebay. It really makes the experience far more pleasant. I spent a few weeks thinking my app was running slowly, only to be blown away by my app's smooth performance on the Galaxy S6. If anything, it's a mood-booster.
What really surprised me is just how much of the Swift code from my iOS project could be directly translated to Kotlin. Many people look at this as a critical downfall of the fully native approach. You've gotta maintain two codebases etc.
And while I can certainly relate to the annoyance of making a change in one place and then having to make that same change in some other place, it's not like the kind of duplication you get from poor abstraction.
You maintain two versions of a file and only two. One version would be nicer, but we aren't talking about the kind of 10x difference you get from using for loops instead of rolling out 100s and 100s of iterations.
Most of the work on this project was rather mindless, and that's actually a good thing. If you want to put in a big day of work, you can't always be working on the most cognitively demanding stuff. You need some fairly mindless copying to give your mind a rest. We all cook and clean and wash the dishes. Porting code is like that.
I was surprised by the huge development acceleration toward the end, and what really fueled that acceleration was the existing knowledge I was able to transfer directly from iOS to Android. Since I had already solved most of the core problems of the app, I simply needed to translate that knowledge to a different language. It was easy.
I think most people look at the prospect of doing separate iOS and Android apps as a 2x effort. I would argue it's more of a 1.5x-1.66x sort of thing. Knowledge, in whatever language you've chosen to represent it, is still knowledge. It transfers, and it speeds up development in a dramatic way.
You won't see it at first, but then you'll be surprised when it all starts coming together very quickly.
I've used react native on an iOS app before, and I still have yet to render a full opinion. To me, there's some kind of balance being struck. You save time in some places while losing it in others.
React Native Time Savers:
- Hot reloading lets you rapidly test user interface code
- React-y-ness makes state management much easier
React Native Time Wasters:
- Fighting the build system when integrating certain third-party frameworks
- Lack of type safety makes debugging more of a challenge
- Having to work through a layer of indirection, which gives you less control over the product. Some layouts and components are harder to build as a result.
In any case, the real perception I want to take on is the notion that a web-based tool or something like React Native will take a project that seems to be a 2x effort and magically transform it into a 1.25x effort.
If you go fully native, the project is more like a 1.66x effort, not 2x. You're still winning if you can shave .16x off of that using cross-platform tools, but I would argue that many of those tools also have you making other compromises because you have less direct control over the product.
Maybe that's okay for your situation. Maybe it's not.
Regardless of the tools you use, you still have to support multiple screen sizes and device orientations. The real project killer might not be your decision to use a cross-platform technology (or not). It might be something as banal as deciding to support the landscape orientation (or not).
I should reiterate that this my shootin-off-the-hip understanding given the projects I've recently completed and not an official scientific investigation into the matter. Observations to the contrary are more than welcome.
If there's one big reason the Android project always takes less time, it's this. By the time you've decided to support your app on Android, you've already crossed a major milestone. You've figured out how to make money on the thing.
By that point in your project's natural progression, you should have some understanding of what your customers do and don't value. You'll know which features are loved and which ones get the cold shoulder.
This is truly wonderful news because it means you can cut features on the Android version. I did this with Skate Dice, sticking to the core features my users love. I believe that's a big reason why the Android version was more of a .66x effort and not a full 1x kind of thing.
Now that my first Android app is complete, I no longer have a dark mysterious cloud over my head, wondering what it takes to support a product on two platforms. As it turns out, it's really not that bad. Sure, it's a little bit of mindless hard work, but it's probably less than you think it's going to be.
If you are on the fence about porting your semi-successful iOS app, I'd say do it! The learning experience and sense of accomplishment are worth the slight annoyance you will feel from watching the simulator grind to a crawl. I feel more confident than ever.