Ever since starting development for LINE beginning in 2011, we have been continuously developing and improving features to provide a better user experience. The growth of the project resulted in an increase of 1.5 million lines of Android client code including modules, and the team expanded to more than 50 members. For such large-scale projects, it’s important to maintain code readability and constantly address technical debts to achieve sustainable software development.
Writing code with high readability is more difficult than simply implementing the features. This requires knowledge on code readability and architecture reconstruction. I created this presentation for sharing such knowledge and skills required to make our development environment more sustainable.
The presentation consists of the eight chapters as follows.
- Introduction and principles: Importance of programming principles and code readability
- Naming: Descriptions, grammar, and word choice
- Comments: Documentation and inline comments
- State: Managing state transitions and deleting unnecessary states
- Procedure: The responsibility and flow of a function or method
- Dependency I: Strength of a dependency between two types
- Dependency II: Direction, duplication, and explicitness of a dependency
- Review: Code review request and review comments
Chapter 1: Introduction and principles
This chapter introduces the importance of code readability and useful principles that you can follow to improve code readability.
Why we need readable code
As mentioned earlier, code readability must be improved to make product development more sustainable. For instance, you can prevent developers (including your future self) from spending an hour trying to understand the source code if you just spend five minutes of your own time to give a meaningful variable name or leave an appropriate comment. The productivity of the entire team throughout the product’s life cycle is much more important than short-term and personal productivity. On the other hand, the necessity to consider code readability would be reduced if the source code has a short lifespan or the range of its use is limited. For example, test implementation or a script that is executed only once falls under this case.
The break-even point of emphasizing code readability ultimately comes down to balancing the time spent reading or explaining the source code to someone else, and the time it takes to writing it. Note that time spent reviewing code or referring to existing code while writing your own should be considered as time spent reading code as well.
Following programming principles while coding is helpful in many cases with writing robust and high readability code. The five programming principles in this chapter were selected because not only are they important for code readability, they also hardly cause any side effects even if applied excessively.
The Boy Scout rule
Robert C. Martin applies a proverb by Robert Baden-Powell, the founder of the Boy Scout Movement, on software development. Although the original meaning and context are different, the saying encourages you to make code cleaner when changing it. There are several ways that you can follow this principle, such as making names more readable and meaningful, adding comments or tests whenever you modify code, or deleting code that is no longer used. Basically the idea is “Don’t make dirty code even dirtier.” For example, adding a new case to a large switch statement is against this principle. We should refactor using a strategy pattern before adding a new case.
YAGNI (You Aren’t Gonna Need It)
This principle claims that code should only be implemented when needed, not when it looks like it will be needed in the future. For example, unused utility functions, abstraction layers without multiple implementations, and parameters where the argument is fixed. Functions and code written in preparation for the future have a high possibility of being unused and can also become obstacles when changes in code are needed for other reasons. An unnecessary conditional branch can be an obstacle when you try to add another conditional branch, complicating the final branch structure as a result. In this respect, it is important to avoid implementing useless functions and to make a simple and scalable design for future changes.
However, this principle is based on the precondition that it is easy to change code. It is difficult to change code for APIs and libraries that are published externally and for database schemas with migration difficulties. In this case, you might have to design and implement code with consideration for how it will be used in the future.
KISS (Keep It Simple Stupid)
The original meaning of this principle is that the design must be simplified for easy equipment maintenance. If this principle is applied to software development, it would mean simplifying specifications and implementations. Be cautious not to confuse purpose with methodology, especially when it comes to implementation technique. Design techniques, principles and paradigms of programming, the beautifulness and consistency of code are just methods to improve code readability and robustness. If these become the purpose, they can rather diminish the readability and robustness of your code. For example, you can make all values containing an integer
Observable with reactive programming. Although it may look “beautiful” from a uniformity perspective, code readability will be worse and finding bugs will be more difficult.
Single responsibility principle
This principle, which is one of the object-oriented programming principles collectively known as SOLID, posits that there should only be a single reason for changing a certain class. For instance, if you implement a single class that includes the structure of user information (name and email address) and a set of these elements (a list of registered users), the number of reasons for changing this class becomes two (to change the user information entry and to change the user registration method). In this case, we cannot guarantee that a change in one aspect will not affect other functionality. The scope of responsibility and interest in a class must be narrowed down to one.
Premature optimization is the root of all evil
This principle claims that optimization with little benefit should not be performed if they complicate the source code. Code optimization should only be executed when the effects are significant, and that is why profiling and estimates are important. However, this is not always true for optimizations that improve code readability. For example, if code used to search
ArrayList elements by iteration is replaced with
HashMap, memory usage might increase, but the amount of required calculations will reduce and the source code will become simpler.
This post only offers a glimpse into the contents of the entire presentation and an introduction to the contents of Chapter 1. In my next post, I’ll be going over Chapter 2 and 3 which will discuss naming and comments.