Understanding Clean Code in Android

Before you start writing your code, it’s better that you understand how to manage your code and how to make your code scalable.

Yoga C. Pranata
MindOrks
6 min readFeb 21, 2019

--

Image by Gabriel Sollman from Unsplash

As Uncle Bob said in his book,

You are reading this “article” for two reasons. First, you are a programmer. Second, you want to be a better programmer. — Robert C. Martin

Like what he said, imagine that you are in a library, and you are looking for some books. If the library sorted and categorized their books, you will find your books faster. In addition, the cool interior design & architecture will make you feel comfortable inside the library while you are searching for your books.

Just like writing books, if you want to build something great, you have to know how to write and organize your code neatly. If you have team members or someone else that has your (legacy) code, they just need to see the variable names or packages or classes and they will understand right away. They don’t need to say “F**k” this code and start it again from zero.

What is “Clean Code”?

As you can see, it is not good enough if you finish your development faster if others cannot understand your code, because it will become another tech debt.

Your code has a definition of “Clean” if it can be understood easily by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility, and maintainability.

— Must I care about it?

The reason why you must care about your code is that your code will describe your thought process to others. That is why you have to start thinking about making your code more elegant, simple and readable.

Characteristics of a Clean code

  • Your code should be elegant: Your code should make you smile the way a well-crafted music box or well-designed car would.
  • Your code has been taken care of: Someone has taken the time to keep it simple and orderly. They have paid appropriate attention to details. They have cared.
  • Your code has to be focused: Each function, each class, each module exposes a single-minded attitude that remains entirely undistracted, and unpolluted, by the surrounding details.
  • Contains no duplication
  • Runs all the tests
  • Minimize the number of entities such as classes, methods, functions, and the like.

One difference between a smart programmer and a professional programmer is that the professional understands that clarity is king. Professionals use their powers for good and write code that others can understand. — Robert C. Martin

Create Meaningful Names

Choosing good names takes time but saves more than it takes. The name of a variable, function, or class, should answer all the big questions. It should tell you why it exists, what it does, and how it is used. If a name requires a comment, then the name doesn’t reveal its intent.

Let’s take a sample:

— Class Names

Classes and objects should have noun or noun phrase names like Customer, WikiPage, Account, and AddressParser. Avoid words like Manager, Processor, Data, or Info in the name of a class. A class name should not be a verb.

— Method Names

Methods should have verb or verb phrase names like postPayment, deletePage, or save. Accessors, mutators, and predicates should be named for their value and prefixed with get, set, and is according to the javabean standard.

— Use Problem Domain Names

When there is no “programmer-eese” for what you’re doing, use the name from the problem domain. At least the programmer who maintains your code can ask a domain expert what it means.

Before we continue, take a break and make some coffee or grab some snacks. :D

OK, now we continue about the writing your code using S.O.L.I.D principles.

Writing your code using S.O.L.I.D Principles

This principles are invented by Robert C. Martin (Uncle Bob), SOLID is a term describing a collection of design principles for good code.

Single Responsibility Principle — SRP

It means every class should have a single responsibility. There should never be more than one reason for a class to change. Just because you can add everything you want into your class doesn’t mean that you should. Split big classes into smaller ones, and avoid God Classes.

Lets take a sample:

We have an RecyclerView.Adapter with business logic inside onBindViewHolder.

It makes RecyclerView.Adapter not having a Single Responsibility because it has a business logic inside onBindViewHolder. This method is only responsible for setting up data into its view binding implementation.

Open-Closed Principle — OCP

Software entities should be open for extension but closed for modification. What it means is that if you write a Class A, and then your teammates want to make a modification in a function inside Class A, They can easily do that by extending Class A, instead of making a modification inside Class A.

The easy example would be the RecyclerView.Adapter class. You can easily extend this class and create your own custom adapter with custom behavior without modifying the existing RecyclerView.Adapter class.

Liskov Substitutions Principle — LSP

Child classes should never break the parent class’ type definitions.

It means that a subclass should override the methods from a parent class that does not break the functionality of the parent class. For example, you create an interface class that has an onClick() listener, and then you apply the listener in MyActivity and give it a toast action when the onClick() is called.

interface ClickListener {
fun onClick()
}
class MyActivity: AppCompatActivity(), ClickListener {

//........
override fun onClick() {
// Do the magic here
toast("OK button clicked")
}

}

Interface Segregation Principle — ISP

The interface-segregation principle (ISP) states that no client should be forced to depend on methods it does not use.

It means that if you want to make a Class A and implement it in another class ( (Class B), it should not override all Class A methods inside class B. To make it clear and easy to understand,

Let’s take a sample: inside your activity, you need to implement SearchView.OnQueryTextListener() and only need the onQuerySubmit() method.

How to achieve that? simple, you just create a callback and a class that extends to SearchView.OnQueryTextListener().

And here is how to implement in view:

val listener = SearchViewQueryTextListener(
object : SearchViewQueryTextCallback {
override fun onQueryTextSubmit(query: String?) {
// Do the magic here
}
}
)
mSearchView.setOnQueryTextListener(listener)

Or, if you are using Kotlin, you can use the Extension Function:

And last, here is how to implement in view:

val listener = object : SearchViewQueryTextCallback {
override fun onQueryTextSubmit(query: String?) {
// Do the magic here
}
}
mSearchView.setupQueryTextSubmit(listener)

Dependency Inversion Principle — DIP

Depend on Abstractions. Do not depend on concretions.

Uncle Bob’s definition of the Dependency Inversion Principle consists of two points:

  • High-level modules should not depend on low-level modules. Both should depend on abstractions.
  • Abstractions should not depend on details. Details should depend on abstractions.

High-level modules, which provide complex logic, should be easily reusable and unaffected by changes in low-level modules, which provide utility features. To achieve that, you need to introduce an abstraction that decouples the high-level and low-level modules from each other.

The easy example is in MVP pattern, you have an object of interfaces that help us to communicate with concrete classes. What it means is, UI classes (Activity/Fragment) don’t need to know the actual implementation of methods in Presenter. So, if you have any changes inside presenter, UI classes don’t need to know or care about the changes.

Let’s see it in this code example:

Now let’s see it in UserActivity:

So what we do is we create an interface which abstracts the implementation of a presenter and our view class keeps the reference of the PresenterInterface.

Conclusion

Mature programmers know that the idea that everything is an object is a myth. Sometimes you really do want simple data structures with procedures operating on them. From now, you have to start thinking about what to implement and about future perspective that will be easy to update.

I know that if you have created an app before with nonsense naming, God classes, Spaghetti code, trust me, I have done the same thing. That’s why I share my knowledge about the Clean Code from Uncle Bob to you, and it is also be a reminder for me and I hope I can help you to understand it.

Last but not least, Comments/Suggestions are welcome as always. Keep learning and keep sharing.

Happy Coding :)

--

--