Fundamentals 13 min read

16 Essential Coding Habits Every Developer Should Master

This article presents sixteen practical coding habits—from self‑testing and parameter validation to thread‑pool usage and cache consistency—that help developers avoid common bugs, improve reliability, and write cleaner, production‑ready code across backend systems.

Java Backend Technology
Java Backend Technology
Java Backend Technology
16 Essential Coding Habits Every Developer Should Master

1. Self‑test after modifying code

Always run a quick test after changing code, even if you only altered a variable or a single configuration line, to catch regressions early.

2. Validate method parameters

Check inputs for nullability, length, and format before processing; unvalidated parameters often cause simple bugs such as database insertion errors.

3. Consider interface compatibility when updating old APIs

When extending an existing public interface, preserve backward compatibility (e.g., add new parameters while keeping old ones functional).

// old interface
void oldService(A, B) {
    // compatible with new interface, pass null for C
    newService(A, B, null);
}

// new interface (cannot remove old one immediately)
void newService(A, B, C);

4. Add clear comments for complex logic

When business logic is intricate, write explicit comments to aid future maintenance.

5. Close IO streams after use

Never leave file or network streams open; use finally blocks or try‑with‑resources to release resources promptly.

FileInputStream fdIn = null;
try {
    fdIn = new FileInputStream(new File("/jay.txt"));
} catch (FileNotFoundException e) {
    log.error(e);
} catch (IOException e) {
    log.error(e);
} finally {
    try {
        if (fdIn != null) {
            fdIn.close();
        }
    } catch (IOException e) {
        log.error(e);
    }
}

Since JDK 7, prefer try‑with‑resources:

try (FileInputStream inputStream = new FileInputStream(new File("jay.txt"))) {
    // use resources
} catch (FileNotFoundException e) {
    log.error(e);
} catch (IOException e) {
    log.error(e);
}

6. Guard against runtime errors (array bounds, division by zero, null pointers)

Check collections size before accessing elements and validate inputs to prevent common exceptions.

// risky code
String name = list.get(1).getName(); // may cause IndexOutOfBoundsException

Safe version:

if (CollectionsUtil.isNotEmpty(list) && list.size() > 1) {
    String name = list.get(1).getName();
}

7. Batch remote/database calls instead of looping individual requests

Network and IO operations are expensive; prefer a single batch query over many per‑iteration calls.

// good
remoteBatchQuery(param);
// bad
for (int i = 0; i < n; i++) {
    remoteSingleQuery(param);
}

8. Think about concurrency consistency when code runs in multiple threads

Operations that are not atomic (e.g., check‑then‑update) can cause race conditions; use atomic DB updates or proper locking.

// unsafe
if (isAvailable(ticketId)) {
    // add cash
    deleteTicketById(ticketId);
}

Safe version using atomic delete:

if (deleteAvailableTicketById(ticketId) == 1) {
    // add cash
} else {
    return "No available ticket";
}

9. Null‑check objects before accessing their properties

Never assume an object is non‑null; guard with an if‑statement to avoid NullPointerException.

if (object != null) {
    String name = object.getName();
}

10. Use appropriate thread pools and consider isolation

Thread pools reduce creation overhead, improve response time, and enable resource reuse; allocate separate pools for critical business flows.

11. Run SQL statements in the database and examine the execution plan

Before deploying, execute your queries and use EXPLAIN to verify index usage and performance.

EXPLAIN SELECT * FROM user WHERE userid = 10086 OR age = 18;

12. Handle exceptions, timeouts, and retries when calling third‑party APIs

Set connection timeouts, decide retry policies, and for sensitive services add signature verification and encryption.

13. Ensure API idempotency

Design APIs so that repeated identical requests have the same effect, using techniques such as unique indexes, tokens, or distributed locks.

14. Consider linear safety of collections in high‑concurrency scenarios

Non‑thread‑safe structures like HashMap can cause dead loops; prefer ConcurrentHashMap or other safe collections.

15. Account for master‑slave replication lag

When reading after a write, be aware that the slave may not have caught up; critical paths may need to read from the master.

16. Keep cache and DB consistency; guard against cache penetration, avalanche, and breakdown

Cache improves latency but requires strategies to stay consistent with the database and to prevent massive cache misses from overwhelming the DB.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Backend DevelopmentSoftware Engineeringcoding habits
Java Backend Technology
Written by

Java Backend Technology

Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.