KotlinConf 2019: Your Multiplatform Kaptain has Arrived by Ahmed El-Helw

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] hello everyone my name is Ahmed I'm an Android engineer at Karim and I want to talk to you about our experience with Kotlin multi-platform specifically so Karim for those who don't know is a ride hailing application specifically targeting the Middle East area and specifically I want to talk about our captain apps and our captains are the captain is what the term we use to refer to those people working on our platform to drop customers off from one point to another and as you can imagine captain app has many responsibilities some of which is trip management so where should the captain go who should he pick up metering so both distance and the time and the route traveled and keeping in sync with the backend but the key point here really is that this app directly impacts the livelihood of captains so captain's a lot of captains do this as a full-time job and they depend on it so if there if if the captain can't work they're not happy and of course that's not good for them because mistakes could negatively affect their earnings so to kind of start from the end as to where we are today with Calton multi-platform we have over 25,000 lines of shared code between iOS and Android that includes tests we've been in production on Android for a year and on iOS for seven months in series with both the iOS and Android captain apps about 30% of the captains are on iOS and the iOS team has five developers in the Android team has 11 developers but of course this is kind of the end of the story so I just kind of want to talk about how we got there and then kind of talk about some of the lessons and things that we learned along the way so initially Kadeem only had an android-only captain up and it was out sourced so the code was not very well written they didn't actually have a team that that actually maintained it so modifying the code was very difficult and there were constantly production issues captain's complaining that things are broken and we kind of have to figure out what went wrong and kind of fixed them and there was no even good automation scenario where we could actually rely on the fact that any changes we made had sufficient testing so that we know everything is good so learning from the mist from from kind of the experiences of others we knew that we couldn't just stop the world and rewrite we'd have to kind of do an in-place rewrite so we began rewriting some of the business logic in Kotlin while within the current app and we built using redux inspired mvi architecture and I'll come back to this a bit later and you know in the meanwhile we are supporting the existing code base but of course what you have to realize is that at this point in time when we started this there was a new team in place so there was a lot of fear of because we're you know we're new to the company we're trying to kind of change things but there's highly sensitive code not very many people know what should happen or what does happen or what works and what doesn't and there's no good documentation for a lot of this a lot of this stuff around the same time as we're rewriting iOS so business iOS came into the picture when business actually asked for an iOS app for captain's so initially what happened is they allocated one or two engineers to begin rewriting the Kotlin that we were writing the the cleaner Coughlin's version that we were writing in two Swift and this quickly became a problem so it was difficult to keep up with the changes that we were making both of us both the iOS devs and the Android devs inadvertently implemented bugs as you could expect and made assumptions that weren't very obvious and it was just very tedious in general around this time we propose to use Kotlin multi-platform and this was maybe late 2017 early 2018 so when we approached management about this they're both skeptical and you know excited about the possibilities of you know if this actually works but skeptical because of some of the other stories about some other companies that with different technologies that they've used and there were lots of unknowns especially on iOS keep in mind this was very early on so there was no company we could point to that same production used it and especially in such a critical environment and so the way that we ended up resolving this is kind of by by by having a risk mitigation strategy so we we sort of said like hey today in order to write this iOS app the iOS does unfortunately have to look at the Android code somehow because there's no good documentation anywhere for how this code should work so they're gonna look at the Android code anyway why not let's try this let's try shipping this multi-platform library if it works great if not this is just plain Coughlin's code with no Android dependencies we can just very easily migrate it to Swift they're very close to each other it's easy to do and so this sounded like a reasonable risk mitigation strategy at the time um so we began by building a multi-platform library and so we actually started by copying some of these Gradle modules that we had we were rewriting in the Android app into a new repository and and this library primarily consisted of primer of this library primarily consisted of common code so a lot of people in multi-platform a lot of the examples online show an Android app and an iOS app side-by-side living with the common code we actually didn't opt for that approach we took a different approach where we actually built a library so most of our library is just it's just a standalone library that's then imported by the iOS app and the Android app respectively so we worked with the iOS the developers to set up and test on iOS build and we continued migrating code into this library and in parallel we kind of you know extracted out an interface and gave it to the teams so that they could actually start in the Android case to rewrite some of the UI and in the iOS case to write the UI for the first time and eventually we launched right so now I kind of want to switch shift gears a bit and talk about some of the lessons that we learned along the way the first one is avoid Android driven development and please please excuse me because I'm putting on my Android developer hat this is my so I'm seeing it from this perspective so for Android developers it's it's very easy to convince an Android developer to adopt Kopplin multi-platform because it's essentially what we're doing every day anyway with very few differences and so usually when a lot of these efforts are actually brought up by Android developers and pushed forward by Android developers but being Android driven unintentionally can actually cause a bunch of problems and here are some of the problems we ran into we quickly noticed some chasms building between the iOS devs and the Android devs and for many reasons the first is distrust of non Swift by iOS devs and the way I like to think about this as an Android developer is the first time someone tells me hey how about you write this up and react native the expression on my face will answer more than my answer will so it's the same thing for them right understanding that it's native helped kind of like you know reduce some of these fears and ultimately once they saw it working in production then that kind of cemented their belief in it another problem we ran into was that we were inadvertently unintentionally working in a silo this caused problems because the iOS developers felt kind of like siloed out and unaware of what we're doing and to us we're like hey the the the the repo is open the PRS are open you could take a look but they felt siloed in addition if you notice early on when I said that we we I said specifically we copied code from the Android project into the multi-platform Lib and the reason for that was two things legacy code and the reliance on some libraries like Rx and at the time there was no reactive library there was and so we kind of we were trying to figure out how we were going to address these problems and so at the time we just kind of kept the fork which caused more problems because we'd update the local copy that lived inside of the Android repo first and then eventually it would take some time to merge to the actual suppose what was supposed to be the shared library that iOS team was using um and it was very frustrating for them because they'd be like hey we found this bug and we're like oh yeah we fixed that but um yeah we'll merge it now so it was frustrating for them so how did we kind of resolve some of these issues the first thing was kind of put better better procedures for communicating changes the first is any bigger change we asked the developers to write a very short document explaining like the architecture of this change send it to the other developers give them time to digest it and just schedule a meeting where people can challenge the idea and suggest better ideas and so on so forth the second one surprisingly got some pushback but in my opinion was one of the best things we actually did so typically our code review process has been two reviews and as an Android developer working when I had at a PR for the library I would just turn to my neighbor who was also an Android developer I'd be like hey can you review this um because it was easier thing to do so we put this policy we said hey one review per platform on the shared code and initially the iOS devs were kind of hesitant about this they're like hey I don't really Kotlin I don't know if I can actually review this code but eventually you know at the beginning one or two of them did and that actually inspired the rest of them too as well over time and the one or two that did first were the first to actually contribute to the library to fix bugs on their own or something like this as well um and then we did we had an explicit a change log with the explicit explicit version changes so this kind of made it easier to understand what changed between one version and another when when we updated code in the library a couple of things to keep in mind this might sound very obvious but iOS developers signed up to work on iOS and what I mean by this is you know there's there's there's a piece of this that we actually experienced this actually where we had one iOS developer who was helping us you know migrate some of this code into the shared library and after some time they're like hey I actually didn't sign up to work on Kotlin I want to work on Swift and on iOS site specifically so just kind of saying this to be mindful of the goals of the engineers working in the org and empower engineers to learn and grow any change in your wants to learn and grow in a different way and so you know that's kind of you know our job to help our colleagues and and managers job to help the people they're managing to kind of learn and grow but just kind of some things to keep in mind a couple of the lessons learned from this so develop develop developing a shared library needs a different mindset this is especially tricky when you're also the customer because essentially you're trying to wear two hats the I am the Android dev had and I'm the library dev had and at some point in time you'll mix it up and you wear the wrong hat you'll forget to switch the hats and this will cause a number of bad things like that code to that that you don't want in the library that will be in the library and things like this so ideal target is that to make your developers your primary customers and of course you facilitate iOS devs feeling ownership because especially initially it'll be very difficult for them to kind of they'll feel like they don't want to contribute or they're afraid to contribute and you kind of need to help them feel welcome to do so and encourage them when we talk about sharing code a couple of considerations and things there as well first what to share so what we're sharing today lots of business logic and rules so actually are all our critical business logic about the captain and how the captain transitions from one state to another it's essentially a state machine that we're sharing behind the under the hood and it's actually core logic and critical logic critical business logic that we're sharing also the troubleshooting and bug fixing so this was this was actually when you start to feel the fruits of your labor is when you know the iOS devs are the ones who find the bug and they find that the bug is in the library and they fix it and you get the fix as well for on the Android side which was which was awesome and tooling tooling is something we want to invest much more into but there's huge opportunities for sharing tooling as well once you're actually sharing some common code as well so some general sharing tips a lot of people ask you know what should we share and in my opinion the answer is it's tricky it depends but if you have to give an answer sure as much as possible but really the answer should be share whatever developers on both platforms are comfortable using and again going back to the analogy of react native so as an Android developer if I'm applying for a job and they say hey our Android app is a hundred percent react native that could impact my decision as to whether or not to work on this app or not so similarly if you say hey we're going to share you I are going to share everything it could also impact on iOS developers decision to work or not so sure what both both are comfortable sharing start with what you can agree on like the end and build trust from there and you know this always applies but study open source libraries and carefully decide whether or not it makes sense to implement this time or not because the reason I point this out specifically is because the great thing is there are lots of new open source libraries all the time that are being built and those those save a lot of time but initially some of them might not be very stable for example and so there's a there's a there's a risk factor involved so you have to decide how much risk is acceptable depending on each case by case scenario when we talk about code sharing we inadvertently talk about dependencies and there are two primary ways to share dependencies the first is expect actual we're in the Catlin multi-platform code you you have an expect class saying that you know the date has a current time and on Android side you implement it saying okay this just returns the current time in Millie's and on the iOS side you say ok this is the corresponding call in iOS which is time interval since 1970 so a couple of points about expect actual the iOS implementation must be in Kaplan and so for this is this is this might not be convenient in the sense that most likely the people doing the iOS implementation our iOS devs and so you're asking them to write the iOS logic in Kotlin whereas it's much easier for them to just write it in Swift the other the other consideration is the implementation sometimes because of the Interop with Objective C it might not even look like pure Coughlin that that you know Android devs for example are used to so due to things like allocations and memory scoping and things like that you know like some of the code ends up looking a little strange and so just some points to keep in mind the other approach is dependency injection and this is what we do very heavily so an example of this would be I have an interface in the Coughlin multi platform code with some message some methods they're defined on the Android side I am I just implement this interface and delegate to some repository and I can use dagger as usual and everything is as usual as normal and on the Android side so I'm just delegating to that repository to kind of get these results right and on the iOS side it's very very similar they are delegating to this booking configuration object to get this result and they're also implementing the same interface now when I actually want to use this in the Kotlin shared code I can use it something like this so I take the actual configuration object as a parameter to my class and I just call it exactly like I would expect to call it the only difference is that when I'm when I'm creating the sample command from the iOS side I'll just pass in the the implement in the iOS implementation of the class versus from the Android side I'll pass in the Android implementation shifting gears a bit to talk a bit about architectural considerations so first kind of suggestion I guess is limit the impact of changes on the SDK layer and we kind of learned this the hard way on on the Android side where the iOS side actually did a lot better because we were because of the fact we were actually moving classes out of the Android code into the shared library we actually we actually share for example moved some of the core booking data classes which are actually used all throughout the app end to end whereas the iOS side said you know what we'll create our own local one and we'll map between this one and and and the other one and you can imagine whenever we needed to actually change that data class you can imagine the headache it was on Android because it affected all the code and to end but on iOS it was much easier because there's just one mapping function you had the tweak and everything was same as normal right so ideally restrict usage of the library to a handful of classes and expose alternative interfaces to the rest of your code so that it makes it easier to adopt changes another point is consider whether or not sharing architectures between platforms makes sense so this is kind of a you know there multum there's a difference of opinion about this but some companies have had success in sharing the same exact architecture between iOS and Android and just it's a point of consideration of whether or not it makes sense for your company or not because inadvertently your library your shirt your multi-platform library could impact the architecture directly or indirectly and I kind of want to give an example of this so I mentioned earlier on that Android library we initially started with building at as MBI so when we think of mvi we think of a stream of states that is observed to that is subscribed upon and and when changes are observed some changes on the UI are made so first off how we actually did this in multi-platform so there's actually this neat method in the standard Lib delegates thought observable which essentially just called every time your setter is called it'll just call whatever is in the lambda and in this case this is just an interface on a booking state listener is just an interface which again in the same way that that that I showed earlier will just be implemented by iOS and Android so that they can handle anytime the state has changed in this case even if this multi-platform even if this this library method didn't exist you can do the same thing by just calling calling a method whenever the setter was called so on the Android side you would implement the listener for example creating the subject and on state changed emitting on next and you know exposing a stream by hiding the subject or whatnot one point I want to point out here something that we found very useful both on iOS and Android side is type aliasing so if you notice the class name is booking state listener but the interface name is CM II booking state listener and so what we did is we gave a name to all the the objects coming from the shared class we prefixed with CMU which stands for captain mobile engine and so we type alias did so even though the class name is actually the same but because of the type alias like it just it's cleaner to use this way we do we do this both on iOS and Android sides the iOS code again is very similar they create their own subject using our X whiffed and again emit on next whenever the method is called the function is called so so that's how we observe changes when when things change but how do we actually make changes so to make changes we just call methods on the library as you would expect it just makes changes so using an example you know if you were to open an app and request a ride what would happen is something called a booking offer is created and this booking offer is sent by the back end to the number of captains to a number of captains who are most ideal to accept your request and if a captain when the captain sees the offer they can choose to accept it and when they do one of two things can happen either it can be assigned to them or it can expire and expired really just means that either someone else got it another captain got it or you know maybe the customer cancelled and backed out for example so you can imagine on the Android side someone click the button to accept the offer and you're just calling this method on it on something in the shared code on booking offer accepted and you're subscribing somewhere to this observable of a booking States and you know looking for a change in for a change in the assignments and whenever something like this happens on the UI thread for example you do something whatever UI makes sense UI change makes sense and expiration the Iowa stuff's actually wanted to do it a bit differently so they didn't want to actually be subscribing one place for the you know assignment and somewhere else for the for the expiration so they kind of wanted to do it a bit differently and what they really wanted was they wanted a function called accept where they would give it the offer and it would return back a booking if it was assigned or would throw an exception otherwise and so they opted to write a layer on the Iowa side to kind of manage this so the way this kind of looks like I noticed a lot of code but I think it's not it's I think the important part is so they have a piece that's watching for changes of expiration and whenever such a such a change happens they just throw an exception and another change for watching assignments and whenever such a change happens they map the booking object from the library into the i/os booking object and then they create an observable where they first accept the offer and then they wait for the first thing to come back whether the assignment comes back or an exception is thrown and that's it and so they just returned a single booking so the reason for this example and kind of talking about this is just saying be intentional about the impact of the design decisions that that that are made inside of the architect platform library on iOS and Android you can imagine in a case where if the architecture on iOS was much much different the way that we structured the architecture on Android might have made it difficult for them to actually adopt it but because things were similar enough it was it was straightforward without actually changing the library to kind of adopt what both library site Swan tit to do shifting gears a bit and talking about platform differences so not everything is an allied is analogous between Android and iOS as you can imagine so on Android for example you can actually request a fused location or you can request GPS location for example and we're actually requesting both and doing different things with both of them but on iOS you just get a location from core location and you have no no control over where it's coming from for example so just something to keep in mind right so other things to consider is the fact that infrastructure or libraries may differ and these are things that we kind of take for granted or we took for granted at least so just the point of heads-up so for example on Android a lot of some of our jobs were we're using work manager and we kind of treated them as kind of fire-and-forget and we knew that if it failed it's gonna retry in the background silently and so on so forth using exponential back-off and whatnot but we didn't communicate this to the iOS devs because we're like they must be doing the same thing but they actually weren't because how would they know right we didn't tell them and so it just happened when they said hey how are you handling errors in this case we're like oh our work manager is doing that for us so just kind of something to keep in mind and actually one more point about this actually even other things like push notifications which are the same feature on like which are similar on both iOS and Android there's different capabilities of the platform that might be available to Android that are not available to us for example and vice versa in other areas so just something to keep in mind I want to show gears a bit and talk a little bit of a code organization so again I apologize Android developer hat on again so Gradle modules as from an Android world we know makes a very good basis of separating business logic and helping achieve kind of faster development and testing time less conflicts between developers on and less contention on the classes that are being changed and we can use something like the keyword the internal keyword to kind of encapsulate certain classes within a module but not expose them outside that module so Gradle modules are great but so what does this have to do with the iOS so an iOS the target is to have a single framework a single multi-platform framework and this is because of limited current limitation in multi-platform so building a single framework from a single module is very straightforward and even from a from a repository consisting of multiple modules Gradle modules it's also straightforward but when you actually have multiple repositories it because things become a bit tricky especially if you do what we did initially which is use sub modules because we're like we at the time we didn't really have another option so keep in mind this is before the the new cathlin multi-platform plug-in which I guess is not new anymore but so before this that's actually what we were doing so we had a sub module on you know the one library had a had a even though there was no code dependency between the two libraries there was the sub module dependency so that you could just build iOS framework at the end but with this with the new Gradle plugin it becomes very straightforward to have multiple repositories with multiple modules in each repository and so what happens is each of these Gradle modules will build an artifact this is very what we're used to on the Android side where you get jar files on Android from each module and you get Caleb's for iOS one per architecture and so then what you can do is you push them to artifactory or sauna type somewhere in maven where you can use them now once you have this now to build the iOS framework what you need is just a single Gradle file somewhere which is kind of like a monolithic Gradle file that's kind of pulling in all the dependencies needed and builds a final framework and you know a snippet of this kind of might might look like this you might notice that we're depending on comm Kadeem captain dependency 1.0 so the nice thing is first off it's versioned secondly i don't actually have the library code here III left the project 1 as an example but all of these all of these live in maven right so the other nice thing is changes to the to the shared code doesn't actually will cannot break iOS unless they change the version number so this is this is kind of a nice thing a couple of notes so this monolithic module I'm talking about has to have at least one source file in it even if that source file is empty and just declares an object or something because otherwise it won't build I think this will be fixed it sometime in the future classes are names faced with base name and objective-c so you might have noticed the base name that you can specify in the module this actually ends up just prefixing the different class names if it's not there it uses the Gradle modules name and in Swift classes are not named spaced so duplicate classes from different modules will have their names changed so why would you have duplicate classes from duplicate modules so the fact is then on Android we can have two classes called core but they live in different packages and that's completely fine on Android but on iOS there isn't there isn't this concept of packages and so consequently if you have two classes called core they conflict and so what multi-platform does is it renames the classes so you can actually use both of them so an objective-c so remember the base name prefix is the class name so you'll have like base core and base core underscore and in Swift you'll have core and core underscore so just something to be mindful of just be careful not to duplicate names because otherwise you're trying to use one of them but you're actually using the other one and which one and like the fact that it ends with an underscore might be a bit tricky so just something to keep in mind the other point is export is not transitive by default so if you export a dependency any dependencies of that dependency iOS will not be able to see so you can set this flag if you want it to be able to see those dependencies shifting gears a bit to talk about a couple of notes about building for iOS so some things are lost in translation so because of the fact that because of the fact that Interop is with objective-c instead of Swift a couple of things are lost in translations one of the things is default parameter values so both Swift and Kotlin have default parameter values which are really great but but not an objective-c so consequently something like the copy method it's there you can use it but you have to pass in all the parameters to it so it's a bit of a it's a bit of a hassle right now the other thing is generics so but things are getting better so imagine you have this class so this is just a node of any data type T and it could it has a value and it has an X node that's it so imagine I implement III I add this into my multi-platform library gets generated in in the in the header for the framework is this type ID and ideas really like any object essentially so it doesn't actually realize that it's generic so when you actually try to use this in Swift it says hey this is not a generic type you can't do this similarly you might think like hey maybe it's because of the tea maybe if I don't make it like maybe if I actually like tell it that like hey this will be a note of a car things will work the way I expected so but again in this case I expect value to be a car but the error is value of type any doesn't does it doesn't know that it thinks that it's it doesn't know what type it is right um she actually without explicitly casting it to a car but as I've caught Lin a Kotlin multiplatform 1.4 I caught the native 1.4 thanks to the work of the touch lab team they added a patch to a better objective-c generics so when you enable this compiler flag what happens is you essentially you can see that the ID got replaced with with T here which is kind of what we want but one kind of thing that we didn't expect is that it's marked as nullable because our initial field wasn't nullable so now the it works but it's a different error which is saying like hey this value type is nullable you have to unwrap it so you actually have to do this for it to work but essentially it's working the reason for this happens to be because of the Interop again because of the interrupts between Objective C and Swift so kevin has a really good blog post where he explains this in great detail I highly recommend checking it out if you're interested if you're interested but essentially the fix is to just set an upper bound on T to be any and if you do that then you get what you would expect so any weight value type T and then you know the second example works as expected as well where it understands that it's a car so debugging between Kotlin native and iOS is difficult touch lab again has a Xcode plugin that helps with this called Xcode Kotlin that you can check out and also like I guess as we heard in the keynote today hopefully there are some things to look forward to in the upcoming year symbolic ation is only there for debug builds so symbolic asian is important because that's how we know when a crash happens where it happened it sucks experimentally they're in for release built in 136 0 and also very recently the touch lab team released a library called crash kit iOS that actually makes it easy for when a crash happens you can actually identify also where in the call to encode the crash happens as a as opposed to just knowing that the crash came from the cufflink I want to talk a bit about multi-threading so co-routines are single threaded on iOS but not for long so there is an EAP version that supports multi multi-threaded coroutines and I think there are some apps pushed out that actually use this especially by touch lab but at the time we were building this so you know early 2018 there were other options like workers and so on but we opted to actually multi thread with delegation and interfaces so the way that this could look like or this looks like is for example I have this interface called the booking interactor and it has a function called handle booking which is just going to do some kind of network call for example and what we pass in is a call back and say hey when you're done just call me back give me an error if you have it or otherwise give me no in which case I know that it succeed succeeded then you can implement this on the Android side and on the iOS side you can implement it as well so you can see here that creating some kind of endpoint you can imagine services some kind of network service class that will take this request execute it and call the lambda on the correct thread to do whatever is inside the lambda which inside the lambda will just say hey what did an error happen is this result in error if is it failure if so we'll just create an error otherwise there's no error and we'll call the callback interestingly enough this code actually was crashing on 135 zero because of the fact that in multi-threading access to all mutable objects needs to be single threaded so kind of like the core role of multi-threading is that objects can either be immutable in which case you can share them across threads or they're mutable in which case only one thread can use them and so this includes object creation using the object and releasing the object all three of these have to happen on the same thread on the Kotlin native thread and what was happening the reason we had the crash there is because what was happening is even though we called the callback on the correct thread after this Swift was deallocating the lambda and our callbacks still existed there so I was trying to do like our callback as well but not on the same thread on a different thread and that was what's causing the crash so this was fixed in 136 but before it was fixed the other way that we that you could work around this was just knowing out the object before you return back from the call and then this way when Swift actually dialects the lambda it doesn't it doesn't do like your object as well and another way we could have fixed this probably but I guess we didn't realize at the time was to just freeze the lambda and we actually realized that but we didn't do it because we had one mutable variable and what we didn't realize at the time is that we could have just changed that mutable variable to an atomic reference which is available on both platforms and would have just solved the problem for us so things that we're thinking about it could even like we're thinking about now so our library tests are currently JVM only and the reason for that is we we use mocks heavily it doesn't a mock que doesn't support multi-platform yet though there's an issue there and so hopefully we can we can hope for that sometime in the future we should have used fakes probably but we didn't so so what more can we share besides business logic really the the thing I love about this point is the fact that the ideas of things that we should share now are more often than not coming from the iOS developers so because they're the ones that wrote the newest app they're feature set is less than the feature set available inside of the Android app so they're like hey we want to do this is this available we're like no only in the Android app they're like hey what if we just build it inside of the multi platform library and this really made me happy because like it shows that after some time even though there's a resistance initially when when they see it working they're sold on it and it just makes everybody more productive another point is how do we avoid inheriting technical debt so again because sometimes we end up migrating from let's say the Android feature into the shared library things end up there that should really shouldn't be there and they're really just there because Oh Android uses this thing but really if you think about it why is Android even using it nobody asked the question for so long and nobody really knows so how do we avoid kind of inheriting more technical debt when we're doing this kind of work I mentioned before common tooling so one of the interesting things that we wanted to do and we kind of did a little bit but we wanted to do more so I mentioned mvi we actually log in a very similar format so that in in production when a problem happens we can just kind of look at the log and understand exactly at which state transition things fail and you can imagine kind of if we if we actually are sharing tools we could actually write a tool very easily to replay exactly what a captain sees on a trip and not only just have to like scour through the logs to figure out what went wrong but we can actually visually see it if we actually invest more time into things like sharing common tools and finally multi-threaded coroutines so again you know this is going to be huge it's going to save us a lot of time so we're super excited about this so in summary avoid android driven development communication is key is it's very important give a sense of ownership especially to the iOS devs and encourage their participation treat your developers as customers as opposed to treating your the app that you're working on as a customer especially in the cases by the way the reason for the for the hole in an ideal world we would have a set of developers that are actually developing the app that are not working on Android and that are not working on iOS but we didn't have the resourcing to do this and so we had to take the resourcing from within the existing teams which is kind of why this ended up happening but if you're but so if you're in that position just make sure you treat your developers as customers architect for success share what both platforms agree on and then you can build from there limit the impact of the shared library on the code be aware that the architecture could potentially influence both platforms a couple of other lessons multi-platform can be as risky or not risky as you want and and this is kind of the key like a lot of people are like oh it's not ready yet I don't know but actually things like the the standard live are like rock solid and people are using them in production now and even for mission-critical apps and they work great now if you're trying to use multi-threaded co-routines in production now well chances are you'll find a bug it's still an EAP it's not even marked as stable yet so just keep in mind something to keep in mind but in general starts small and expand from there so build trust and you know with time this trust basically allows you to increase your impact invest in building and supporting open source libraries because now is the time like now is a it's a beautiful time because a lot of as more and more people are adopting Kotlin multi-platform and there's a huge opportunity to you know to build open source libraries and and and invest in them even if it's just reporting issues when we see them things like that it just kind of makes the ecosystem better one final summary and small by the way like we're hiring and we're doing a lot of cool projects so if you're interested come talk to me so I just wanted to summarize all of this in a rhyme so for engineers that Kadeem multi-platform was just a dream qapla multi-platform made it true and it can work for you too we share on Android on iOS our code is clean and not a mess business logic is what we share while showing our iOS devs that we care most of our code lives in common main to keep our dependencies nice insane dependencies implemented on the platform side we use dagger on Android with nothing to hide on swift we or we roll our own di I speak the truth and do not lie we build libraries and version them to updating a change log with whatever is new push them to a maven repo to use an add a tag with nothing to lose Caleb's are uploaded on iOS jars on Android without a mess the clients use them as you'd expect and best of all bugs that we detect bugs that we detect can be fixed on both platforms with ease saving us half the development fees with multi-platform coroutines coming soon the limits are really beyond the moon so if you haven't considered sharing code it's a good time to get into this thought mode that is all I have to say I hope you enjoyed this talk today thank you [Applause]
Info
Channel: JetBrainsTV
Views: 3,158
Rating: undefined out of 5
Keywords: JetBrains, software development, developer tools, programming, developer, kotlin, kotlinconf, kotlinconf 19, multiplatform, kaptain, careem platform, kotlin multiplatform, ios, sdk
Id: R61N5yJGhKI
Channel Id: undefined
Length: 40min 56sec (2456 seconds)
Published: Mon Dec 16 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.