Avoiding Unnecessary Comments

15 min read

Clean Code and Readability — review Java comments that only restate statements instead of adding information the code cannot express.

1. Introduction

Comments are useful when they explain information that cannot be understood clearly from the code itself. However, excessive or unnecessary comments make Java code harder to read rather than easier.

In real company projects, developers frequently add comments such as:

JAVA
// Get customer
Customer customer = customerRepository.findById(customerId).orElseThrow();

// Check if customer is active
if (customer.isActive()) {
    processCustomer(customer);
}

These comments do not provide new information. They simply repeat what the Java statements already communicate.

Unnecessary comments increase visual noise, create additional maintenance work, and can become incorrect when the code changes.

A clean codebase should rely primarily on:

  • Meaningful variable names
  • Clear method names
  • Small focused methods
  • Proper abstractions
  • Straightforward control flow
  • Appropriate types

Comments should be added only when they provide useful context that cannot reasonably be expressed through the code.

During Pull Request review, reviewers should therefore ask not only:

"Is a comment needed?"

but also:

"Can this comment be removed by making the code clearer?"

2. What This Topic Means

Avoiding unnecessary comments means removing comments that merely describe obvious Java statements or compensate for unclear code.

Consider:

JAVA
// Create payment request
PaymentRequest request = new PaymentRequest(orderId, amount);

The variable and class names already explain what is happening.

The comment adds no useful information.

Instead, comments should provide information such as:

  • Why a specific implementation exists
  • Why a business rule behaves unexpectedly
  • Why an external API requires a workaround
  • Why a performance optimization is necessary
  • Why a concurrency-related implementation must not be simplified
  • Why temporary compatibility logic exists

For example:

JAVA
// Partner gateway rejects requests older than five minutes, so regenerate the timestamp before retrying.
paymentRequest.refreshTimestamp();

This comment provides context that is not obvious from the method call itself.

The objective is not to eliminate all comments.

The objective is to eliminate comments that do not add meaningful information.

3. Why It Matters in Real Projects

Readability

Too many comments interrupt the natural flow of code.

A developer should be able to scan a method and understand its behavior without reading a comment before every statement.

Maintainability

Every comment becomes another piece of information that must be kept synchronized with the code.

When code changes but comments remain unchanged, developers may receive conflicting information.

Debugging

Outdated comments can mislead developers during production incident investigation.

A developer may trust the comment instead of verifying the actual code behavior.

Reliability

Incorrect comments can result in unsafe modifications when developers misunderstand business or technical behavior.

Team Development

Large development teams frequently modify the same services over several years.

Reducing low-value comments makes genuinely important comments easier to notice.

4. Core Concept

The key principle is:

Prefer self-explanatory code over comments that explain obvious implementation details.

Comments should not be used as a substitute for:

  • Better variable names
  • Better method names
  • Smaller methods
  • Better class design
  • Proper enums
  • Domain-specific types
  • Clear exception handling

For example:

Bad:

JAVA
// Check if status is 1
if (order.getStatus() == 1) {
    process(order);
}

Better:

JAVA
if (order.getStatus() == OrderStatus.READY_FOR_PROCESSING) {
    process(order);
}

The better implementation removes the need for the comment entirely.

Another example:

Bad:

JAVA
// Calculate final price
BigDecimal x = p.subtract(d).add(t);

Better:

JAVA
BigDecimal finalPrice = productPrice
        .subtract(discountAmount)
        .add(taxAmount);

The code itself should communicate normal application behavior.

5. Important Rules

  • Do not comment obvious Java statements.
  • Do not explain meaningful method names with comments.
  • Do not use comments to compensate for poor variable names.
  • Do not add comments before every if, loop, repository call, or return statement.
  • Remove commented-out production code.
  • Avoid comments documenting source-control history.
  • Avoid developer-name comments.
  • Remove comments that are no longer accurate.
  • Prefer extracting complicated logic into a clearly named method.
  • Use constants and enums instead of comments explaining magic values.
  • Keep comments that explain important business reasons.
  • Keep comments that explain external-system limitations.
  • Keep comments that document non-obvious concurrency assumptions.
  • Keep comments that explain counter-intuitive performance optimizations.
  • Never store sensitive production data or credentials inside comments.
  • Review comments whenever the related code changes.

6. Bad Code Example

Consider a Spring Boot customer-account service.

JAVA
@Service
public class CustomerAccountService {
    private final CustomerRepository customerRepository;
    private final NotificationService notificationService;

    public CustomerAccountService(CustomerRepository customerRepository, NotificationService notificationService) {
        this.customerRepository = customerRepository;
        this.notificationService = notificationService;
    }

    public void deactivateCustomer(Long id) {
        // Find customer by ID
        Customer c = customerRepository.findById(id).orElseThrow();

        // Check if customer is already inactive
        if (!c.isActive()) {
            // Return if inactive
            return;
        }

        // Set active false
        c.setActive(false);

        // Save customer
        customerRepository.save(c);

        // Send notification
        notificationService.sendAccountDeactivatedNotification(c);

        // TODO check later

        // customerRepository.flush();
    }
}

The method contains many comments, but almost none provide useful information.

7. Problems in the Bad Code

Redundant Comments

Comments such as:

JAVA
// Find customer by ID

// Save customer

// Send notification

simply repeat the statements below them.

Weak Variable Naming

The variable:

JAVA
Customer c

is unnecessarily abbreviated.

A meaningful name such as:

JAVA
Customer customer

makes the code clearer without comments.

Comment Explaining Control Flow

This comment:

JAVA
// Return if inactive

adds no information because the return statement is obvious.

Weak TODO

JAVA
// TODO check later

does not explain:

  • What needs to be checked
  • Why it matters
  • Who should address it
  • Whether it is tracked
  • What production behavior may be affected

Commented-Out Code

JAVA
// customerRepository.flush();

is dead code.

Source control already preserves previous implementations.

Missing Domain-Specific Exception

orElseThrow() generates a generic exception rather than communicating a meaningful application failure.

8. Code Review Findings

A senior Java reviewer should identify the following:

  • Most comments simply translate Java statements into English.
  • The code would be clearer with better variable naming.
  • Several comments should be deleted rather than improved.
  • The TODO is not actionable.
  • Commented-out repository code should not remain in production source.
  • Customer-not-found behavior should be explicit.
  • The method should communicate business intent through code first.
  • No genuinely complex business behavior exists that requires this many comments.

The reviewer should avoid requesting additional comments.

The correct recommendation is to simplify the source and remove unnecessary documentation.

9. Reviewer Comment Example

A professional Pull Request comment could be:

Most of these comments repeat what the code already expresses. Could we remove them and use a more descriptive variable name such as customer instead of c?

Another review comment:

Please remove the commented-out flush() call. Git history already preserves previous implementations, and keeping dead code here creates unnecessary noise.

For the TODO:

Can we either link this TODO to a tracked issue and explain the expected follow-up, or remove it if no concrete action is required?

10. Improved Code

JAVA
@Service
public class CustomerAccountService {
    private final CustomerRepository customerRepository;
    private final NotificationService notificationService;

    public CustomerAccountService(CustomerRepository customerRepository, NotificationService notificationService) {
        this.customerRepository = customerRepository;
        this.notificationService = notificationService;
    }

    public void deactivateCustomer(Long customerId) {
        Customer customer = customerRepository.findById(customerId)
                .orElseThrow(() -> new CustomerNotFoundException(customerId));

        if (!customer.isActive()) {
            return;
        }

        customer.deactivate();
        customerRepository.save(customer);
        notificationService.sendAccountDeactivatedNotification(customer);
    }
}

The improved implementation does not need comments because the code communicates the behavior clearly.

11. Improved Code Explanation

Better Parameter Name

id became:

JAVA
customerId

This gives immediate domain context.

Better Variable Name

c became:

JAVA
customer

No comment is required to explain what the variable represents.

Domain-Specific Exception

Instead of:

JAVA
orElseThrow()

the code now throws:

JAVA
CustomerNotFoundException

This makes failure behavior clearer.

Domain Method

Instead of:

JAVA
customer.setActive(false);

the code uses:

JAVA
customer.deactivate();

This expresses business intent rather than exposing a low-level state mutation.

Redundant Comments Removed

The implementation is now easier to scan because each statement is self-explanatory.

Dead Code Removed

The commented-out flush() statement no longer distracts future developers.

12. Bad Code vs Improved Code

AreaBad CodeImproved Code
ReadabilityMany comments interrupt code flowCode explains itself
MaintainabilityComments must be updated with codeLess duplicated information
TestabilitySimilar behaviorClearer domain operations simplify test intent
ReliabilityGeneric exception and vague TODOExplicit failure behavior
ReviewabilityReviewer must inspect comment noiseBusiness behavior is immediately visible

Performance is effectively unchanged because removing comments does not alter runtime execution.

The improvement is primarily in readability and maintainability.

13. Real Project Scenario

Consider an e-commerce inventory microservice.

A developer writes:

JAVA
// Loop through products
for (Product product : products) {
    // Check stock
    if (product.getAvailableQuantity() > 0) {
        // Add product
        availableProducts.add(product);
    }
}

Every comment is unnecessary.

The code already describes the operation.

A cleaner implementation could be:

JAVA
List<Product> availableProducts = products.stream()
        .filter(Product::isAvailable)
        .toList();

Or, when a loop is clearer:

JAVA
for (Product product : products) {
    if (product.isAvailable()) {
        availableProducts.add(product);
    }
}

Now suppose an unusual rule exists:

JAVA
// Marketplace listings must remain visible for 10 minutes after stock reaches zero because partner inventory updates are eventually consistent.
if (product.hasRecentlyReachedZeroStock()) {
    keepListingVisible(product);
}

That comment is useful because it explains a non-obvious business reason.

The distinction is important.

Normal code does not need narration.

Unexpected behavior may need explanation.

14. Production Impact

Unnecessary comments usually do not directly cause application failures, but they create long-term engineering risks.

Difficult Maintenance

Large classes containing hundreds of redundant comments become slower to understand.

Outdated Documentation

Code may change while comments remain unchanged.

For example:

JAVA
// Retry three times
for (int attempt = 0; attempt < 5; attempt++) {
    retryRequest();
}

A future developer now receives contradictory information.

Incorrect Debugging

During an incident, developers may rely on inaccurate comments and investigate the wrong behavior.

Hidden Important Information

If every statement has a comment, genuinely important comments are difficult to notice.

Unsafe Refactoring

A misleading comment may cause developers to preserve incorrect logic or modify correct logic based on outdated assumptions.

15. Common Developer Mistakes

Commenting Every Statement

Example:

JAVA
// Create request
PaymentRequest request = createRequest();

// Validate request
validate(request);

// Process request
process(request);

These comments provide no additional value.

Writing Comments Instead of Renaming Variables

Bad:

JAVA
// Customer email
String e = customer.getEmail();

Better:

JAVA
String customerEmail = customer.getEmail();

Explaining Magic Values With Comments

Bad:

JAVA
if (retryCount > 5) { // Maximum retries
    fail();
}

Better:

JAVA
private static final int MAX_RETRY_ATTEMPTS = 5;

if (retryCount > MAX_RETRY_ATTEMPTS) {
    fail();
}

Commenting Closing Braces

Avoid unnecessary constructs such as:

JAVA
} // end if

} // end method

Well-structured Java code should make scopes easy to understand.

Keeping Old Implementations as Comments

Bad:

JAVA
// oldPaymentService.process(payment);
newPaymentService.process(payment);

Delete the old implementation.

Writing Author Comments

Avoid:

JAVA
// Added by Dattatray on 08-08-2026

Source control already records this information.

Writing Change History Inside Classes

Avoid source comments containing a manual change log.

Use:

  • Git history
  • Pull Requests
  • Jira
  • Azure Boards
  • Issue trackers

Using Comments to Explain Large Methods

If a method requires comments such as:

JAVA
// Step 1
// Step 2
// Step 3
// Step 4

it may indicate that the method should be decomposed into smaller methods.

16. Edge Cases

Traditional runtime edge cases are not directly created by unnecessary comments, but reviewers should consider maintenance-related edge cases.

Comment Becomes Outdated

The most common issue occurs when behavior changes without updating the comment.

Business Rule Changes

A comment may describe an old business policy that is no longer valid.

Temporary Workarounds

A comment describing temporary logic can become permanent unless the removal condition is clear.

External Integration Changes

A comment describing an API limitation may become invalid after a vendor upgrade.

Concurrency Logic

Removing a comment explaining thread-safety assumptions may make future refactoring dangerous.

Therefore, the objective is not automatic comment deletion.

Reviewers must distinguish unnecessary comments from comments containing essential context.

17. Performance Considerations

Comments do not meaningfully affect Java runtime performance because comments are removed during compilation and are not executed by the JVM.

Therefore, unnecessary comments are primarily a readability and maintenance issue rather than a performance issue.

However, comments may legitimately explain performance-sensitive implementation decisions.

For example:

JAVA
// Fetch only IDs because loading full entities here previously caused excessive heap usage during the nightly 3M-record batch.
List<Long> customerIds = customerRepository.findInactiveCustomerIds();

This comment is useful.

Without the explanation, a future developer may replace the optimized projection with a full entity query.

Avoid comments such as:

JAVA
// This is faster

Instead, explain the actual reason:

  • Large dataset
  • Database round trips
  • Vendor throttling
  • Heap usage
  • Query-plan behavior
  • Measured latency

18. Security Considerations

Unnecessary comments can become a security issue when developers place sensitive data inside them.

Never commit comments containing:

  • Passwords
  • API keys
  • JWT secrets
  • Database credentials
  • Private keys
  • Access tokens
  • Real customer records
  • Internal security bypass instructions

Bad:

JAVA
// Temporary production password: Prod@123

Deleting such a comment later may not completely solve the problem because the secret could remain in Git history.

The credential should be rotated.

Comments can still be useful for security-sensitive design decisions.

Example:

JAVA
// Tenant ID must come from the authenticated principal, never from request payload data.
String tenantId = currentUser.getTenantId();

This comment explains an important authorization rule.

19. Testing Considerations

Removing unnecessary comments normally does not require new tests because comments are not executable.

However, refactoring code to make it self-explanatory may involve:

  • Renaming methods
  • Extracting methods
  • Introducing domain methods
  • Replacing magic values with constants
  • Simplifying conditions

Existing tests should confirm that business behavior remains unchanged.

Unit Tests

Verify important business behavior.

For the customer-deactivation example:

  • Active customer becomes inactive.
  • Already inactive customer is ignored.
  • Missing customer produces the expected exception.
  • Notification is sent after successful deactivation.

Integration Tests

Where repository behavior matters, verify persistence state using an integration test.

Important Principle

Comments should never replace tests.

Bad:

JAVA
// Customer cannot be null here.

Better:

Define and test the actual contract.

20. Refactoring Guidelines

When removing unnecessary comments from existing Java code:

  1. Read the comment and associated implementation.
  2. Determine whether the comment explains what or why.
  3. Do not immediately delete comments explaining important business context.
  4. Rename unclear variables.
  5. Rename unclear methods.
  6. Extract complicated blocks into focused methods.
  7. Replace magic numbers with named constants.
  8. Replace primitive status codes with enums where appropriate.
  9. Remove commented-out code.
  10. Remove manual source-history comments.
  11. Verify old TODOs against the issue tracker.
  12. Run automated tests after structural refactoring.
  13. Review Git history if a strange comment appears to protect unusual production behavior.
  14. Keep comments that document genuinely non-obvious constraints.

The safest approach is:

Improve the code first, then evaluate whether the comment is still necessary.

21. Best Practices

Use Meaningful Names

Instead of:

JAVA
// Calculate customer discount
BigDecimal d = calculate(c);

Use:

JAVA
BigDecimal customerDiscount = calculateDiscount(customer);

Extract Methods Instead of Writing Section Comments

Instead of:

JAVA
// Validate request
...

// Create payment
...

// Save payment
...

use:

JAVA
validatePaymentRequest(request);
Payment payment = createPayment(request);
paymentRepository.save(payment);

Use Domain Methods

Instead of:

JAVA
// Mark invoice as paid
invoice.setStatus(InvoiceStatus.PAID);

prefer:

JAVA
invoice.markAsPaid();

when the domain model supports the behavior.

Replace Magic Values

Instead of:

JAVA
if (attempts == 3) { // Max retry count
    return;
}

prefer:

JAVA
private static final int MAX_RETRY_ATTEMPTS = 3;

Explain Genuine Constraints

Keep comments explaining information such as:

JAVA
// Vendor accepts no more than 100 customer IDs per API request.
List<List<Long>> batches = partition(customerIds, 100);

Review Comments Like Code

Comments should be checked for:

  • Accuracy
  • Relevance
  • Security
  • Maintainability
  • Continued necessity

22. Practices to Avoid

Narrating Java Syntax

Avoid:

JAVA
// Increment count
count++;

The code is obvious.

Comments Before Clear Method Calls

Avoid:

JAVA
// Validate order
validateOrder(order);

The method name already explains the action.

Commented-Out Code

Avoid:

JAVA
// oldRepository.save(entity);

Delete it.

Vague TODOs

Avoid:

JAVA
// TODO improve

No developer knows what "improve" means.

Manual History

Avoid:

JAVA
// Changed by John
// Modified by Mike
// Fixed by Sarah

Use Git.

Comments Explaining Poor Names

Avoid:

JAVA
String x; // Customer account number

Rename the variable.

Long Comments Hiding Poor Design

If a comment needs several paragraphs to explain a method's flow, consider restructuring the method.

Duplicate Javadoc

Avoid:

JAVA
/**
 * Gets customer name.
 * @return customer name
 */
public String getCustomerName() {
    return customerName;
}

Unless the API contract contains non-obvious information, this documentation adds little value.

23. Code Review Checklist

  • Does this comment provide information that the code cannot communicate clearly?
  • Is the comment merely describing the statement below it?
  • Could better variable naming eliminate this comment?
  • Could a better method name eliminate this comment?
  • Could extracting a method remove the need for this explanation?
  • Is the comment still accurate?
  • Does the comment explain why rather than what?
  • Is there commented-out code that should be deleted?
  • Does the TODO contain actionable information?
  • Should the TODO reference a tracked issue?
  • Is source-control history being duplicated inside the source file?
  • Are developer names or dates unnecessarily stored in comments?
  • Does any comment contain sensitive information?
  • Are magic values being explained through comments instead of constants?
  • Are status codes being explained instead of represented by enums?
  • Is an important business constraint being lost if this comment is removed?
  • Is a performance optimization documented only where genuinely needed?
  • Are concurrency assumptions documented where appropriate?
  • Are external API limitations clearly explained?
  • Would the code remain understandable if this unnecessary comment were deleted?

24. Common Pull Request Review Comments

  1. *This comment repeats what the method name already communicates. Can we remove it?*
  1. *Could we rename c to customer instead of relying on the comment to explain the variable?*
  1. *The implementation is clear without this comment. Removing it would reduce noise and maintenance overhead.*
  1. *Please remove the commented-out code. Git history already preserves the previous implementation.*
  1. *Can we replace this magic value with a named constant instead of explaining it through a comment?*
  1. *This TODO is not actionable. Please reference the tracking issue and describe the required follow-up.*
  1. *The comment no longer matches the current condition. Please update or remove it so it does not mislead future maintainers.*
  1. *These section comments suggest that this method may be doing too much. Could we extract these blocks into well-named methods?*
  1. *Please avoid adding the developer name/date here; Git already tracks authorship and change history.*
  1. *This comment explains an important vendor limitation and is useful. Please keep it, but consider adding the related ticket/reference for additional context.*

25. Code Review Exercise

Review the following Spring Boot payment-processing code.

Identify:

  • Unnecessary comments
  • Poor naming
  • Code smells
  • Maintainability problems
  • Potential risks
  • Better refactoring opportunities

Do not reveal the solution until completing your review.

JAVA
@Service
public class PaymentProcessor {
    private final PaymentRepository paymentRepository;
    private final PaymentGateway paymentGateway;

    public PaymentProcessor(PaymentRepository paymentRepository, PaymentGateway paymentGateway) {
        this.paymentRepository = paymentRepository;
        this.paymentGateway = paymentGateway;
    }

    public void process(Long id) {
        // Get payment
        Payment p = paymentRepository.findById(id).orElseThrow();

        // Check if payment is already processed
        if (p.getStatus() == PaymentStatus.COMPLETED) {
            // Return
            return;
        }

        // Maximum retry count
        int x = 3;

        // Try payment three times
        for (int i = 0; i < x; i++) {
            // Call gateway
            PaymentResponse r = paymentGateway.charge(p);

            // Check success
            if (r.isSuccessful()) {
                // Set status
                p.setStatus(PaymentStatus.COMPLETED);

                // Save
                paymentRepository.save(p);

                // Return
                return;
            }
        }

        // Set failed
        p.setStatus(PaymentStatus.FAILED);

        // Save failed payment
        paymentRepository.save(p);

        // TODO handle this properly later

        // paymentRepository.flush();
    }
}

26. Exercise Solution

Issue 1: Excessive Statement Comments

Comments such as:

JAVA
// Get payment

// Check success

// Save

// Return

do not add useful information.

Issue 2: Weak Variable Names

These variables are unclear:

JAVA
p
x
i
r

While i is acceptable for a small loop index, the important domain variables should be meaningful.

Use:

JAVA
payment
maxRetryAttempts
paymentResponse

Issue 3: Magic Configuration

The retry limit is stored as:

JAVA
int x = 3;

A named constant or configuration property communicates intent better.

Issue 4: Comment Explaining Magic Value

JAVA
// Maximum retry count
int x = 3;

The comment is being used because the variable name is poor.

Rename the value instead.

Issue 5: Retry Logic Inside Main Method

The retry loop makes the business method more difficult to read.

A focused helper method can communicate the behavior without section comments.

Issue 6: Generic Missing-Payment Exception

Use a domain-specific exception.

Issue 7: Vague TODO

JAVA
// TODO handle this properly later

provides no actionable information.

Issue 8: Commented-Out Code

JAVA
// paymentRepository.flush();

should be deleted.

Improved Code

JAVA
@Service
public class PaymentProcessor {
    private static final int MAX_PAYMENT_ATTEMPTS = 3;

    private final PaymentRepository paymentRepository;
    private final PaymentGateway paymentGateway;

    public PaymentProcessor(PaymentRepository paymentRepository, PaymentGateway paymentGateway) {
        this.paymentRepository = paymentRepository;
        this.paymentGateway = paymentGateway;
    }

    public void process(Long paymentId) {
        Payment payment = paymentRepository.findById(paymentId)
                .orElseThrow(() -> new PaymentNotFoundException(paymentId));

        if (payment.getStatus() == PaymentStatus.COMPLETED) {
            return;
        }

        if (chargePayment(payment)) {
            payment.markCompleted();
        } else {
            payment.markFailed();
        }

        paymentRepository.save(payment);
    }

    private boolean chargePayment(Payment payment) {
        for (int attempt = 1; attempt <= MAX_PAYMENT_ATTEMPTS; attempt++) {
            PaymentResponse paymentResponse = paymentGateway.charge(payment);

            if (paymentResponse.isSuccessful()) {
                return true;
            }
        }

        return false;
    }
}

Why This Is Better

Comments Are No Longer Needed for Obvious Behavior

The method names communicate intent:

JAVA
chargePayment(payment)

payment.markCompleted()

payment.markFailed()

Named Constant Replaces Comment

Instead of:

JAVA
int x = 3;

the code uses:

JAVA
MAX_PAYMENT_ATTEMPTS

Clear Domain Names

The implementation is easier to understand without explanatory comments.

Smaller Method

Retry behavior has been extracted into:

JAVA
chargePayment()

The main process() method now reads like a high-level business workflow.

Domain-Specific Exception

Missing-payment behavior is explicit.

Dead Code Removed

The commented repository operation is gone.

Important Production Note

In a real payment system, simply retrying a charge may create duplicate transactions unless the payment gateway supports idempotency.

If the provider requires a specific idempotency mechanism, that would be an appropriate place for a useful comment.

For example:

JAVA
// Reuse the same idempotency key across retries so the provider cannot create duplicate charges.
PaymentResponse paymentResponse = paymentGateway.charge(payment);

This explains a critical integration requirement rather than obvious Java syntax.

27. Interview Perspective

Avoiding unnecessary comments commonly appears in senior Java and code-review interviews as part of clean-code discussions.

An interviewer may provide a method with comments before every line and ask:

  • Is this well-documented code?
  • Which comments would you remove?
  • When should comments be retained?
  • How would you make this method self-explanatory?
  • Why is commented-out code problematic?
  • When is a TODO acceptable?
  • Can comments become a maintenance risk?
  • How can naming reduce comments?
  • When should a performance-related comment remain?
  • How would you review an important workaround comment?

A strong senior-level answer should distinguish between:

Code narration

and:

Context documentation

Code narration usually adds little value.

Context documentation may be extremely valuable.

28. Interview Questions and Answers

Basic Question

Question: Why should Java developers avoid unnecessary comments?

Answer:

Because comments that simply repeat code:

  • Add visual noise
  • Increase maintenance effort
  • Can become outdated
  • Make important comments harder to notice
  • Often hide poor naming or design

Readable code should communicate normal behavior directly.

Intermediate Question

Question: How can you remove the need for comments?

Answer:

Use:

  • Meaningful variable names
  • Clear method names
  • Small focused methods
  • Domain methods
  • Named constants
  • Enums
  • Explicit exception types
  • Simple control flow

For example:

Instead of:

JAVA
// Maximum retry count
int x = 3;

use:

JAVA
int maxRetryAttempts = 3;

or preferably:

JAVA
private static final int MAX_RETRY_ATTEMPTS = 3;

Advanced Question

Question: Are comments always a code smell?

Answer:

No.

Comments become valuable when they document information that cannot be expressed clearly through code.

Examples include:

  • External API constraints
  • Legacy-system workarounds
  • Non-obvious business rules
  • Concurrency assumptions
  • Security decisions
  • Performance constraints
  • Migration compatibility logic

The presence of a comment is not automatically bad.

The important question is whether the comment adds unique and accurate information.

Scenario-Based Question

Question: You see this code during review:

JAVA
// Wait 2 seconds
Thread.sleep(2000);

What would you recommend?

Answer:

The comment is not useful because the statement already communicates the delay.

I would first investigate why the application needs to wait two seconds.

If it represents an external constraint, the intent should be explicit.

For example:

JAVA
// Vendor reporting API exposes newly uploaded files with up to a two-second consistency delay.
Thread.sleep(REPORT_VISIBILITY_DELAY_MS);

However, blocking with Thread.sleep() in application logic should also be reviewed carefully because another retry or asynchronous design may be more appropriate.

Code-Review Question

Question: Should commented-out Java code be kept in a Pull Request?

Answer:

Normally no.

Source control already stores previous versions.

Commented-out code:

  • Creates noise
  • Becomes stale
  • Is not compiled
  • Is not tested
  • Confuses future maintainers

It should generally be deleted.

Real-Project Question

Question: Give an example of a comment that should remain in production code.

Answer:

Consider an external payment API:

JAVA
// HTTP 409 means the idempotency key was processed previously.
// Treat it as an already-completed payment rather than retrying the charge.
if (response.statusCode() == HttpStatus.CONFLICT) {
    return PaymentResult.ALREADY_PROCESSED;
}

The Java condition itself cannot explain the vendor-specific meaning of HTTP 409.

The comment therefore preserves important integration knowledge.

29. Quick Rule to Remember

If a comment only tells you what the next line does, improve the code and remove the comment. Keep comments that explain why non-obvious code exists.

30. Final Takeaway

Avoiding unnecessary comments is an important part of writing maintainable Java code.

The goal is not to produce comment-free applications.

The goal is to ensure every comment earns its place.

What the Developer Should Remember

Developers should first make code understandable through:

  • Meaningful names
  • Small methods
  • Clear domain concepts
  • Constants
  • Enums
  • Explicit exceptions
  • Simple control flow

Only then should comments be added where important context is still missing.

What the Reviewer Should Check

During Pull Request review, check whether:

  • Comments duplicate code.
  • Naming can replace comments.
  • Complex methods should be refactored instead of narrated.
  • Comments are accurate.
  • TODOs are actionable.
  • Dead commented-out code has been removed.
  • Important business or technical constraints remain documented.
  • Sensitive information is absent.

What Should Be Avoided in Production Code

Avoid:

  • Comments before obvious statements
  • Comments explaining poor variable names
  • Comments explaining magic values that should be constants
  • Commented-out code
  • Manual change logs
  • Developer-name comments
  • Vague TODO comments
  • Outdated comments
  • Sensitive information in comments
  • Excessive Javadoc that duplicates method signatures

Clean Java code should explain normal behavior through the implementation itself.

Comments should be reserved for information that future developers would otherwise be unable to discover easily.

The best comment is not the one that explains complicated code. Often, the better solution is to simplify the code so that the comment is no longer necessary.