A pattern for code sharing in Kotlin Multiplatform

In this article, Douglas Hoskins shows how the MVP pattern can be used to great effect when creating a robust, maintainable cross-platform app with Kotlin Multiplatform.

With Kotlin Multiplatform we can create a library of shared business logic and use it in our iOS and Android apps. It’s possible to use any class in that library, anywhere within our native code. Sounds powerful! 

But in reality, we need to be more organised.

We need a pattern for architecting our system which will:

  • clearly define the boundaries of our shared codebase
  • make the shared code more structured and easier to develop
  • make it easier for the entire development team to work with shared code
  • make the shared code easier to test

The MVP pattern works really well in Kotlin Multiplatform apps for maximum code sharing in a structured fashion. It lets us clearly define our interfaces to our shared library. This makes native implementation simpler, and makes testing a breeze.

In this blog we are going to see how to create a simple weather display screen in the MVP pattern.

Let’s get started!

The View

As we can see from the diagram, the Presenter and Models components of our pattern live in the shared Kotlin code, while the Views are native.

But in order for the pattern to work on shared code, the Views need to be the same on both platforms. So let’s start by creating an interface for our native View.

This interface encapsulates anything the presenter would want to send to the view. Don’t forget that the shared logic should be doing all of the heavy lifting. The views should be “dumb”: data passed into the view should be ready to display to the user without further processing.

The next step is to implement that view on the iOS and Android native sides.

Let’s look at iOS first. Kotlin Native maps Kotlin interfaces to protocols which can be accessed from Swift or Objective-C.

The iOS view is in place, and we’re making use of a Kotlin interface from Swift. Very nice! The Android side is more predictable:

Nothing out of the ordinary here, we declare our Activity in Kotlin and implement the View interface in the usual manner. Life with Kotlin Multiplatform is very easy for Android developers!

Our native views are in place. We can see that specifying our views as Kotlin interfaces works really well because:

  • The only points of interaction between shared and native code are those defined in the contract
  • iOS and Android developers can easily see what they need to do to interact with shared code (by implementing the functions we have defined)
  • Changing our view interface will cause a compilation error on our native views. We can be sure that the native side is up-to-date with the shared code at all times

Now let’s see how to implement a Presenter that can be used by our native views.

The Presenter

We’ve specified an interface for our View already, so now let’s do the same for our Presenter. 

This completes our WeatherContract we defined earlier, with a specification of both the View and the Presenter. It’s pretty simple: we have functions to associate and dissociate the view with the presenter, and another function to refresh the weather (possibly to be triggered by a refresh button or a Pull-to-Refresh mechanism).

Specifying an interface for the presenter will help us immensely when it comes to mocking it for unit testing.

For now, let’s create a real implementation of the presenter. 

The presenter’s job here is to accept actions performed by the user and ensure the correct app functionality happens as a result. In this case we have abstracted location and weather retrieval into dependencies that are provided to the presenter in the constructor.

This will help us with testing as we’ll see later. But for now we’ve provided default implementations of them, giving us a concrete presenter which we can instantiate from our native Views and hook up to our UI.

Let’s look at iOS first.

We instantiate our presenter in viewDidLoad, and pass it a reference to the view. Additionally, we call presenter.dropView() in our dealloc method — this is the presenter’s chance to do any cleanup required when the user navigates away from the screen. 

However, in order for this method to get called, we need to ensure the presenter is storing a weak reference to our view, not a strong reference.

If we don’t do this, then we will have a memory leak. The presenter’s strong reference to the view will prevent the view from being deallocd.

Both iOS and Android support weak references, but Kotlin Multiplatform has no built-in notion of them. We need to add it ourselves. Fortunately this is very easy!

First of all we declare a WeakReference in shared code:

The expect keyword here tells us that the implementation of this class will be provided separately for each target platform.

We then need to implement it separately for iOS and Android using actual.

Here’s what it looks like for Android:

And on iOS:

That’s it – we now have a WeakReference definition we can use from our shared code. So let’s edit our Presenter implementation to use it:

Very nice! We are now safely storing a weak reference to our iOS native view.

Finally let’s add the presenter to our Android view:

That’s all we need! We now have a functioning MVP interface for our native views to communicate with the presenter.

Testing

The final piece of the puzzle is testing. Kotlin Multiplatform forces us to keep our view and business logic code cleanly separated, and therefore much easier to test. We can use the kotlin.test library with MockK to simulate and test all the scenarios we care about.

Here’s an example of a test which ensures the happy path behaves correctly and ensures that values make their way from the location and weather providers to the native views.

This approach can be extended to cover a wide variety of success and error scenarios. 

The MVP pattern means our views are very lightweight, so the majority of our testing effort should be directed towards testing our shared code like this. Future articles will also look at snapshot and interaction tests for our native views.

Wrap up

In this article we’ve seen how to use MVP to specify contracts between native and shared code. Using this pattern, it’s very clear exactly how a shared library should be used from iOS or Android code. It scales well for simple or complex screens and can be used across your project.

We’ve also seen how to use the expect/actual mechanism to avoid memory leaks when using this pattern on iOS.

And we have seen how our presenter logic can be tested, adding confidence and robustness to our shared code and providing a high level of test coverage to both our iOS and Android apps.

This approach puts us well on our way to creating a shared codebase which will make our iOS and Android apps more consistent, and reduce the effort required for development, testing and maintenance.

In future articles, we will look more closely at the presenter implementation, and at some of the interesting libraries available for use in Kotlin Multiplatform projects.

Introduction to Kotlin Multiplatform

We’ve just finished building our first commercial project using Kotlin Multiplatform. In the first of an ongoing series Douglas Hoskins, our Head of Mobile, gives an overview and some initial thoughts. We’re already working on future posts that will go into more detail and explain how we used this emerging technology.

Mobile development in 2019. The choice for developers is greater than ever in terms of frameworks and architecture.

But there’s one approach in particular that is getting the team at Future Platforms very excited indeed: it’s Kotlin Multiplatform.

Kotlin has been the language of choice for the modern, discerning Android developer for some time now. Its impact on the scene has been similar to that of Swift in the iOS community.

It’s been a breath of fresh air for those used to Java. Verbose, boilerplate-heavy code has made way for powerful, expressive Kotlin. It makes codebases more readable, and its null-safety eliminates entire classes of bugs. Android developers have embraced it in droves.

As the name suggests, Kotlin Multiplatform is a framework which allows Kotlin code to run on many target platforms.

This includes iOS!

It’s been around in beta form for quite a while, and it’s now ready for production. In fact, we’ve just finished a large project using it.

This post will introduce the platform and explain why we think it’s a great approach for cross platform app development.

Let’s set the scene. You should seriously consider Kotlin Multiplatform if:

  • You are building apps for both iOS and Android
  • Which are equivalent in terms of functionality and user journey
  • But the UI should still reflect the finer nuances of the target platform

This brings us to the first key thing to understand about Kotlin Multiplatform: there is no shared UI. The only shared code is behind the scenes; your app’s back-end.

You’re essentially building a bespoke core library for your native iOS and Android apps to share.

This means all sorts of complicated business logic can be written once, instead of twice. Think of everything that goes on below an application’s UI: network calls, user input validation, data manipulation, storage and caching.

With the traditional model of separate development teams per platform, this logic is designed and implemented twice, once by an iOS team, once by an Android team. Inevitably, both will have their own quirks, their own slightly different interpretations of business requirements, and their own bugs.

Using Kotlin Multiplatform, both apps are aligned on a single standard library. This increases stability, reduces development effort and streamlines testing.

But wait, don’t other solutions provide a means of sharing UI too?

They do, and Kotlin Multiplatform steps away from this thorny issue. I won’t dive into all the pros and cons of cross-platform UI frameworks here, but it’s fair to say they all come with some amount of risk. So while some may consider this a shortcoming, Kotlin Multiplatform in fact offers a pragmatic solution for low-risk code sharing.

Code you write in a Kotlin Multiplatform library really behaves the same as equivalent code you’d write for the native platform alone. And your apps are no different from the point of view of the user.

From the developer’s perspective, the latest and greatest tools can be used to craft pixel-perfect user experiences, tailored to the platform.  Native teams can use their existing skills. And if you’re building a team, Kotlin and Android already go hand in hand.

Speaking of teams… what about the iOS developers? How did they cope with a considerable change to the regular app development workflow?

Our iOS folks all reported positive experiences with Kotlin. I think there’s a few reasons for this. For one, people really love to learn something new. New technologies, new approaches. It also brought the team closer. iOS and Android developers were collaborating, working together to create the best possible API for the shared code, that would work on both platforms.

But mainly, the benefits were easy to see by the whole team. Each new feature added to the app brought additional complex back-end logic, implemented only once. Less code to write means less code to maintain and debug in future; everyone’s happy!

Finally, and this may be controversial so I’ll whisper it, Kotlin’s actually a lot like Swift, as this cheatsheet shows! Most concepts Swift developers are used to have easily recognizable equivalents. It really isn’t difficult for an iOS team to pick up.

What is the development experience like?

Android Studio and IntelliJ are both supported for Kotlin development. This means Android developers can work entirely in one environment, but iOS developers who want to work on Kotlin code will need two IDEs side-by-side.

In fact, the story is very straightforward on Android — the shared codebase behaves like any other Kotlin library you might include in your project.

On iOS it’s also pretty simple; you build your shared Kotlin library, and then it becomes available for use in your Swift code the same as any other library you are importing.

Any class defined in your core Kotlin codebase can be accessed or instantiated from iOS or Android native code. Sticking to a pattern such as MVP keeps things tidy and organised.

What can you do in a Kotlin Multiplatform shared codebase?

The flavour of Kotlin that you write in a Kotlin Multiplatform codebase is slightly different to what you might find in an Android codebase. The main reason is that you can’t use anything provided by the JVM, or by the Android framework itself.

But fear not! Kotlin provides a rich standard library, while HTTP and JSON parsing are available via multiplatform libraries. These, combined with a growing selection of open-source libraries from the community, means that most things you’ll want to do in your iOS or Android app will be possible in Kotlin.

Of course, there is complete flexibility to fall back to native code when required. For example, in our project, the Klock library provided most of what we needed for date and time manipulation, but we still needed access to the iOS and Android native timezone utilities.

Kotlin’s native interop means it is also possible to write iOS-specific Kotlin code. This code can interact with the iOS platform APIs, meaning it is possible to write an entire iOS app only in Kotlin! While we would not recommend doing that, we did find this convenient when we needed to create very small snippets of code touching the platform APIs.

Anything to watch out for?

This technology is still emerging, so occasional issues are to be expected. And it should be noted that the iOS compatibility is still officially in beta. But, on the whole we found the stack reliable.

There is an official tutorial for getting started, along with many unofficial ones. Things tend to go well if these are followed to the letter! But if your setup has to deviate from the template for any reason, there is a very active and engaged Multiplatform community on the #kotlinlang Slack channel. This should be your first port of call in the event of any issues. The participants there have advice and solutions for most problems.

Some of the platform libraries are under heavy development, so frequent updates are available. A pragmatic approach is required to ensure that these don’t disrupt an existing, working setup.

We are very pleased with the results Kotlin Multiplatform has delivered for our teams so far. It will be at the top of our list of technologies for new projects, and we will be looking closely at deploying it into existing projects also.

Look out for more blog posts in the future which will explore the aspects of Kotlin cross-platform app development in greater depth.

Visit to Devoxx UK 2019

This year I had an opportunity to visit the Devoxx conference again and it’s been an amazing experience. For those of you that hear of Devoxx for the first time – it’s a 3 day developer community event where people from all over the world share their technical experiences covering topics like Cloud, BigData, Programming, Methodologies, Architecture, Security, AI and so on, you name it. It’s also not just about talks, there’s Hands-on Labs and Deep Dive sessions, where you can learn new things together with experts and a Coding Café, grab some coffee or lunch and you can join in the community to fix that bug that didn’t let you sleep during the night.

I’m a senior backend developer and I mostly work with Microsoft technologies, .Net, C#, Web and Cloud development, but I’m always open to learning something new. You can’t just close your eyes and assume that this is the best technological stack for every problem, there are a lot of different solutions in the market and you’re always looking for the best one that suits your business. Devoxx is mostly oriented towards Java and that was the key factor for me to look out for best solutions in the market – this year’s theme: Back to the Future!

With the technology trends of AI, Autonomous Devices, IoT, AR/VR and Quantum Computing – “back to the future” seems like a really fitting theme. Autonomous vehicles are roaming the streets, we’re getting our questions answered by assistants on our phones, data centres are getting their first quantum computers installed and our industry is transformed by smart devices, but is that all there is to it? What’s next? My quest for finding the best and latest news in the market begins.

I’ll only cover some of the topics as this article would be way too long to cover it all, but if you feel like it’s not enough then all of the recorded sessions can be found online. The talks take place in multiple rooms and auditoriums in parallel so I had to choose of what’s of most interest for me. Here are some of the talks and topics that I found really interesting:

Cloud, Containers & Infrastructure

Continuous deployment to Kubernetes with the Google Container Tools

Talk by David Gageot – container orchestration systems like Kubernetes are great, but what about developer experience. Google listened to the community request and there are quite a few tools around to make your life as a developer easier. Check out his talk to find out how to use tools like Skafold, Kaniko, Jib and Bazel – CI/CD doesn’t have to be painful.

Service Mesh patterns

Talk by Alex Soto – microservice systems have huge advantages compared to  monolith architecture, but comes with its own challenges. Monitoring, collecting statistics, tracing, unexpected failures, routing etc. check out his demo on how you can solve those problems.

Architecture

Building Reactive Pipelines: How to go from scalable apps to (ridiculously) scalable systems

Talk by Mark Heckler – how to build systems that scale? Technical talk and a live demo about message brokers streaming platforms and how Project Reactor builds on reactive streams to help create performant and scalable reactive microservices.

Reacting to the future of application architecture

Talk by Grace Jansen – she’s a developer advocate at IBM, but before that she was a biologist and gave a talk about how we can learn from bees to better architect our software, make systems more responsive and resilient through reactive architecture frameworks.

Modern Web

An Introduction to WebAssembly

Talk by Guy Royse – he’s a Developer Evangelist and was explaining how WebAssemly works and how to use it. Javascript has been the king of front end for a long time now, but it’s not the only way to run code on a browser. WebAssembly is a byte-code language that you can run on modern web browsers.

The Web, its frameworks and its standards: deconstructing them for a more resilient code base

Talk by Hubert Sablonniere – an amazing show and presentation about the current situation in front end world. React, Vue, Angular – these are the most popular frameworks right now, but Hubert raises some very important questions – why are we using those tools? What problems do they solve? How can we produce future-proof code that resist against the hype and evolution of Web platforms?

Methodology & Culture

Me, My Code and I

Talk by Rosanne Joosten – she’s a software engineer and has a bachelors degree in Psychology. Presentation about code reviews and if it would be possible to read people from the code they write? What sort of people you need in your teams to achieve better results.

Agile is a Dirty Word

Talk by James Birnie – how did Agile become a dirty word? What does dirty look like? Agile, Lean, Kanban, Scrum, MVP, Prototype – all of these words are becoming toxic in one sense or another. How do we clean up this mess and what does clean look like?

Summary

At the end of the day there’s some fun to be had as well – Blind Ignite sessions where speakers get 5 minutes to present 20 slides, the slides are on auto forward and the presenter has never seen the slides before, what could go wrong? The rest of the evenings are some open sessions where everyone gets to speak on topics like writing documentation or writing your own blog or a book, it’s all about that community feeling where people share their experiences from all different fields.

After the whole conference I tried to come up with some general ideas of what the current IT market feels like and where it’s going. It’s not an easy task to take all of the information in from two days of talks, but here are my thoughts:

  • Microservices is still the leading architecture, make the services reactive and resilient – there are a lot of new tools out there to make your life easier to achieve this.
  • Serverless platforms are on the rise, they’re scalable and require less infrastructure, depending on the problems you’re trying to solve – serverless could be your next answer.
  • If you’re building microservices – Kubernetes is currently the most popular open-source platform for managing your containerized workloads and services.
  • Data is the most valuable resource available in today’s market – use Machine learning and AI to make good use of it.
  • Continuous integration and continuous delivery are the best practices – if you don’t have it setup yet then this is your next goal.
  • The web as we know it is evolving, WebAssembly could be the next Javascript, there’s already some projects, tools and languages in the market like Blazor, Emscripten and Rust to make this happen.
  • Storing large amounts of data for a long term archive is quite expensive – there’s a lot of research going into using DNA as archive storage. New portable devices that are able to read/write DNA code could hit the market fairly soon.
  • If you’re dealing with a lot of sensor data or just purely with a lot of devices – go for an IoT solution.

It feels like we’re concentrating more on making our lives better by optimizing our tools and processes instead of coming up with new frameworks and solutions, the big bang of new things in the market is starting to slow down and that’s a good thing I think, this is how evolution happens. The whole conference covers a wide range of topics and even if you’re not a developer, it is definitely worth visiting.

Effective fully-native multi-platform app development

Hype and excitement around cross-platform app development has never gone away. It seems to go in cycles: some big industry player releases a new framework which creates a lot of buzz, then it dies down slightly, only for another new framework to gain traction.

They all seek to let developers maximise reach and minimise development costs.

Efficient and innovative cross-platform development has always been important to us at Future Platforms; the “Kirin” model – shared application code running on both iOS and Android (but with separate UI) – has been pivotal to complex apps we have delivered for Domino’s Pizza, Glastonbury and Wembley.

We have always placed a high value on the benefits of this approach: time and effort saved by not solving problems twice over, with associated reduced costs of ownership and maintenance. The approach also ensures a single, consistent interpretation of client requirements, and therefore an equally good user experience across platforms.

But choosing to use a cross-platform approach for your app can be a risky decision. Frameworks such as React Native and Flutter add an additional layer between the developer and the machine, making it harder to diagnose any issues you run into (is this a bug in the framework, or am I just using it wrongly?). They also require the use of languages which are not otherwise used on mobile; JavaScript for React Native, Dart for Flutter, and C# for Xamarin.

Continue reading “Effective fully-native multi-platform app development”

Why do we attend conferences? #dotSwift 🇫🇷

Intro

As a developer you know that technology is continually evolving. So, in order to succeed you too need to continually evolve.

You can use books, courses, forums, etc. but today I am going to talk about conferences and one conference in particular, dotSwift (for iOS and Mac developers).

The aim of this article is to help you to understand if a developer conference is for you. You can then judge if it’s worth your while to go to such a conference.

Continue reading “Why do we attend conferences? #dotSwift 🇫🇷”