Netflix Android and iOS Studio Apps now powered by Kotlin Multiplatform
netflixtechblog.com
netflixtechblog.com
For me it makes perfect sense to e.g create an internal API client using this. You use platform specific frameworks for making the actual HTTP requests[1], but can write all higher level business logic in Kotlin and expose that. Adding a new REST route or change data validation would be done only once and be in sync on all platforms.
But I'm guessing that you have to pretty knowledgeable about the underlying platforms to know how (and if it's even possible) to create a good abstraction above the platform code. For something like audio/video playback or BLE, I'm guessing that there might be enough differences between Android and iOS that an abstraction that fit both is really unwieldy. And even if you create something resonable today, one of the platforms might introduce new features which destroys your abstraction.
[1]: I noticed that they even have some kind of built-in HTTP client abstraction: https://kotlinlang.org/docs/mobile/use-ktor-for-networking.h...
It goes one step further, you can have platform-neutral code to parse the API returns into Kotlin models.
https://blog.jetbrains.com/kotlin/2020/10/kotlinx-serializat...
A lot of business logic is shared in the domain layer on each platform client (and possibly on the server), and I think re-use of that is/will be Kotlin's main selling point.
Add SQLDelight for shared data access code on clients, and you can cover a lot of ground with one codebase.
source: have worked on apps you likely use every day
If you can have your apps share their data models between both android and iOS you can have the apps share the HTTP request/response handling and their DB code etc and then it truly becomes just a dumb client.
YouTube/Netflix also have complex video encoding/playback code that can be written in c++ and shared between clients.
Most social media apps liek FB/Insta/Snapchat have complex camera and photo handling code as well as async messaging code. Which if you have things like retries or photo compression/encryption you'd probably want to share between clients. etc..
But put logic aside being able to use the same programing language across platform eliminate a lot of the context switching.
As someone who has had to maintain apps across web, iOS and Android, the answer to that is most definitely no.
Search for "offline first" to see how people are exploring architectures like this.
Edit: source: I worked on a product bundling chat functionality as a plug in.
In fairness, I think this is not so relevant for apps which are consumption first, but if there's any kind of collaboration, or even just writing from the client, you want to show an optimistic (at least; some systems make the client state canonical) representation regardless of sync status.
But, of course, there are plenty apps that prefer to do things locally, for so many reasons - if Spotify downloads songs, it does so locally. Or a note taking app such as Evernote needs to capture and compress whatever was drawn on the screen. Not to mention games!
If you think about more than CRUD apps, you’ll see that there are plenty things to be run on the device which are independent of UI.
- Data model operations on local copy of data: For some use cases you can't just send everything to the server all the time, instead you want a local representation which is periodically synced with the server
- Logging / monitoring: Expose a single logging / monitoring API which can be shared across platforms
- Input validation / rules engine: Consider implementing a syntax highlighter, you wouldn't want to do that on the backend. Even simple form validation might sometimes be preferable to do client side, calling the multiplatform validate(data_model) and getting per-field validation back would allow for a lot of logic re-use.
- Do work that could be done on the server: Because of a lot of factors, like privacy or cost you might want to do work that could be done on the server. I.e, calling some sensitive third party API (banking?) where you have to transform requests/responses. Or maybe computation on large sets of data (video compression?) which otherwise would need to be sent to the backend.
- Interact with devices only locally accessible: IoT/bluetooth things
Server authoratative validation is security; frontend validation is UX
At what size and level of expertise/experience does it make sense to consider it?
What are the prerequisite knowledge/skills/abilities that a two pizza team needs to keep the learning curve practical?
Just my personal experience, but if you have a good Android/Java "two-pizza team", you probably already have the makings of a good Kotlin team, given the appropriate time for folks to pick it up.
So the platform teams need to have shared prior knowledge of how to build with the same architectural patterns, and they need to be sold on the possibility and merits of using those same patterns and coordinating on their plans of implementation.
For a two pizza team, I'd recommend not overthinking it and to just give it a try if it makes sense for you or not if it doesn't. Hard to tell; it all depends on your requirements and how good your people are.
Aside from Kotlin I also think Rust with C FFI or WASM are good potential avenues to explore here. In the WASM case generic business logic can be written in Rust and compiled to WASM, platform capabilities such as networking/GPS etc can be exposed to the WASM VM via functions provided by the host. Further, with WASM it would also be possible to run the same code across web, native clients, and the server.
Reimplementing platform UI
Poor reimplementaions of platform UI, such as navigation, that almost always looks subtley wrong or doesn't "feel" right in terms of interactivity. This also often lead to shipping a single platform's UI convention on every platform, for example Material on iOS or iOS patterns and conventions on Android.
Poor UX
An app's UI is more than just how it looks, just as important is how it feels, and if it fits in and feels at home as an app on the platform. Often cross platform solutions generate apps that have slightly "off" UX, such as sluggish interactivity(RN has this this issue), missing gestures(such as backswipe). In general many small cuts that deterioriate the user experience
Focus only on the visual
The visual representation of an app is only one part of the UI as mentioned above, an obvious other example is accessibility which is often lacking with cross platform tech, especially on iOS. I wrote a whole blog post about how Flutter Web fails[0] in this regard yesterday.
Binary size
By necessity cross platform solutions reinvent a lot of what the platform already provides which leads to larger binaries(performance is a feature).
Performance
Ionic for example, runs in a non-JIT(on iOS) enabled webview so can never match the performance of native. React Native runs a JS enging(again no JIT on iOS) which demands more from the device and uses more battery than native in my experience(performance is a feature).
In general, cross platform UI works by targetting a lowest common denominator of the platforms which naturally results in a worse experience.
0: https://hugotunius.se/2020/10/31/flutter-web-a-fractal-of-ba...
Ionic is not Flutter. Flutter has to ship a ton of code to reimplement things Ionic can use right from the browser. Size increase is marginal with Ionic and Ionic can be used to build high lighthouse performance PWAs which Flutter Web cannot in its current state.
Ionic does use a JIT-ed webview. WKWebView is JIT'ed, but JavaScriptCore (which React Native uses) is not.
The rest of your points are subjective and we find Ionic apps, when designed well like any other app, have great performance and user ratings.
Also nowadays the dominant computation platform of the world is mobile phones, with most of the world being Android and many with money being iOS. Desktop UIs like the web with custom screen reader & extensions & custom css mod and such are not the P0 priority. I would also imagine it's not the majority of people with these accessibility needs using it either. Desktops are the world of the office worker, middle aged person who's calcified into desktops or other power user types.
It would be hooking into iOS & Android standardized accessibility APIs. I'd imagine it executes far better there, because non-selectable text in UI elements are pretty much platform standard for mobile & desktop apps.
Furthermore in that light I'm guessing that flutter web & desktop are also P2 projects to the P1 flutter mobile projects, and android / material design is P0.
For this reason, I’m hesitant to make use of a shared codebase for the networking parts of an app. By using your own stack, you’re throwing out a ton of device-specific optimizations and risk things like keeping the user’s cell antenna activated for longer than needed or not gracefully handling transitions between connection types.
For most mobile apps, I think the only part that really makes sense to share between platforms are those to do with pure logic and data manipulation, since there’s not as much benefit from doing that full native, and any processing optimizations are typically surfaced in a way that’s accessible to lower level languages (and thus third party stuff like Kotlin Multiplatform).
> Almost 50% of the production code in our Android and iOS apps is decoupled from the underlying platform.
An added bonus of this approach is that it forces you to have a clear separation between your user interface code, and your business logic. A lot of mobile (and front end) apps out there have no architecture, putting API calls, state management and UI right next to each other in the same modules. Our approach forces you to keep UI code just focused on UI, while keeping all logic somewhere else, where it can isolated and as a benefit much more easily unit tested.
You would be surprised just how large of a share of your codebase can be moved into platform agnostic code if you have a solid architecture. Our UIs are "dumb" and render themselves from view models which have exactly the data needed to render the view. All the logic and state management to construct these view models can be written in the cross platform repo and shared across the Android and iOS apps. For example, to render a list, you will need to use the native UITableView or RecyclerView separately, but all the code that manages how many rows are in the list, the data each row needs, as well as updating the data when the list is reordered can be shared across platforms.
Some companies also use lots of ffi code generation tools.
If you're business logic needs these platform specific functionalities (which will definitely be the case as you've stated) then you can abstract out interfaces and let each platform handle them natively.
Kotlin multi platform as described here has no UI system, it’s a way of compiling Kotlin to binaries that are easily linked to both Android and iOS apps, with some bridging back and forth conversions into the native systems in each case. You’ll still need two separate code bases to call the common binary and handle UI.
Try spending one or two evenings with Flutter writing a simple app and build it for two or three platforms to see what the few issues are.
Once you have that setup you can then add a different platform "web/iOS". The base module would have setup certain contracts that new "platforms" would have to implement.
What you need to do is analyze your situation and make a decision on whether you have significant non-UX code which will be a bear to maintain long-term. Most people do not, so maintaining a platform-agnostic layer is unrealistic.
To help with this, let's look at an older example: Microsoft. In https://channel9.msdn.com/Events/CPP/C-PP-Con-2014/024-Micro... they describe how they are using C/C++ as the basis for their Office applications. Why? They have a load of legacy code that needs to be reused and they needed the exact behavior on all platforms. This code runs on the client and can't be moved off to the server-side which would be the preference when feasible.
Since iOS and Android can consume C/C++ code it makes sense to maintain as much of the application in C/C++ as possible for sharing while creating native apps which are as thin as reasonable. They can do iOS and Android specific things where it brings value, but centrally, they can decide if it should be something available across all platforms, or even architect it partly in C/C++, and partly in the native API for the mobile platform. This allows them to bring it quickly from Android to iOS in a future release.
Microsoft can easily afford to do everything described above. If we look at Netflix they are in a similar position, but don't have as much legacy C/C++ code. Kotlin MP feels like a nice alternative given Netflix's situation.
Do you feel like you are in a similar situation? Few developers are in this situation, but it's attractive to architecture astronauts. While somewhat unpleasant, duplicating functionality in native iOS and Android code bases might be the right thing for your apps now. If not, there are in-between options such as moving to Flutter for all your UI code and Dart becomes your main client language. You have to be able to live with any compromises (I'm more familiar with Xamarin which is an aging, but similar trade-off.) That seems like one of the better balances today with good momentum behind the platform and strong implementation.
Naturally it isn't on Google's and JetBrains interest to talk about them.
It sounds like this tool is used internally. Given that, was it not possible to issue tablets of a single platform to users instead? Or are users using their personal devices?
For starters good luck turning on / off features, handling UI state, and tying in the business logic to that state. And good luck mangling dependencies and build times with a new added Kotlin dependency :-)
I assume this has nothing todo with video as its on a phone, but does anyone in the TV business know what this app actually does or could do - time management/planning/todo/contacts/legal/safety guidelines repository etc?
That's how I wrote multiplatform code 7 years ago, using hidden webviews in the background.
Unfortunately, Android or iOS to this day have not supported JS (or really Node/V8) as a first-class citizen. The best approach is still just to use webview, which has a performance cost, amongst other complexities.
Time will tell if Kotlin Multiplatform is light enough and has the minimum number dependencies to warrant its inclusion in mainstream, high-traffic applications.
https://github.com/jsjeon is probably the most prolific one as I often see him in the commit history.
BTW which plugin are you working on?
I develop https://cursive-ide.com.
As a native Android dev, my arm-chair hypothesis is that currently both of those (kotlin, flutter) are targeting different developers and until either one starts including the other developers then I don't see any one winning over.
Kotlin - loved by native devs Flutter/Dart - web devs (previous experience with JS)
*I'm biased as a Native android dev but from my experience this is the case. Also Kotlin is really a great/fun(ctional)/expressive language
Also Kotlin Multiplatform and Flutter are very, very different use cases.
For anyone who isn't aware:
Kotlin Multiplatform lets you share business logic. Think "make a library that can be used on iOS and Android". You still need to write the UI and platform-specific plumbing separately for each.
Flutter includes the UI and can give you apps running on both platforms (and web and desktop, too!) with 100% shared code†.
†In practice, though, you may need to get your hands dirty with platform-native code for functionality not already covered by the plugin ecosystem, though that need diminishes over time.
To be honest, I’m kinda surprised they don’t just go Cordova, one platform for all.
It's usually pretty easy to tell Cordova apps from native apps. The quality is wildly different and they tend to "feel" wrong, even to users who aren't super technical.
I would never recommend that route unless you're on a shoestring (<$10k) budget.
Even then I'd recommend Flutter first.
I suppose it would be possible to make one that isn't bad, but that seems like more effort than just making a native app in the first place.
It seems weird to say Cordova being a poor experience is a myth and then to say Flutter will always be bad. Flutter is already lightyears ahead of Cordova.
I don't know anyone shipping Capacitor projects, so can't really compare that.
as someone who was tasked with porting a cordova app to native (android), i can second this opinion (as a dev and user)
edit: sorry, i mistook "capacitor" or "cordova" (^_^;)
https://blog.jetbrains.com/kotlin/2020/07/kotlin-native-memo...
Why is this not a problem for Netflix?
[^1] https://github.com/apple/swift/blob/main/docs/Android.md
Good to know it’s possible though. Just maybe with more tooling...
On the other hand, if you can lower Kotlin to native code, it may be more natural to interact with (of course, there are still these nonsense of Java's default UTF-16 string <-> Swift's native UTF-8 string conversion).
Interoperability between high level languages are just hard. I am skeptical of either way, but I can see how it is more appealing to go from Kotlin to Swift direction.
On the other hand, data modeling and high-level data transformation doesn't require all language features. It is possible to do such with a limited DSL that supports product / sum types, some filter / map / flatmap / zip, and boom, you now have your view models for UI rendering. As long as we've made up our mind on string UTF-16 / 8 or have some performant library to do lazy transformation on these. We can go a long way on standardize business logic cross iOS / Android platform.
In fact, in 10 years Google has never made available their internal tools that simplify JNI integration, leaving the community on their own to create our tools.