Lesson Completion
Back to course

Code Quality and Tools: Static Analysis, Reviews, and Logging

Beginner
12 minutesā˜…4.7Java

1. The Hook (The "Byte-Sized" Intro)

  • In a Nutshell: Static analysis = automated code review (SonarQube, Checkstyle, PMD, SpotBugs). Code reviews = peer feedback (small changes, timely, constructive).
  • Logging: SLF4J facade + Logback, levels (TRACE/DEBUG/INFO/WARN/ERROR), structured logging.
  • Metrics: Cyclomatic complexity (≤10), code duplication (<5%), coverage (≄80%).
  • CI/CD: Automate builds, tests, quality checks.
  • Golden rule: Tools catch bugs early, humans catch design issues!

Think of car quality control. Static analysis = automated sensors (detect defects). Code review = human inspector (design, safety issues). Logging = flight recorder (diagnose problems). CI/CD = assembly line quality checks (every step). Metrics = performance indicators!


2. Conceptual Clarity (The "Simple" Tier)

šŸ’” The Analogy

  • Static Analysis: Spell checker (finds errors automatically)
  • Code Review: Editor feedback (improves quality)
  • Logging: Security cameras (record what happened)
  • CI/CD: Automated factory (build, test, deploy)

3. Technical Mastery (The "Deep Dive")

java
// =========================================== // 1. STATIC ANALYSIS TOOLS // =========================================== // Checkstyle (coding standards) // checkstyle.xml <module name="LineLength"> <property name="max" value="120"/> </module> <module name="MethodLength"> <property name="max" value="50"/> </module> // PMD (potential bugs, dead code) // pmd.xml <rule ref="category/java/bestpractices.xml/UnusedPrivateMethod"/> <rule ref="category/java/errorprone.xml/AvoidBranchingStatementAsLastInLoop"/> // āŒ PMD will catch: void processData() { for (Item item : items) { if (item.isValid()) { continue; // āŒ Last statement in loop (redundant) } } } // SpotBugs (bug patterns) // Catches: if (s == "test") { } // āŒ String comparison with == Date d = new Date(2024, 1, 1); // āŒ Deprecated constructor // SonarQube (comprehensive) // Measures: Bugs, Vulnerabilities, Code Smells, Coverage, Duplication // Quality Gates: Block merge if quality drops // =========================================== // 2. CODE REVIEW BEST PRACTICES // =========================================== // āœ… GOOD: Small PR (200-400 lines) // Easy to review, quick feedback // āŒ BAD: Large PR (2000+ lines) // Takes hours to review, likely to miss issues // Review checklist: // 1. Does it work? (tests pass) // 2. Is it readable? // 3. Is it maintainable? // 4. Are there tests? // 5. Is naming clear? // 6. Any security issues? // āœ… GOOD: Constructive feedback // "Consider using Optional here to avoid null checks" // āŒ BAD: Personal criticism // "Why did you write such terrible code?" // =========================================== // 3. LOGGING BEST PRACTICES // =========================================== // āœ… Use SLF4J facade import org.slf4j.Logger; import org.slf4j.LoggerFactory; class UserService { private static final Logger logger = LoggerFactory.getLogger(UserService.class); void createUser(User user) { logger.debug("Creating user: {}", user.getId()); try { repository.save(user); logger.info("User created successfully: {}", user.getId()); } catch (Exception e) { logger.error("Failed to create user: {}", user.getId(), e); throw e; } } } // Log levels: logger.trace("Very detailed (rarely used)"); logger.debug("Debugging info (dev environment)"); logger.info("Important events (user actions)"); logger.warn("Warnings (potential issues)"); logger.error("Errors (need attention)"); // āŒ BAD: Wrong log level logger.info("NullPointerException occurred!"); // āŒ Should be ERROR! logger.error("User logged in"); // āŒ Should be INFO! // āŒ BAD: String concatenation (eager evaluation) logger.debug("Processing: " + expensiveOperation()); // āŒ Calls expensiveOperation() even if DEBUG disabled! // āœ… GOOD: Parameterized (lazy evaluation) logger.debug("Processing: {}", expensiveOperation()); // āœ… Only calls if DEBUG enabled! // āŒ BAD: Logging sensitive data logger.info("User password: {}", password); // āŒ NEVER! logger.info("Credit card: {}", creditCard); // āŒ NEVER! // āœ… GOOD: Structured logging (JSON) logger.info("user_action", kv("userId", userId), kv("action", "login"), kv("timestamp", Instant.now())); // Output: {"userId":123,"action":"login","timestamp":"2024-01-01T00:00:00Z"} // =========================================== // 4. CODE QUALITY METRICS // =========================================== // Cyclomatic Complexity (number of paths through code) // āœ… GOOD: Complexity = 2 int max(int a, int b) { return (a > b) ? a : b; // 2 paths } // āŒ BAD: Complexity = 10 (too high!) void process(Order order) { if (order.isPremium()) { if (order.getTotal() > 1000) { if (order.hasDiscount()) { if (order.getCustomer().isActive()) { // ... } } } } } // Rule: Keep complexity ≤ 10 // Code Duplication // āŒ BAD: Duplicated code void processOrder() { validate(); calculate(); save(); } void processReturn() { validate(); // āŒ Duplicated! calculate(); // āŒ Duplicated! refund(); } // āœ… GOOD: Extract common logic void processOrder() { commonProcessing(); save(); } void processReturn() { commonProcessing(); refund(); } void commonProcessing() { validate(); calculate(); } // =========================================== // 5. CI/CD PIPELINE // =========================================== // Jenkins / GitHub Actions pipeline stages: - name: Build run: mvn clean compile - name: Test run: mvn test - name: Quality Check run: | mvn checkstyle:check mvn pmd:check mvn spotbugs:check - name: Coverage run: mvn jacoco:report fail_if: coverage < 80% - name: SonarQube run: mvn sonar:sonar fail_if: quality_gate = FAILED // =========================================== // 6. IDE INSPECTIONS // =========================================== // IntelliJ IDEA warnings // āš ļø Variable 'x' is never used int x = 10; // Remove unused variable // āš ļø Method can be static void helper() { } // No instance fields used // āš ļø Condition is always true if (list.size() >= 0) { } // Size never negative! // Enable inspections: File → Settings → Editor → Inspections

5. The Comparison & Decision Layer

ToolPurposeWhen to Use
CheckstyleCoding conventionsAlways (enforce style)
PMDPotential bugs, dead codeCI pipeline
SpotBugsBug patternsCI pipeline
SonarQubeComprehensive qualityCI pipeline, pre-merge

6. The "Interview Corner" (The Edge)

The "Killer" Interview Question: "What makes a good code review?" Answer:

Good code review:

  1. Small changes (200-400 lines)
  2. Timely (reviewed within 24 hours)
  3. Constructive (suggest improvements, not criticize)
  4. Focus on code, not person
  5. Check: correctness, tests, readability, security

Review checklist:

text
āœ… Does it work? (tests pass) āœ… Are there tests for new code? āœ… Is naming clear? āœ… Is it maintainable? āœ… Any security issues? āœ… Follows conventions? āœ… No code duplication?

Pro-Tips:

  1. Automated quality gates (fail builds on quality drop):
xml
<!-- Maven: Fail build if coverage < 80% --> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <configuration> <rules> <rule> <element>BUNDLE</element> <limits> <limit> <counter>LINE</counter> <value>COVEREDRATIO</value> <minimum>0.80</minimum> </limit> </limits> </rule> </rules> </configuration> </plugin>
  1. Pre-commit hooks (run checks before committing):
bash
# .git/hooks/pre-commit #!/bin/bash mvn checkstyle:check if [ $? -ne 0 ]; then echo "Checkstyle failed! Fix issues before committing." exit 1 fi

Topics Covered

Java Fundamentals

Tags

#java#programming#beginner-friendly

Last Updated

2025-02-01