Improve code readability
Developers spend more time reading code than writing it. By reading I mean debugging code, reviewing code submitted by others, learning new code bases, and so on.
So make sure your code is easy to read, even if you need longer names, write more code, and lose your smarts.
For example, even though the variable name timeInMillis is longer than time and you need to enter more characters, the developer can figure out what time the variable is counting without looking at the rest of the code.
For another example, there are many one-line solutions available online. For example, it is very clever to write a palindrome number as follows:
def isPalindrome(self, x: int) -> bool:
a=list(str(x))
return a==a[::-1]
Copy the code
But it’s very difficult to understand. One-line solutions are challenging and are not recommended in codebase that is jointly maintained by several people.
Value of refactoring
Refactoring is only worthwhile if it saves you and your team more time than it takes. You should focus on the code you read and write frequently.
Consider assigning non-urgent refactoring to new team members to practice so they can learn and add value.
Think of technical liabilities as financial liabilities that can be taken on in moderation
Sometimes, from a business perspective, providing valuable function as soon as possible can get more benefits, such as before a similar function in the competition, even if this time the function is not perfect enough and it doesn’t matter, as long as you can set up plans, in debt, are smothering “interest”, improve the code in a timely manner.
If technical debt accumulates faster than you can afford to pay it back, problems arise and the code base becomes increasingly difficult to deal with.
For example, in a time crunch, it might also be the right business decision to release a feature before completing testing, but you need to catch up on testing immediately afterwards. If you delay testing, soon new code will appear on top of the untested code, and features will be released untested, and it will become increasingly difficult to pay off the technical debt and return the team to a well-maintained codebase.
Don’t make surprises
Team members will assume that your code follows common conventions, so you shouldn’t surprise them by deviating from those conventions.
For example, if you write a function isButtonEnabled(), team members will assume that the function is checking for a button and that it will return a Boolean, since most such function names start with “is-“. If your function does something else, it should be clarified in the name.
The length of the name should depend on the scope
For example, variable names like I and j could be used in a for loop, but the name of the global constant should be more precise about its intent.
Functions also need to be readable, not just to avoid repetition
In general, we say that code that is repeated more than three times should be written as a function, but I want to add two more cases where it should be written as a function:
1) When a comment needs to be added to explain the purpose of this code;
2) When more than 3 layers are nested.
For example, suppose I write the following UI functions:
Fun setupViews() {// Set up textView textView.isvisible =... TextView. Text =... ... More textView setup... // Set up imageView. imageview. image =... ImageView. BackgroundColor =... ... More imageView setup... }Copy the code
We should put the corresponding code into the other two functions, setupTextView() and setupImageView(), even if they don’t contain duplicate code.
The code written this way serves as documentation in itself, and if someone needs to modify or debug the imageView, they can go to setupImageView() without reading all the code.
Another common case is the maximum number of lines of code for a function, which can be set arbitrarily, usually in the range of 5 to 100. I personally think that the basic criterion is to read functions without turning the page.
There are many forms of repetition
DRY (Don’t Repeat Yourself) is a well-known software engineering principle. The most common form of duplication is exactly the same code, but some forms of duplication are less obvious, such as implementation duplication.
For example, for a class defined as follows:
class TreeNode {
val value: String
var children: List<TreeNode>
val isLeaf: Boolean
fun addChild(node: TreeNode) {
children.add(node)
isLeaf = false
}
fun removeChild(node: TreeNode) {
children.remove(node)
if (children.isEmpty()) isLeaf = true
}
}
Copy the code
Instead of setting isLeaf every time a Child is updated, you can add fun isLeaf() = children.isempty () so that when you update the class, you don’t have to check whether isLeaf has been updated.
Don’t duplicate the work of others
Before implementing a feature, you should first check to see if the implementation is already in the code base.
For example, if you need to process time, the constant SECONDS_PER_MINUTE might already exist and you can reuse it, rather than defining it multiple times in the same code base.
Learn and follow the programming style of the project
A common set of development guidelines makes it easier for team members to understand each other’s code, as well as for newcomers. Often, the actual rules are not as important as making sure they are followed. For example, I’ve seen some Kotlin where all file names containing extension functions end with “-ext”, while others end with “-s”. The actual selection is not important, but everyone’s selection must be uniform so that the programmer knows where to find Foo’s extension function. Is it in fooext.kt or foos.kt?
Improve code cleanliness with lint rules
If you use Lint in your projects and you often manually tweak formatting or get formatting suggestions during code reviews, then you should consider adding a new Lint rule.
Learning to use an IDE
Modern ides such as Android Studio and VSCode are very powerful. You should learn how to use the various IDE gadgets (such as the debugger), as well as keyboard shortcuts, which takes time but can save you a lot of time in the long run.
You should customize Settings and keyboard shortcuts to optimize your workflow. For example, JetBrains IDE doesn’t offer the “Split Editor TAB” shortcut by default (you have to click Window → Editor Tabs → Split Vertically), but I added a custom shortcut because I use it a lot.
Comments should explain why, not how
Ideally, the code should be self-explanatory and not need to be commented. Programmers often ignore update comments when modifying code. Over time, comments become inaccurate and differ greatly from the actual code. Before you write comments that explain what your code does, consider refactoring your code so it speaks for itself.
However, the code alone is not enough to explain why you chose this approach. Annotations can provide context, such as product requirements to help you make decisions, system constraints, or efficiencies.
Don’t treat your test code like a second-class citizen
When writing production code, you may want to spend some time planning the code to make sure it is in good shape before a feature is released, but programmers often ignore test code as long as it works. However, test code also needs to be maintained, and if it is difficult to understand, this can add to the maintenance burden.
Part of the problem is that test code is generally not subject to rigorous review. People spend a lot of time reviewing production code, but don’t feel the need to test it because it’s already been tested.
Table-driven testing
A few months ago, I discovered Junit’s parameterized tests, which helped me write more thorough tests.
In regular unit tests, there is usually only one test function per input. As a result, many functions have repetitive code, and it’s easy to miss some input. Table-driven tests have a single test function, and a table that contains all possible inputs and expected outputs. You can test all inputs with a single test function.
Adopting a new library is risky
Each library has a pre-release version that is likely to break existing functionality.
In a newly released library, ease of testing may be a secondary concern, and if you want to adopt the new library in a large project, you must verify beforehand that the library will pass your test code and be compatible with production code.
Until a library is widely adopted by the community, it can be difficult to find resources when you run into problems. And perhaps the library will never be widely adopted, and the project itself will be forgotten by the maintainers.
Some libraries seem to be used by everyone, but are they being used in real projects? Or is it just in the demo?
When asking team members for help, focus on their approach, not just the solution
Pay attention to the resources and tools your team members use so that if you face a similar problem in the future, you’ll be better equipped to handle it on your own. It is valuable to discover new resources and tools, such as document resources, Git commands, keyboard shortcuts, and so on.
When reviewers are confused or misunderstand code changes, there is a problem with the code
In addition to responding to review comments, you should consider refactoring or adding comments to clarify. This ensures that others reading this code in the future will not encounter the same confusion.
Read code review comments
When you have trouble understanding a piece of code, read the code review carefully. Reviews of code show what else has changed at the same time, so it is valuable to read them, and they may also contain explanations of the decisions behind the code.
If you are implementing a feature that is very similar to an existing feature, reading code reviews for similar features can help you plan your implementation. For example, if I want to add an Android feature, but iOS or the Web already have it, it’s helpful to see how other platforms implement it.
Study the way you like
In college, aside from what you learned in the classroom, you learned mostly from your side projects, which will help you stand out when it comes to finding a job. But if you’re looking to move on later, you’ll be more likely to get real work experience than your side projects.
In side projects, you can do what you love, and of course you can continue to enjoy those projects! But there are many other ways to learn: reading blogs, watching lectures, taking online courses, listening to podcasts, and so on. You can find your favorite way, or you can use your time outside of work to pursue other interests.
The quality of online resources is uneven
Anyone can publish a technical blog post over the Internet. If you’re trying to learn a new technology from a blog post and it doesn’t make sense, it might just be that the post itself isn’t that good, and you shouldn’t give it up and try another source.
Official resources and tutorials are often a good place to start. Conference presentations and company tech blogs tend to be of high quality because these resources are highly vetted.
The last
Speaking of learning resources, here are some of the sites I visit and many of the guidelines for this article:
- Refactoring Guru: A web site that explains how to write and refactor clean code.
- Clean Code: The classic software engineering book. Some of this is a bit dated and overlaps with Refactoring Guru, but it’s still worth reading.
- Martin Fowler’s Website: The author has written many books on software development, and his website has a lot of information on software architecture and refactoring.
- Android Weekly Newsletter: A Weekly magazine with a selection of technical articles, podcasts, and talks. Android only, but there are similar weeklies for other platforms.
- Yelp Android School: GitHub repository for tech talks Half are Android focused, and half are software engineering.
If you want to learn more about programming, check out the following figure for more details