Migrating From JUnit 4 to JUnit 5: A Definitive Guide

Migrating from JUnit 4 to JUnit 5 involves updating dependencies, annotations, and testing classes while running old and new tests together. Custom runners and rules need to be replaced with extensions, and parameterized tests require rework to fit the new model. This guide provides step-by-step instructions for a smooth, gradual migration.

Testing

Code Quality Checks

Code quality often deteriorates over time, especially in legacy projects, slowing development and introducing bugs. Using code reviews, static analysis, and dynamic analysis helps detect issues early, while fast feedback loops prevent problems from accumulating. Combining these practices with continuous monitoring ensures cleaner, more maintainable code.

Software Design

Testing Myth #2: Unit Tests Are Not Worth It

Many developers see unit tests as extra work, but their main purpose is improving design, not just finding bugs. Writing tests while coding encourages loose coupling, high cohesion, and produces a fast regression suite. Adding tests after the fact may require refactoring to gain real benefits.

Testing

Testing Myth #1: Writing Tests Slows You Down

Skipping tests might speed up short-term development, but it increases long-term maintenance costs and debugging time. Writing high-quality, feature-focused tests improves stability, catches errors early, and makes future changes easier and safer. Investing in tests upfront ultimately accelerates development over the software’s lifecycle.

Testing

Code Smell: Dead code

This post explains why unused or unreachable parts of a project are a common warning sign in aging systems. It outlines how changing requirements and incomplete cleanups create unnecessary leftovers. The article focuses on practical ways to remove this clutter and keep projects lean and maintainable.

Software Design

Make Better Git Commits

Effective Git commits make tracking changes easier and improve collaboration. This article covers committing frequently, focusing on single logical changes, separating formatting updates, and writing meaningful commit messages. Following these guidelines keeps your project history clear and maintainable.

Productivity

Code Smell: Large Class

This post examines why overly large classes make code harder to understand, maintain, and test. It outlines strategies for splitting classes, creating subclasses, or defining interfaces to clarify responsibilities. Refactoring in this way promotes better design, easier testing, and greater code reuse.

Software Design

Avoiding Unnecessary Null Checks

Null checks are a common source of bugs and clutter in code. This article explores ways to avoid returning or passing nulls, including using the Null Object pattern, throwing exceptions, and designing objects that encapsulate behavior. By eliminating nulls, you simplify code, reduce errors, and encourage cleaner design.

Software Design

Misconceptions About Code Reuse

Reusing code is important, but inheritance and static utility classes are often misapplied. Inheritance should focus on modeling hierarchies, not sharing methods, while utility classes can violate object-oriented principles. This article explains how to use composition and meaningful class responsibilities to create cleaner, more flexible, and maintainable code.

Software Design

How to Prevent Legacy Code From Emerging

Legacy code does not appear out of nowhere. It often grows from small shortcuts, missing tests, and neglected refactoring. This article explains how developers unintentionally create messy, unmaintainable code and offers practical strategies to prevent it. By maintaining code, refactoring while adding features, and writing tests, you can keep your codebase clean and easier to work with over time.

Software Design