Cleaning Up Code: Not Just About Refactoring Part 2
- Mariusz Sieraczkiewicz
- Software development , Code quality
- June 18, 2008
Table of Contents
Due to formatting problems with code on Blogspot, it is recommended to read this article in PDF format. You can download the PDF version of the article here.
Introduction
We have taken the first step towards organizing the initial code. Let’s take another. Let’s examine the following snippet:
public class ExtendedBitSet extends BitSet {
int length;
The length
field of the class is package-visible. This was probably not the author’s intention. They might have forgotten to explicitly write the appropriate access modifier. In any case, one should be aware of a fundamental consequence of this solution: this field will be accessible to all classes in the package, which limits its information encapsulation. This situation can be generalized to the statement:
Apply the most restrictive possible access modifiers.
In this case, it would obviously be the private modifier:
private int length;
When creating a class that will be the base for other classes and there is a need to expose this field, the protected
access modifier should be used:
protected int length;
However, it is good practice to choose the private
modifier until there is a need to use this field in a subclass (i.e., during the derivation of new classes). This is analogous to the typical security strategy for network administrators: block by default.
Explicit Initialization of Fields and Variables
Besides the above remarks, I would like to propose one more improvement. I am an advocate of explicitly initializing variables because it clearly reveals the author’s intention. If I create an object field, I explicitly assign it an initial value of null. When I create an integer, I initialize it with zero. This way, I save potential readers of my code the guesswork of whether I meant the default value or if, perhaps not knowing the language details, I assumed something incorrect. This can be significant when debugging errors.
To summarize:
Explicitly initialize fields and variables.
As a result, we will obtain such a solution:
private int length = 0;
Create Space for Readability
Our vision likes space. It does not like cramped sentences, vast amounts of expressions in a small space. Do a simple experiment. Take a small fragment of your code and add some spaces (between operators, between lines) and compare which version is more readable. Here is an example:
public byte[] toByteArray() {
int bytesNumber;
if(length % 8 == 0) bytesNumber = length / 8;
else bytesNumber = length / 8 + 1;
byte[] arr = new byte[bytesNumber];
for(int j = bytesNumber - 1, k = 0; j >= 0 ; j--, k++) {
for(int i = j * 8 ; i < (j + 1) * 8; i++){
if(i == length) break;
if(get(i)) arr[k] += (byte)Math.pow(2, i % 8);
}
}
return arr;
}
And the spaced version:
public byte[] toByteArray() {
int bytesNumber = 0;
if ( length % 8 == 0 ) {
bytesNumber = length / 8;
} else {
bytesNumber = length / 8 + 1;
}
byte[] arr = new byte[bytesNumber];
for( int j = bytesNumber - 1, k = 0; j >= 0; j--, k++ ) {
for( int i = j * 8; i < (j + 1) * 8; i++ ) {
if ( i == length ) {
break;
}
if ( get(i) ) {
arr[k] += (byte) Math.pow(2, i % 8);
}
}
}
return arr;
}
This modification took me about two minutes. However, the ability to create code consistent with the coding style, which is my habit, allows me to write such code without any additional time overhead. And what a pleasure to read!
Consistent Coding Standards
I cannot imagine creating code that does not adhere to pre-established rules. When it comes to team work, it is an essential condition for group work. We have great support since there are many ready-to-use standards, e.g., Code Conventions for the Java Programming Language, and tools that will help us, especially in the initial period, to diligently adhere to them (Checkstyle).
Below is an example of the discussed class formatted according to the standard based on the one proposed by Sun.
public class ExtendedBitSet extends BitSet {
private int length = 0;
public ExtendedBitSet( int size, String str ) {
super( size );
length = size;
int strLength = str.length();
for( int i = 0; i < strLength; ++i ) {
if ( str.charAt( strLength - 1 - i ) == '1' ) {
set( i );
}
}
}
// Other methods and constructor omitted for brevity
}
Returning to our field length
, it really has another drawback - its name is exactly the same as the name of a method from the superclass. This is a disadvantageous situation for two reasons:
- Two different entities should not have the same name (method and field) because it can lead to confusion.
- The variable’s name does not reflect the property’s essence. This field holds a value that determines the fixed length of the bit vector. For example, the name
fixedLength
would make much more sense.
Let’s change the name of the field length
to fixedLength
.
To summarize the above considerations:
Do not use the same name for different purposes.
Assign names to fields, methods, and classes that unambiguously reflect their meaning.
Avoid Repetition
Analyzing further, let’s look at both constructors, and we’ll clearly notice a property - there is a lot of repeated code there. This brings us to a rule that is the essence of refactoring:
Eliminate all repetitions.
Repetitions are the evil that accompanies programmers at every step. Tempting copy-paste often leads to time-consuming or, worse, hours-long searches for bugs resulting from the desynchronization of similar code fragments. Repetitions in the long run are unsustainable, hence their elimination is the primary goal of all refactorings. We can change the sample code to the following form:
public ExtendedBitSet(int size, String str) {
super(size);
fixedLength = size;
initializeBitSet(str);
}
public ExtendedBitSet(String str) {
this(str.length(), str);
initializeBitSet(str);
}
private void initializeBitSet(String str) {
int strLength = str.length();
for (int i = 0; i < strLength; ++i) {
if (str.charAt(strLength - 1 - i) == '1') {
set(i);
}
}
}
The code is slowly organizing and looking better. We’ve made changes related to appearance (coding standards and space), eliminated some repetitions, and resolved ambiguities. Of course, it’s always important to weigh the degree of refactoring or beautifying the code so as not to become a victim of perfectionism. It is worth seeking the help of other programmers, preferably those who themselves follow certain rules and have significant experience, and ask for an opinion. You will surely learn a lot about your programming.
(Text translated and moved from original old blog automatically by AI. May contain inaccuracies.)