Using Kotlin for ODK Android apps

Guys can we continue the android development in kotlin. IMHO Because once the project size gets big enough it will be a trouble to convert the entire code base to kotlin.

Why would we want to convert the entire code base to Kotlin? What are the pros? The cons? What impact will it have on attracting contributors? On stability? On maintaining the codebase?

I think Java is okay. I don't see any reason to convert it to kotlin. If later on we need to optimize the performances we can use JNI(java native interface) to use C/C++ .

I was thinking about enabling Kotlin in order to allow using both but converting everything to Kotlin?

1 Like

Most of the android project are now written in kotlin and google also recommends the same. I feel i we can have kotlin support for android development it might be helpful in attracting more contributers from the community.
As for converting the entire code base to kotlin i was just mentioning it. we don't need to do now. As of now it will good if we support kotlin also

Might there be a good ‘boundary’ upon which to determine what might be/not be a good candidate for porting to Kotlin initially? Eg (new?) question/control specific UI widgets first, then perhaps form navigation/lifecycle management, then finally core javaRosa type stuff? Just wondering if there could be a way to intelligently stage such a code transition (having faced similar issues wrt Objectice-C / Swift...)

1 Like

kotlin reduces a lot of boiler plate codes. for eg. you don't need the reference the UI widgets in the java code which reduces a lot of variable in the activity code. another advantage i could see by using kotlin in our project is by using kotlin-coroutines or asynchronous task(which i believe to be good boundary as skunkworks-bat mostly deals Firebase networking code and also using room for storing local data instead of SQLIte helper i believe to be a good choice and kotlin helps a lot in using room) , right now we are using AsyncTask for that Asynchronous code and in google I/O 2018 they recommended us to move to coroutines. The https://github.com/opendatakit/skunkworks-bat project is only in the beginning stage So i thought i would be the best time to use use move from support library to AndroidX and introduce kotlin in the project

The reason i recommended this approach is because in my team we have just started using kotlin for android development and everyone loves it. and we are slowly porting the entire the code base from java to kotlin and now the code base has both java and kotlin code. regarding the time needed to implement the proposal in the case of https://github.com/opendatakit/skunkworks-bat is if we have a single person working on converting the support library to androidx, moving to room from SQLite Helper and shifting the code to kotlin i believe it would only take 2-3 weeks

In your experience have you seen anything to suggest what might lend itself better/ worse to porting first? At least in mine, I’ve found porting ‘low’ level custom code - stuff that often doesn’t follow an overall framework (eg javaRosa) takes a bit more care to switch languages than, say, UI code that often follows a similar pattern. I say all that having zilch experience in Kotlin... but if you could offer some knowledgeable recommendations on perhaps what lends itself better, that might help guide any such a transition.

ok i got it.Actually i am working in a online movie booking app(JusTickets). when we ported the code to kotlin we faced few problems.
1.The first problem was with Dependency Injection (Dagger 2) . I guess one of the problem was with using lateinit keyword in kotlin code. we faced with few build time errors. it was only a minor change as we were able to correct it with help of error messages.
2. another case is few Unit tests and java fields were broken due of NPE(Null Pointer exception) in kotlin
3.a Third party lib(in our case one of payment gateway lib) was creating a lot of problems. So we left that part untouched for now.

as For the strategy we followed we were using mvvm architecture so we started from the entity layer and moved higher in the hierarchy and most of the migration can be easily done with java to kotlin tool in android studio our work was mostly to lookout for errors in generated code and correct it.

I know my answer is lacking all the details you were expecting. I just recently joined the company so i am not totally aware of all the problems the team faced while migrating :sweat_smile: .Sorry for my lack of knowledge (i am still learning). i would really appreciate any feedback regarding this proposal

1 Like

To follow up on this with new information that has since come up. Google is moving towards Kotlin-first Android as they announced in early May 2019. I don't know that there is an urgent need to change but definitely something to keep in mind.

My experience with Kotlin is that it is definitely less verbose and a lot of Android developers enjoy working in it, so in that way it may help maintainability and in attracting developers. Java isn't going anywhere any time soon per Google "There may be valid reasons for you to still be using the C++ and Java programming languages and that’s totally fine. These are not going away"

1 Like

Thanks for chiming in, all!

It's true that Kotlin has addressed a lot of Java's most notorious warts and that it would certainly be nice to leverage the improvements it brings to the table.

Are there any downsides to a mixed-language project other than having to get used to multiple languages? That is, are there complicated bindings that need to be added or anything like that?

@seadowg, I bet you have Thoughts.

I do! I'm guessing @LN has noticed from my not so subtle "well in Kotlin..."s during our discussions.

For context on where I'm coming from on this: I've been working in Kotlin since before it's 1.0 release and have been using it in production across Android and web (mostly Spring) since the beginning of 2016. I've converted several codebases from Java to Kotlin including one I'd consider to be a "larger" Android app on the scale of Collect. My standard answer to any dedicated team working on Android about whether they should switch to Kotlin would be "hell yes". However...

TLDR

Ultimately I think this is a pretty hard decision to make due to the hit it could have on potential contributors. In my mind, the best way to do it would be a focused effort to avoid the codebase existing in a midway state for too long. I also think it would be best to wait see how Google's adoption of Kotlin evolves and matures - we're still not yet at a point where we're not able to use SDK features (other than some nicer APIs) in Java. That could change in the next couple of years though.

There are a lot of good points here so I thought it might be nice to summarize with some of my own thoughts in response to @yanokwa questions:

What are the pros?

  • Immutable references: In Kotlin we have val and var keywords to denote our references. As vals are immutable Kotlin codebases often end up like the "everything is final" dreamland that we wish we had in Java.

  • Null safety: Kotlin like a lot of more "modern" statically typed languages has nullable and non nullable types:

    val string1: String? = null // this is fine
    val string2: String = null // does not compile
    val string3: String = string1 ?: "default" // `string3` == "default"
    val string4: Int? = string1?.length // `string4` == null
    

    While initially it seems the biggest advantage here is just having more succinct ways to deal with null in my mind the largest advantage is us all being forced to ask ourselves whether values will be null or not when writing code.

  • Data classes: Kotlin's data classes give us a far simpler way of representing the data in our app than a POJO as they come with a built in deep equality and a copy method (that works like a builder). Also they are just really simple:

    data class Dog(val name: String)
    
  • Cleaner functional operations: Using Lambdas in Kotlin is much easier that in Java as they work directly on types you want them to such as List or Map. This means no stream() or collect() muddling up the code you're trying to write. As an aside, this only works because of:

  • Extension functions: In Kotlin we can add functions to existing objects that operate on their public members. This is basically a nice sugar over creating a static method in Java but it aids discoverability (as you get autocomplete on them) which is really helpful in large codebases. Here's an example:

    fun Context.getIntAttribute(resId: Int): Int {
        TypedValue outValue = new TypedValue();
        this.getTheme().resolveAttribute(resId, outValue, true);
        return outValue.data;
    }
    
    val color = context.getIntAttribute(R.attr.colorOnPrimary)
    

    These are really useful in existing frameworks with slow moving APIs (looking at you Android). The Android team has started using these as a way of quickly adding small helpers to the SDK without effecting the underlying objects.

  • Java 6 compilation: Kotlin compiles to Java 6 which let's us stop worrying about at which API level a Java feature was introduced to Android. This was a huge initial advantage to Kotlin as it could do Lambdas on Android but with everyone's minimum creeping up (and the SDK team getting better at keeping up with Java) that's admittedly becoming less of a problem.

  • Less boilerplate: This was brought up by @udhay24 and it's certainly true. For me this really comes down to Kotlin's std lib doing a good job of using all the features above to cut down on the amount of sheer code you have to write.

  • SDK team favoritism: this was mentioned by @russbiggs_hotosm. While the SDK team still claims they'll be supporting Java for a long time to come it does seem like Kotlin is their favorite new tool which could lead to Java apps losing out on newer APIs. Conspiracy theorists might also bring up that the ongoing Oracle vs Google mega lawsuit could be a strong motivator for Kotlin on Android - this is massive speculation though (but fun).

There are a lot of other nice features of Kotlin, including many interesting changes to how you can express generics, that its team does a good job of illustrating here.

The cons?

  • Converting: If you want to use Koltin in an existing app you have to admit that there is going to be a lot of (probably slow) work involved in converting existing code. This will often leave the code in a middle ground stage for a rather long time. You don't have to of course but I don't think any of us would argue that having two languages in a code base long term would be that nice - moving in and out of files in the same system that have different languages is always a bit of a hit to your brain.

  • Differing styles: Kotlin lets you write some really nice functional code: you have lambdas, you can pattern match, there is autocasting of types etc. This however can lead to codebases having an odd jumble of different styles. People, like myself, who have worked in languages like Scala and Haskell can use Kotlin to write some pretty beautiful, maniacal code where as other people can use it to write highly performant, smart, boring procedural code. I've definitely had a hard time in larger Kotlin codebases making the code style feel consistent.

  • SDK team favoritism: Yeah I think this is also a problem. The SDK team is excited about Kotlin and they are moving really fast with it. This could leave other things behind. An example: At I/O 2018 (as @udhay24 brings up) Google were happily encouraging people to use coroutines (Kotlin's implementation of the coroutine pattern) instead of AsyncTask. At the time testing code with coroutines wasn't something that worked well: there were limited helpers and it really didn't play well with Robolectric - let's not even begin to think about the problems it could have posed for Espresso. They've solved some of these problems in the last year but it's an example of the team leaving their own testing frameworks behind. I think it's important when thinking about adopting big new features of the Kotlin ecosystem that Google still has a lot of old code to support.

  • Tooling and compiler maturity: Although JetBrains is behind Kotlin so this is always getting, IntelliJ/Studio still have a nicer Java experience and the compiler is still slower usually.

What impact will it have on attracting contributors?

This is an interesting one. As far as I'm aware, Kotlin's presence is still very focused around Android and most web/back-end developers in the Java world are using Java 8+. We've already got a large blocker on Collect for gaining contributions due to Android being a more niche world and I'd worry switching to Kotlin would up the bar for entry for Java developers coming from outside Android.

There is potentially an argument to be made that using Kotlin brings in Kotlin developers but, in my experience, most of that is made up of people who have probably written Java before and probably will again at some point. This might change as Kotlin attracts more developers from the Ruby, JS etc world however.

On stability?

Generally I've found Kotlin Android code to be stabler due to us catching lifecycle related null pointers. Other than that, I don't think I'd say that Kotlin is inherently more or less stable than Java. If we're talking about stability, I'd never prioritize shifting to Kotlin over reworking/increasing test coverage.

On maintaining the codebase?

Personally I've found it easier to work in Kotlin codebases due to all the nice features it has and the extra discipline it forces on developers. At the same time, any language can be used to write unmaintainable code!

4 Likes

I'm not sure we'd be look to JNI in the future but even so there's no reason that Kotlin would prevent us from doing that: https://developer.android.com/training/articles/perf-jni.

I don't know Kotlin well but since
Kotlin might be used along with Java
and
Kotlin multiplatform supports sharing code between Android and iOS

it would be possible to use at least Javarosa (but also some business logic from ODK Collect) to build ODK Collect for iOS. Am I right @seadowg?
if so it might be a big opportunity for us or other devs interested in something like that.

it would be possible to use at least Javarosa (but also some business logic from ODK Collect) to build ODK Collect for iOS. Am I right @seadowg?

It's possible but a lot of work I'd imagine! JavaRosa would have to completely re-written in Kotlin though. Also, JavaRosa wouldn't be able to use any Java libraries - multiplatform requires you to use Kotlin multiplatform libs as everything is going to need to compile to the target platform. I don't really know enough about JavaRosa to understand how big a hit that would be :confused:

I thought that since we can use Java classes in Kotlin we could also use Javarosa (in Java) without converting.

We can use Java classes from Kotlin when we're targeting the JVM from the Kotlin compiler as both the Kotlin and Java code gets compiled to and run as JVM bytcode. The Java compiler is still used here - the Kotlin compiler doesn't deal with any of the Java.

If we were to target JavaScript with the Kotlin compiler we couldn't use any Java code as the Kotlin would be compiled to Javascript and any Java in our project would still be compiled to JVM bytecode. We could of course use Javascript dependencies and also interop with our own JavaScript code.

So if we wanted to build an iOS Collect app with shared code we'd rewrite JavaRosa in Kotlin (and only use multiplatform libraries) and then have it compile to JVM bytecode for Java/Android and (I'm guessing) LLVM bitcode for iOS. Then our Android app (which could be in Kotlin or Java) and our iOS app (with could be in Kotlin or Swift) could depend on it.

There's a blog post that goes through a big example of this here.

As much as it would be a lot of work I do think it's a really interesting idea as few apps actually have a large piece of core "domain logic" like JavaRosa. Whenever I see those multiplatform examples I'm pretty confident most apps would end up with 5 or 6 data structures shared and nothing else but would take on all the complexity of the multiplatform dependency graph and build system. For us, it might be worth it down the line!

3 Likes

This PR has introduced some Kotlin to Collect. The motivation here was to add Coroutines (in an abstracted way) so that we can use them to replace the now deprecated AsyncTask.

I could see using Kotlin within submodules like this to be a way forward for using it more in Collect without randomly sprinkling it over the codebase.

1 Like