Why Clean Code Matters: Practical Tips for Naming, Classes, Functions & Testing
This article explains why clean, well‑structured code is essential for productivity, outlines best practices for naming, class design, function implementation, and testing, and provides concrete examples and refactoring techniques to help developers write maintainable software.
1. Why Keep Code Clean?
Unclean code reduces productivity as a project ages, leading to hard‑to‑extend code, crashes, overtime, higher hiring costs, and even company failure.
Code becomes difficult to extend and may cause other issues.
Program crashes.
Overtime.
Increased company cost (additional hires) – it can even lead to bankruptcy.
1.1 Start Clean from the Beginning
Write clean code from the start and refactor any untidy code immediately; never adopt a "fix it later" mindset. later equal never If you keep postponing, you’ll accumulate a lot of technical debt.
If something must be done, do it early.
1.2 How to Write Clean Code?
Clean code should be highly readable, avoid duplication, and follow design‑pattern principles such as:
Single Responsibility
Open‑Closed Principle
Liskov Substitution
Dependency Inversion
Interface Segregation
Law of Demeter
Composition over Inheritance
2. Naming
Good names improve readability, reduce understanding cost, and increase efficiency.
2.1 Bad Naming Practices
Meaningless names
public interface Animal {
void abc();
}The method abc() gives no clue about its purpose.
Better naming:
public interface Animal {
void cry();
}Now callers understand the method’s intent.
Names must be meaningful and self‑explanatory.
Inconsistent naming across similar operations
public interface StudentRepository extends JpaRepository<AlertAll, String> {
Student findOneById(@Param("id") String id);
List<Student> queryAllStudent();
}Both methods query students but use different verbs. After standardisation:
public interface StudentRepository extends JpaRepository<AlertAll, String> {
Student findOneById(@Param("id") String id);
List<Student> findAll();
}Redundant naming (e.g., adding "Variable" or "Table" unnecessarily)
// Use concise prefixes
getXxx(); // single object
listXxx(); // multiple objects3. Classes
Clean classes should satisfy:
Single Responsibility
Open‑Closed Principle
High Cohesion
3.1 Single Responsibility
A class should be small and have only one reason to change. Large classes usually have too many responsibilities.
Reduced complexity
Improved readability
Better maintainability
Lower risk of change‑induced bugs
How to determine if a class is short enough?
If a class’s name cannot accurately describe its sole responsibility, it is likely too large.
Example of a class with multiple responsibilities:
public abstract class Sql {
// SQL operation
public abstract void insert();
// Statistics operation
public abstract void countInsert();
}Refactor by extracting the statistics responsibility:
public abstract class CountSql {
public abstract void countInsert();
}3.2 Open‑Closed Principle
Software should be open for extension but closed for modification. Adding new logic should not require changing existing code.
Violating example:
public abstract class Sql {
public abstract void insert();
public abstract void update();
public abstract void delete();
}To add a query operation, the class must be modified.
Refactored version:
public abstract class Sql {
public abstract void generate();
}
public class CreateSql extends Sql {
@Override
public void generate() {
// implementation
}
}
public class UpdateSql extends Sql {
@Override
public void generate() {
// implementation
}
}Imagine a toolbox with many drawers, each holding well‑defined components, rather than a few large drawers where everything is thrown together.
3.3 Cohesion
High cohesion means a class’s methods operate on a shared set of variables, forming a logical whole.
Why maintain high cohesion?
High cohesion leads to many small classes, each fulfilling a single responsibility.
What if cohesion is low?
Split the class into smaller, more focused classes and methods.
4. Functions
Clean functions should:
Do one thing
Have good names
Have tidy parameters
Handle return values properly
4.1 Do One Thing
A function should be short and focused on a single responsibility.
Before refactoring, a method may handle validation, compression, and result reporting in 135 lines:
public class PicService {
public String upload(){
// validate image (80 lines)
// compress image (50 lines)
// return status (5 lines)
return "0";
}
}After refactoring:
public String upload(){
check(); // validation
compress(); // compression
return "0"; // result
}4.2 Function Naming
1. Names Should Be Self‑Explanatory
Bad example:
public String addCharacter(String originString, char ch);The name does not indicate whether the character is added at the start, end, or a specific position.
Better examples:
// Append to the end
public String appendCharacter(String originString, char ch);
// Insert at a specific position
public String insertCharacter(String originString, char ch, int insertPosition);2. Functions Should Have No Side Effects
If a function performs an unrelated side effect (e.g., initializing a session while checking a password), the side effect should be reflected in the name or separated into another method.
4.3 Parameters
1. Fewer Parameters Are Better
When a method has more than three parameters, consider encapsulating them into a meaningful object.
public List<Student> findStudent(int age, String name, String country, int gender);
// Encapsulated version
public List<Student> findStudent(StudentCriteria criteria);2. Avoid Boolean Flags
Boolean flags create two distinct code paths inside one method, violating single responsibility. Split into two methods instead.
// Flag version
render(Boolean isSuite);
// Refactored
renderForSuite();
renderForSingleTest();3. Avoid Output Parameters
Returning results via modified parameters adds cognitive load. Prefer returning the result directly.
public void findStudent(){
Student student = new Student();
doSomething(student);
return student;
}4.4 Return Values
1. Separate Commands from Queries
Do not combine an action and a boolean result in one method.
public Boolean addElement(Element element);Refactor to:
public void addElement(Element element);
public Boolean isAdded(Element element);2. Use Exceptions Instead of Error Codes
Throwing exceptions reduces nested error‑handling code.
// Before: many nested if‑else checks
if (handle != DeviceHandle.INVALID) {
// ...
} else {
logger.log("Invalid handle");
}
// After: exception handling
try {
tryToShutDown();
} catch (DeviceShutDownError e) {
logger.log(e);
}4.5 How to Write Such Functions?
Start with a working implementation, then refactor immediately to improve structure.
Later equals never!
4.6 Code Quality Scanning Tools
Tools like SonarLint can automatically detect issues such as duplicated code, potential null‑pointer exceptions, deep nesting, and suggest fixes, helping quantify metrics like bug rate and duplication.
5. Testing
Testing verifies that code works correctly; test code itself should also be clean.
5.1 Test‑Driven Development (TDD)
TDD is a core agile practice that drives design by writing failing tests before production code.
Pros: Early usable product, fewer bugs.
Cons: Test code can be twice or more the size of production code, but saves debugging time.
5.2 FIRST Principles
Fast – tests run quickly.
Independent – tests do not depend on each other.
Repeatable – tests run the same everywhere.
Self‑validating – tests assert results automatically.
Timely – tests are written before production code.
5.3 Test Code Patterns
Use the given‑when‑then pattern for readable tests.
/**
* If an item is loaded from the repository, its name should be transformed to uppercase.
*/
@Test
public void shouldReturnItemNameInUpperCase() {
// Given
Item mockedItem = new Item("it1", "Item 1", "This is item 1", 2000, true);
when(itemRepository.findById("it1")).thenReturn(mockedItem);
// When
String result = itemService.getItemNameUpperCase("it1");
// Then
verify(itemRepository, times(1)).findById("it1");
assertThat(result, is("ITEM 1"));
}5.4 Automatic Test Generation
Two IDE plugins can generate unit tests automatically:
SquareTest (paid)
TestMe (free)
6. Conclusion
Writing clean code improves readability, extensibility, development efficiency, reduces overtime, and raises a developer’s skill level.
Every developer should read "Clean Code" to enhance coding ability and mindset.
Remember: write clean code early; don’t rely on later fixes.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java High-Performance Architecture
Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
