Our Android apps are huge: they have over 1.3 million lines of code, over 210 million downloads on the Google Play store and an amazing team of 23 people who develop them. The AMA was a great opportunity for the community to find out more about how we develop.
Andrei, Anton, Arkadii, Ivan, Michael, Nick, Zsolt and I were very excited to have the chance to interact in such a way with external developers, and hope that the 163 answers we provided were helpful.
Over the three hours of live Q&A, the topics discussed were pretty varied. We covered architecture, tools, tips for the learners, approaches for delivering features and many more. It would be impossible to list them all, but here are the top 5 questions most voted by the Reddit community!
Zhuinden asked about using Android Jetpack, Fragments and Activities, and what we are using instead.
Zsolt: Good question!
Limitations: some Jetpack approaches don’t scale well to a multi-app architecture domain. I realise this is a niche problem, but it’s actually a serious one for us.
LiveData: No. Instead of MVVM, we have MVI, and we’ve developed our own automatic scoping for it, a tool called the Binder. Right now it only exists as part of our library — MVICore, but it’s targeted for extraction to a separate lib. We find it to be more versatile than LiveData, as it can be used outside the context of Android too and it’s super easy to use (Kotlin one liners). You can read more about the concept here and here. It’s a really amazing tool. Check it out.
Navigation component: No. We have a Router pattern with our version of RIBs. Having to maintain global navigation in apps with shared components adds maintenance burden both on the app level as well as app-specific knowledge to the shared components. The latter, specifically, is a huge downside if you want to reuse a component in different apps. The component shouldn’t assume anything about the app it’s used in (e.g. what screens are available). In contrast, Routing is basically local navigation. It moves navigation down from a global concern to an implementation detail of a component, meaning you are free to plug them in anywhere without having to worry.
Fragments: No. We have something similar to a deeply nested Fragment tree with RIBs, but much better. We also solved the problem of constructor injection without hacks like FragmentFactory, in a compile-time safe way. The framework constructs your component for you, but you tell it how to do it.
As for why we’re going our own way instead of following mainstream, the answer is that the whole process started many years ago. Way before the Jetpack era there was a time when we tried following “the Google way”, and as a result, burnt ourselves with Fragments. We moved farther away, trying to figure out what alternative would be best for us. We have been among the first to adopt new tech on many occasions (we tried Clean architecture as early as 2016, RxJava 2016, Kotlin 2017, Redux-inspired MVI 2017), and such tooling/frameworks/libs were not that abundant either. By the time Jetpack was announced, we had already invested in our in-house tech stack. Overall, we’re quite satisfied with it compared to mainstream approaches.
Having said that, we are using Room and personally I’m super-excited about Jetpack Compose 🙂
It gives me great pleasure to say that Zsolt’s answer above got a Gold Award from the Reddit community ✌️
Juliocbcotta asked not one but six questions in a single comment!
- Do you use Kotlin? How much of the project is in Kotlin?
Nick: Yes, all new features are written in Kotlin.
We have ~690k LOC of Kotlin and ~680k LOC of Java
2. Annotation processing for the win, or no, no, no?
Arkadii: No, no, no. Compiler plugins are our future 🙂
Nick: We’re trying to avoid annotation processing and for development builds we’re using reflection implementations of annotation processing libraries if possible. Currently, we have annotation processing for Dagger, Room and Toothpick.
Andrei: Apt is fine as long as it’s not kapt.
3. Is the project segmented by country? How does this work?
Ivan: From the native client-side it looks like a single backend which we access via API. Then on the server-side, it is segmented in some areas, but the answer is not simple, as functionality is shared between the application layer and a bunch of services.
Nikolay K (server team): We have 2 main regions (two DC locations). Each user is served from their primary region. The region is based on user location, chosen on user registration and can be changed afterwards (when the user is offline) if the user has changed their location.
4. Does the project use appbundle? What is the difference in the size of the archived project?
Nick: yes, we use App Bundle and we even have a dynamic feature. The difference after releasing the app using App Bundle was about -17%.
Andrei: We also used dynamic delivery and have written an article about this 🙂
5. Have the team ever thought of migrating to a multiplatform approach? Which one or why not?
Arkadii: We’re experimenting with Kotlin Multiplatform. We have an internal project written fully in Kotlin MultiPlatform and are considering this technology for production. We also have a few multiplatform modules in our main projects but currently, they are used in Android only.
We created our own Reactive Extensions library to support the transition: Reaktive.
MVICore is currently being converted to Kotlin Multiplatform.
6. Could the team share something about one simple change or new feature that made a big difference in the numbers?
Anatoly: As regards features: we implemented Badoo Video Chats and we had functionality to send gifts. Users had to tap on the streamer icon, then pick “Send gift” and then pick an actual gift. It was 3 clicks to actually send gifts and wasn’t clear for users that we have such functionality. So, we added a bottom bar with scrollable gifts and users had the ability to tap with a single click and immediately send a gift for the streamer. It took about 3 days to implement, but we saw a huge spike in the number of gifts sent.
Michael: We display the number of likes a user has received in the top left of the app. Previously it would be displayed as a dot which would animate to briefly display the current number of likes. Removing the animation and leaving the number of likes displayed, permanently improved metrics considerably.
Dadofbimbim: What database are you using inside your app?
Arkadii: we use SQLite, either basic SQLiteOpenHelper or Room
Note: This was one of the shortest answers that we sent, so let me share a little bit more context here. We’re using Room only for new modules that we are working on right now. But for other parts of the application (chat for example), that were already using SQLiteOpenHelper, it isn’t worth migrating everything to Room.
Synteycz: I imagine you have some legacy code. How do you stand on refactoring old stuff to be on time with new tech? If you do refactor, how do you do it? Do you have one particular guy doing refactor or have specific time reserved especially for refactoring?
Anatoly: When we’re developing new features and it touches some already existing functionality we can add estimations to refactor old parts. Also, if we see some problems with our codebase, we discuss this with managers to get some time dedicated to refactoring. And as a baseline, we dedicate about 20% of the time to refactoring. Anyone can do refactoring depending on the situation, we don’t have a specific person for this.
Anton: I try to follow The Scout rule — “Leave your code better than you found it”. While working on a feature that is related to and touches the legacy code I try to increase test coverage, maybe do some small refactoring like splitting long methods. But for the larger-scale refactoring, we devise a specific plan with time estimation and defined stages.
Michael: We had sections of our code dating back to 2012. It had been left untouched as we’d been too scared to change it because we lacked test coverage. So, our approach was first to improve test coverage — along with our amazing Calabash testing team to build tests we could rely upon. We then started carving chunks out of the legacy in small pieces, often lumping it in with feature work. Finally, to get rid of some of the worst of it, we discussed dedicating some time exclusively to cleaning it up. As a Revenue Team rule, we each spend one day a week keeping our tech debt under control and picking up any odd tasks that still need doing.
TL;DR: When you are touching legacy code — try to refactor it, if this makes sense. Discuss it with your manager to ensure you have time for refactoring and maybe even dedicate some percentage of your time just for refactoring.
TheAmazingSausage: What architecture are you using? Are you happy with it? What would you change if you could? Any lessons learnt worth sharing?
Arkadii: We use MVI + RIBs
Zsolt: We use a heavily modified version of RIBs (“This branch is 871 commits ahead, 15 commits behind uber:master” is what I mean by heavily modified). It gives us a tree structure where every level can be taken and plugged into a different app (with the whole subtree that belongs to it). Inside the nodes we have MVI pattern with reactive bindings. We are happy with it! :)
Lessons worth sharing: Activity is a wrong abstraction. Navigation can’t be global if you want to reuse components. Removing the notion of screen from your components helps a lot. Having a defined structure for creating components really helps in understanding each others’ code. Do the heavy plumbing behind the scenes so that your client code becomes easier to write and maintain.
Michael: Within the Revenue Team we’ve recently started experimenting with a new MVI based approach that we’ve called SubFlow. It’s heavily inspired by the actor pattern (as seen in libraries like the Play Framework and Vert.x). The approach was originally used by our iOS team. When we saw how well it worked for them we decided to try it out as well. It works by breaking down the business logic into simple, single-step actors. Each actor/subflow can then launch the next subflow to perform the next step in the chain, with the choice of next subflow being configured externally.
Our main goals were to reduce code complexity and verbosity while also increasing knowledge sharing with our iOS team. Although still an experiment, we’ve been very happy with it. Sadly, it’s not yet open source.
Also, one particular question was asked by three different people so I thought it would be nice to include it here, too.
How to become an Android developer? And here are our responses:
Anatoly: I started with writing simple examples, then I tried to find ANY “Android Developer” job. It was super difficult to get that first job (took me about 6 months), but after getting that first one, it was much easier to find the next. You might try the same approach.
Anton: The best way to become a professional developer, I believe, is to find a mentor and have them guide you through your first steps into professional development. It could just be someone you know who’s already a mobile developer. You can also meet other devs on the local meetups organised by various companies. I did that until I eventually succeeded at interviews. Be sure to ask for feedback from every interview you get and learn from it. Good luck, in your career!
Andrei: If you’ve already got some finished projects, that’s amazing! It was a long road for me with thousands of declined applications and the main thing I learned is not to give up.
Michael: If you only read one book, make it Effective Java.
Zsolt: Rather than going into specifics, or even focusing on Android, I think the following 8 things generally help a lot more than any actual tech in itself:
Do a pet project. Ideally not so large that you never finish it (seriously, everything takes a LOT longer than you think at the start. So, start small).
Try out some approaches on that pet project. Stretch yourself beyond your comfort zone. Struggle with new things a bit until they click and, you’ll expand your mental models and your toolset in the process.
Ask for feedback on it from various sources. Not everyone who says it’s super cool are right, but not everyone who says it’s shit are right either.
Dig into any applied pattern/lib before committing to it. I don’t mean a 30-page research paper, but just enough to understand what are the general pros and cons of using it.
Try to get a good understanding of what the current trends are (again, with their pros and cons) and where they are heading. This is not something you can do overnight, and you need to keep updated. There are thousand different sources on this, from conference videos, to Twitter, to Reddit, to Android weekly and podcasts. Pick one of those that fit your taste.
Both having pet projects and company employment are different things but are both things you can use to improve yourself. For the pet projects, you can try out things that a company with an existing set of applied tech and a focus on delivery, would never give you the chance to do. But working at a company, you need to focus on aspects of an app otherwise easier to neglect (caring even for a small % of users with performance, screen sizes, localisation, etc.). It’s also important to gather valuable feedback from colleagues.
Try to mentor others who know less than you do. You don’t have to be an expert to do this, you can even start now — there’s always something you already know that some others don’t. Doing this has two benefits: firstly, it improves your communication skills (which will become an even more important than technical skills at some point in your career) and secondly, it tests you, revealing whether you really understand a topic or just feel like it.
Try to be the worst musician in the band you play in. If you’re the best, find another band where you’re the worst again so that you can learn the most (this advice is from The Passionate Programmer — a good read)
Being part of a public-facing Ask Me Anything session was extremely interesting and great fun for all of us.
It’s something completely different from our daily routine, of course, even if the whole thing was a pretty intense experience. Being on a video call with 9 other people while processing questions, composing answers and trying to not lose track of where you were a minute ago with all the distractions going on, isn’t as easy as you might imagine.
But it was definitely worth all the time and effort, and the turnout was even better than anticipated. We were so amazed by the sheer number of questions. Should we be asked in the future to take part in another AMA in the future, the answer will definitely be yes!
Our thanks go to everyone who participated, and to the AndroidDev Reddit group for hosting our event.
Our Bumble and Badoo Android team is growing! Feel free to get in touch and find out more here if you’re interested in joining us 🙂