This post, like Kent Beck says in his book Implementation Patterns, “…is based on a rather fragile premise that good code matters…”. But we all know that clean code matters as we’ve had to deal for so long with its lack. And so does Kent.
The Total Cost of Owning a Mess
A few years ago, like every naive Android developer working in an early-stage startup in India, I tried to “hack” real world problems, to “disrupt the industry” and to put a “dent in the universe”. Without a care in the world about good software design or architecture, I started writing code to build an Android app that would one day become one of the biggest consumer heath-care apps in India.
Sprint after sprint, hack after hack, features were built in a mad rush. Build. Measure. Learn. Time-to-market was important and every day mattered. Time flew by, we were growing at the rate of 1 team member every 6 months and the app had hit the million downloads mark.
By this time, the app had stopped being trivial and it had become a multi-tenant client, if that’s even a thing. Features that would take hours when we started now took days, sometimes weeks. Every Activity was 1000+ lines of spaghetti code as Android inherently doesn’t worry too much about the separation of concerns. The total cost of owning a mess had significantly slowed us down.
The Android Conundrum
The code looked ugly, Activities managed everything:
- Config changes
- What not
After all, Activities are Controllers, right? Or are they Views? I didn’t know anymore.
The Grand Redesign In The Sky
We needed to design the app in a way that changing a line of code somewhere did not break something somewhere else. The app had to be, as Uncle Bob says, “robust but not rigid, flexible but not fragile”.
This was when my mentor and friend Kashif Razzaqui joined the team to help us alleviate the mess. The grand redesign never happened, but we refactored the hell out of our code:
- We added a “service” layer and moved all the non-UI code into them, one service at a time.
- We chucked AsyncTasks and moved to ListenableFutures using Guava.
- We dumped AsyncHttpClient for OkHttp.
- But more importantly, we started reading a lot: Clean Code, Clean Architecture, SOLID, DRY, The Pragmatic Programmer, Java Concurrency In Practice, Domain Driven Design, etc.
Soon we started seeing the benefits of our efforts. Productivity increased, we were writing things faster, everyone was happy.
This was until we unified our apps and all hell broke lose. Just having an additional service layer didn’t cut it.
The Art of Clean Code
A few days into the experimentation, we decided to switch to RxJava and implement MVP using Clean Architecture. We made sure we encapsulated all layers behind interfaces and separated concerns well.
- The View, usually implemented by a Fragment, contains a reference to the presenter. The only thing that the view will do is to call a method from the Presenter every time there is an interface action.
- The Presenter is responsible to act as the middle man between View and Model. It retrieves data from the Model and returns it formatted to the View. But unlike the typical MVC, it also decides what happens when you interact with the View.
- The Model is only the gateway to the domain layer or business logic.
- The Interactor deals with I/O and is the provider of data to be displayed in the View.
Now it’s much easier to switch out one layer with a completely new implementation. Redesigning the UI, a part and parcel of Android app development, has become much easier. Things can finally move fast without breaking.
The Boy Scout Rule
It’s not enough to write code well, the code has to be kept clean over time. The fact of life is that software has a tendency for entropy. We’ve all seen code rot and degrade over time so we borrowed the simple boy scouts rule: “Leave the campground cleaner than you found it.”
If we all checked-in our code a little cleaner than when we checked it out, the code simply could not rot. The cleanup doesn’t have to be something big. Change one variable name for the better, break up one function that’s a little too large, eliminate one small bit of duplication, clean up one composite if statement.
Our way of building a scalable app might not be “correct” and you might not agree with this post. After all, not all martial artists agree about the best martial art, or the best technique within one ;)
There are many different approaches towards MVP and a lot of interesting solutions to adapt it to Android. The one fact that we can’t deny is that Clean Code matters and you just can’t sweep it under a rug.