Mobile development at reBuy: Moving (back) to Native

Rajko Winkler
9 min readJul 31, 2018

--

Sometimes it takes guts to make decisions, this is equally true for the tech world as for any other field in life. And sometimes it takes even more guts to revoke those decisions and move on.

“Write once, run everywhere”

In late 2014 we as the mobile team at reBuy were utterly impressed by Xamarin’s unique promise: Build native UIs for Android, iOS, and Windows Phone based on one single, shared C# codebase.

“Write once, run everywhere” seemed like the perfect fit for our rather small mobile team back then. Xamarin Forms supported a common set of UI controls and layouts to then map those to the corresponding native UI controls at run time.

Besides the predefined set of controls, developers could also extend the UI with custom layouts by providing additional custom render classes for the targeted platforms. The promise also included interoperability towards native libraries through bindings.

Considering that we had previously come from minimal native implementations in Java and Objective C partly embedding web views, this seemed like an incredible opportunity: Design and develop one app and literally roll it out at once to our Android and iOS users.

Start Fresh

The mission of reBuy is to increase the overall life cycle of products by selling and buying used goods. Providing a usable and appealing app is essential to bind customers in a long term.

So we gave it a shot: The team started off by implementing the purchasing branch of reBuy. Customers can sell used media products and consumer electronics at a fixed price and receive their money once their items arrived at the reBuy warehouse. Development included the usage of the user’s camera to easily scan products by their bar codes along with the regular product search and checkout process.

It took another year until we managed to release the selling part of the reBuy app, by that time the number of developers had doubled, totaling four. In July 2016 the team released a feature-complete Xamarin Forms app to our users.

Technically we delivered a solid app. However, basically, all design decisions had been taken top-down, an approach that implies design confidence based on personal opinions and experiences, but lacks measurement of impact on the users overall.

Step up

A/B testing provided us with a tool to gain immediate feedback from our users. In very small experiments we could tell if a certain feature went in the right direction. It felt like we were moving fast.

It was that time, however, when we started to run into limitations within Xamarin Forms. Design approaches became more tedious to fulfill, and bindings to third-party libs we desperately wanted to use, didn’t exist. Creating some of them turned out to be cumbersome and error-prone.

At this point however you usually don’t make a move yet, the app had literally just been released. Instead, you work your way around it, which means investing some extra time in tweaks and fixes. And that might be bearable for the moment.

Turning point

The performance turned out to be another major disturbing point to the user experience of our app, though. This had been especially true for the Android app. The underlying Mono layer became a massive bottleneck, resulting in unacceptable startup times beyond 15 seconds.

So while Xamarin Forms’ abstraction level had been extremely convenient during development and maintenance, the outcome more and more turned into an unpleasant solution for our customers.

Into the wild

This is when you do know it’s time to make a move. But now that we saw what’s wrong, where do you start? Well, we locked ourselves up in a remote location for a few days and began testing possible alternatives, at first for our troublesome Android app with its mentioned burdens. In small teams, we created two minimal prototypes of the reBuy app that gave us just enough load and data to compare them in startup times and still were doable within the given time frame.

Code camp in the wilderness of Brandenburg

Going half-native?

Technically speaking we had Xamarin Native vs Android Native in this battle. Xamarin Native for Android simply provides a C# abstraction layer to the complete Android stack. So the obvious hope was to make use of a large amount of code reuse and still benefit from native UI components.

Expectations towards Android Native were naturally driven by the idea to get the most out of the richness of the Android ecosystem. To be able to follow the latest design approaches and get to use a wide variety of available components and tooling. The obvious downside was the assumed learning curve to embrace Android development.

In retrospect, the adoption of Xamarin never provided the needed comfort to easily navigate through obstacles. From small things like a terrible “official” forum as a promoted source of support to quite often breaking changes in layouts in the broader picture, we never fully gained the confidence of either a helpful backing or a critical mass user base.

We had to leave our comfort zone, though, to deliver something more appealing to our customers.

It was a tough debate on opportunities, risks, and also about leaving our comfort zone. We discussed, compared, and timed. While Xamarin Native outperformed Xamarin Forms as expected we had to accept that we still were not able to make use of third-party components natively. And user adoption seemed even lower than Forms, so not much help in sight either.

In the end, it was a clear decision to commit ourselves to the idea of “moving back” to native. The expected benefits were just too overwhelming. We had to leave our comfort zone, though, to deliver something more appealing to our customers.

The green field

So here we were: A developer's dream, the green field. About a week after we took the decision Google happened to announce broad support for a JVM language other than Java — Kotlin. Effectively they said it was to become a first-class development language for the Android environment. Support and samples were meant to cover Kotlin from now on also.

So since we were starting fresh anyway, we tried out Kotlin by converting some of our prototype Java code to it. We quickly dug deep into it, grasped its concepts, and were astounded by its capabilities.

Toward the start of development, we looked at what other teams were doing to adapt to the new language. Often other companies would start including Kotlin by writing unit tests for their existing Java code base first to ease the shift. Well, that wasn’t us exactly…

Kotlin — All in

Instead, we took our next bold decision: we as the dev team committed to 100% Kotlin right from the start. On one hand, this felt right, why start with Java? On the other hand, a new language bears risks, as its adoption was low at that point and there were fears that we might miss out on mature of an existing ecosystem again. In the end, this was one of the reasons to move away from Xamarin in the first place.

The milestones for the fully redesigned app were already planned and they did not allow additional time to be wasted, because let’s face it: if we put our team on a complete redesign, we effectively stop delivering anything new to our customers until the new app had been released.

The team concluded we could always fall back to Java for certain classes in case we got stuck. To this day this has not happened once.

But hey, Kotlin is a JVM language, and the interoperability capabilities between Kotlin and Java were convincing. The team concluded we could always fall back to Java for certain classes in case we got stuck. To this day this has not happened once.

Kotlin itself was an easy play, the language has similarities to C#, which we had used with Xamarin. In addition to that, we again went for the Reactive Programming model which comes as RxJava in the Android world. Its usage allowed us to apply some of the concepts we had already used intensively.

Hands-on

The main target was a minimal release by mid-December. This left the team with around six months to complete this ambiguous goal. Work got structured in four milestones, the first two targeting the selling side, followed by one for the purchasing side, finalized by one running QA test rounds with an external testing company, and finishing up.

Team’s additions chart from GitHub, created some impact around the milestones in August and September

Despite the language being friendly, we had to invest a lot in understanding the platform itself. The team had different experience levels regarding technical topics like application life cycle, view handling, and UI creation. So naturally, it took some weeks to really get us going.

After having settled with some of the more important technical decisions, and already making use of new designs that our design team had prepared for us, we were up and moving at the end of July.

In retrospect, we roughly made every milestone on time. We held various internal presentations and started internal tests to gather early feedback. Constantly we were driving on that slightly uncomfortable edge, knowing we are moving fast.

Getting there

The closer we got to December 15th, the more the team got excited. After going through an evaluation with an external QA company and plenty of hours of bug fixes and last improvements we managed to release to the targeted audience of 1% at the exact date. This meant around 2000 of our users were able to download the new app version.

From experience, the learning starts once an app is released. There are so many things that you can test even with such a low number of customers. We found some serious troubles in the way we handled our fragments that required quite some effort at the beginning of this year to get this straight.

The team did an awesome job of catching up on the issues that arose. We managed to improve the app, even adding more features and getting A/B testing in place. From sprint to sprint, we carefully released to an increased number of our users.

Break-even

One of the most desperately awaited moments at that time was the break-even in mid-April: Distribution of the new app to 50% of our users. For the first time in over 10 months of development, we were able to directly compare old vs new apps and see how well they would perform. Would users accept the new app? Did we manage to provide something meaningful to our users?

No more rolling back, no back up, we are live!

To keep it short: The numbers we saw were quite promising! The conversion rate on our selling side was up by more than 4 %. Green, the purchasing side, was even beyond expectations by seeing a 19.5 % increase in conversion rate and a 12.75 % uplift in average order value.

Here and there we still had some smaller flaws, but the numbers proved us right. By the end of April, we finally rolled out to 100% of our customers. No more rolling back, no backup, we are live!

In the past months, we were able to keep those numbers on the right track and in addition had two months with an all-time high in created revenue with our Android App. The new app not only outperformed the old one economically, but startup time also went down by 3x. Also by not carrying around the Xamarin overload anymore, our app size went down by 5x and is now below 10 MB.

It won’t stop here

Not taking too much of a rest we went on to release our app to our French customers by the end of May this year. This effort will be extended in Q3 and beyond. On top, we will see more A/B testing to continuously provide more value to our customers.

You as the reader might recall that we completely stepped out of development to create our new Android app in June 2017. Well, this was also true for our iOS app. So from the beginning of 2018, we also started investing heavily in its re-development. A tremendous team effort with some help from third parties led to its projected completion at the beginning of Q3. This feels pretty exciting and the past year has truly been an incredible learning time for the complete team.

--

--

Rajko Winkler

into product • flips bytes on the daily • working at reBuy • bilingual parenting