Posts Tagged ‘SoftwareQuality’
[MunchenJUG] Evolution of Static Analysis: The Journey to PMD 7 (7/Oct/2024)
Lecturer
Andreas Dangel is a distinguished software engineer with extensive expertise in Java, Spring, SQL, and agile methodologies. With a professional career spanning several decades, he has significantly contributed to the IoT consumer electronics industry. Andreas has been a pivotal figure in the open-source community, serving as a maintainer of PMD since 2012 and a committer at the Apache Software Foundation for the Maven project. Currently based in Munich, he continues his professional endeavors at MicroDoc.
Abstract
This article explores the comprehensive transformation of PMD, a leading multi-language static code analyzer, through its significant transition to version 7. It examines the fundamental principles of PMD—including its rule-based architecture and copy-paste detection—while detailing the modernization of its core engine to support evolving language features and improved performance. The analysis highlights the challenges faced during this decade-long development cycle, the shift in architectural paradigms to accommodate complex language parsing, and the strategic roadmap for the future of automated code quality assurance.
The Architecture of Static Analysis: Understanding PMD
PMD serves as a sophisticated static code analyzer designed to identify problematic patterns, common mistakes, and stylistic inconsistencies across various programming languages. Originally established in 2002 as the “Project Mistake Detector,” the tool has evolved into a robust, rule-based ecosystem supporting over ten languages. The system’s utility is grounded in its ability to detect issues that often elude standard compilers, categorized into domains such as error-prone constructs, best practices, code style, and performance.
The engine operates on a rule-based methodology where every detectable problem is governed by a specific rule. PMD offers users more than 400 predefined rules, including 270 specifically for Java. These rules can be customized through two primary methods: writing custom Java classes or utilizing XPath expressions to query the source code’s Abstract Syntax Tree (AST). To facilitate the latter, the PMD ecosystem includes a “Rule Designer” application, allowing developers to visualize code structures and test XPath queries in real-time.
Beyond standard rule checking, PMD includes a specialized Copy-Paste Detector (CPD). Unlike the core engine, which requires deep language parsing, CPD utilizes a different technological approach that allows it to support an even broader range of languages for identifying duplicated code blocks.
Implementation and Integration Strategies
PMD’s versatility is reflected in its diverse integration options within the modern software development lifecycle. Written in Java, the tool can be executed via a simple command-line interface (CLI) or integrated into various build and development environments.
Build Tool Integration
For Java-centric projects, integration via build automation tools is the standard approach:
- Maven: Utilizing the
maven-pmd-plugin, developers can automate code verification and copy-paste detection as part of the build process. - Gradle and Ant: Similar plugins exist to ensure code quality is maintained continuously without manual intervention.
- Quality Gates: By configuring the build to fail upon rule violations, PMD serves as a mandatory quality gate, ensuring that no substandard code reaches the repository.
IDE and CI/CD Ecosystems
To provide immediate feedback, PMD supports major Integrated Development Environments (IDEs) including Eclipse, IntelliJ IDEA, and VS Code. Furthermore, it is deeply integrated into Continuous Integration (CI) services. For instance, Jenkins utilizes specialized plugins to visualize results and track the history of violations across builds, providing insights into whether code quality is improving or deteriorating over time. Modern cloud services and GitHub Apps also leverage PMD to perform automatic code reviews during pull requests, providing comments directly on the affected code blocks.
Innovations in PMD 7: Redesigning the Engine
The transition to PMD 7 represents a fundamental shift in how the tool processes source code. The primary driver for this major release was the need to overcome the limitations of the aging architecture that had been in place for nearly two decades.
The internal redesign focuses on several key areas:
- Parsing Modern Java: As Java’s release cadence accelerated, PMD needed a more flexible way to handle new language features like records, sealed classes, and pattern matching.
- Performance Optimization: The new version introduces architectural changes that improve the speed of analysis, particularly for large-scale projects with hundreds of rules.
- Language Support Expansion: While Java remains a core focus, PMD 7 strengthens its multi-language capabilities, including better support for languages like Salesforce’s Apex.
One of the significant challenges in this journey was maintaining backward compatibility while significantly altering the AST structure. The development team had to balance the introduction of more descriptive node types with the risk of breaking existing custom rules written by the community.
Future Directions and Sustainability
Looking ahead, the PMD project aims to enhance its analysis capabilities by incorporating more data-flow and control-flow sensitivity. This would allow the tool to detect more complex logic errors that require understanding the state of variables across different execution paths.
Sustainability remains a focal point for the project. As an open-source initiative maintained by a small core team of three individuals and occasional contributors, the “Journey to PMD 7” also serves as a case study in open-source lifecycle management. The roadmap includes simplifying the process of writing and maintaining rules to encourage more community participation and ensuring the tool remains relevant in an era of increasing automated development.
Links:
[DevoxxUK2025] Zero-Bug Policy Success: A Journey to Developer Happiness
At DevoxxUK2025, Peter Hilton, a product manager at a Norwegian startup, shared an inspiring experience report on achieving a zero-bug policy. Drawing from his team’s journey in 2024, Peter narrated how a small, remote team transformed their development process by tackling a backlog of bugs, ultimately reaching a state of zero open bugs. His talk explored the practical steps, team dynamics, and challenges of implementing this approach, emphasizing its impact on developer morale, customer trust, and software quality. Through a blend of storytelling and data, Peter illustrated how a disciplined focus on fixing bugs can lead to a more predictable and joyful development environment.
The Pain of Bugs and the Vision for Change
Peter began by highlighting the chaos caused by an ever-growing bug backlog, which drained time, eroded team morale, and undermined customer confidence. In early 2024, his team faced a surge in bug reports following a marketing campaign for their Norwegian web shop, a circular economy platform selling reusable soap containers. The influx revealed testing gaps and consumed developer time, hindering experiments to boost customer conversions. Inspired by a blog post he wrote in 2021 and the “fix it now or delete it” infographic by Yasaman Farzan, Peter proposed a zero-bug policy—not as a mandate for bug-free software but as a target to clear open issues. The team, motivated by shared frustration, agreed to experiment, envisioning predictable support efforts and meaningful feature feedback.
Overcoming Resistance and Defining the Approach
Convincing a team to prioritize bug fixes over new features required navigating skepticism and detailed “what-if” scenarios from developers. Peter described how initial discussions risked paralysis, as developers questioned edge cases like handling multiple simultaneous bugs. To move forward, the team framed the policy as a safe experiment, setting clear goals: reducing time spent on bug discussions, improving software reliability, and enabling meaningful customer feedback. By April 2024, they committed to fixing bugs exclusively for two months, a bold move that demanded collective focus. Peter, as product manager, leveraged his role to align stakeholders, emphasizing business outcomes like increased customer conversions over bug counts, which helped secure buy-in.
The Hard Work of Bug Fixing
The transition to a zero-bug state was arduous but structured. Starting in May 2024, the team of six developers tackled 252 bugs over the year, fixing around five per week, with peaks of 10–15 during intense periods. Peter shared a chart showing the number of open bugs fluctuating but never exceeding 15, a manageable load compared to teams with hundreds of unresolved issues. The team’s small size and autonomy, as a fully remote group, allowed them to focus without external dependencies. By August, they reached “zero bug day,” a milestone celebrated as a turning point. This period also saw improved testing practices, as each fix included robust test coverage to prevent regressions, addressing technical debt accumulated from the rushed initial launch.
Sustaining Zero Bugs and Reaping Rewards
Post-August, the team entered a maintenance phase, fixing bugs as they arose—typically one or two at a time—while spending half their time on new features. Peter noted that this phase, with months starting at zero open bugs (e.g., March–May 2025), felt liberating. Developers spent less time in meetings, and Peter could focus on customer growth experiments without bugs skewing results. A calendar visualization for April 2025 showed most days bug-free, with only two minor issues fixed leisurely. The simplicity of handling bugs case-by-case, without complex prioritization, mirrored the “fix it now or delete it” mantra, fostering a happier, more productive team environment.
Lessons for Other Teams
Reflecting on the journey, Peter emphasized that a zero-bug policy requires team-wide commitment and a tolerance for initial discomfort. While their small, autonomous team faced no external dependencies, larger organizations might need to address inter-team coordination or legacy backlogs. He suggested a radical option: deleting large backlogs to focus on new reports, though he hadn’t tried it. The key takeaway was the value of simplicity—handling one bug at a time eliminated the need for intricate rules. Peter also highlighted that the process built psychological safety, as tackling a tough challenge together strengthened team cohesion, making it a worthwhile experiment for teams seeking better quality and morale.
Links:
[DevoxxUK2025] Cracking the Code Review
Paco van Beckhoven, a senior software engineer at Hexagon’s HXDR division, delivered a comprehensive session at DevoxxUK2025 on improving code reviews to enhance code quality and team collaboration. Drawing from his experience with a cloud-based platform for 3D scans, Paco outlined strategies to streamline pull requests, provide constructive feedback, and leverage automated tools. Highlighting the staggering $316 billion cost of fixing bugs in 2013, he emphasized code reviews as a critical defense against defects. His practical tactics, from crafting concise pull requests to automating style checks, aim to reduce friction, foster learning, and elevate software quality, making code reviews a collaborative and productive process.
Streamlining Pull Requests
Paco stressed the importance of concise, well-documented pull requests to facilitate reviews. He advocated for descriptive titles, inspired by conventional commits, that include ticket numbers and context, such as “Fix null pointer in payment service.” Descriptions should outline the change, link related tickets or PRs, and explain design decisions to preempt reviewer questions. Templates with checklists ensure consistency, reminding developers to update documentation or verify tests. Paco also recommended self-reviewing PRs after a break to catch errors like unused code or typos, adding comments to clarify intent and reduce reviewer effort, ultimately speeding up the process.
Effective Feedback and Collaboration
Delivering constructive feedback is key to effective code reviews, Paco noted. He advised reviewers to start with the PR’s description and existing comments to understand context before diving into code. Reviews should prioritize design and functionality over minor style issues, ensuring tests are thoroughly checked for completeness. To foster collaboration, Paco suggested using “we” instead of “you” in comments to emphasize teamwork, posing questions rather than statements, and providing specific, actionable suggestions. Highlighting positive aspects, especially for junior developers, boosts confidence and encourages participation, creating a supportive review culture.
Leveraging Automated Tools
To reduce noise from trivial issues like code style, Paco showcased tools like Error Prone, OpenRewrite, Spotless, Checkstyle, and ArchUnit. Error Prone catches common mistakes and suggests fixes, while OpenRewrite automates migrations, such as JUnit 4 to 5. Spotless enforces consistent formatting across languages like Java and SQL, and Checkstyle ensures adherence to coding standards. ArchUnit enforces architectural rules, like preventing direct controller-to-persistence calls. Paco advised introducing these tools incrementally, involving the team in rule selection, and centralizing configurations in a parent POM to maintain consistency and minimize manual review efforts.
Links:
[DevoxxFR2014] PIT: Assessing Test Effectiveness Through Mutation Testing
Lecturer
Alexandre Victoor is a Java developer with nearly 15 years of experience, currently serving as an architect at Société Générale. His expertise spans software development, testing practices, and integration of tools for code quality assurance.
Abstract
This article examines the limitations of traditional code coverage metrics and introduces PIT as a mutation testing tool to evaluate the true effectiveness of unit tests. It analyzes how PIT injects faults into code to verify if tests detect them, discusses integration with build tools and SonarQube, and explores performance considerations, providing a deeper understanding of enhancing test suites in software engineering.
Challenges in Traditional Testing Metrics
In software development, particularly when practicing Test-Driven Development (TDD), the emphasis is often on writing tests before implementing functionality. This approach, originally termed “test first,” underscores the critical role of tests as a specification that could theoretically allow recreation of production code if lost. However, assessing the quality of these tests remains challenging.
Common metrics like line coverage and branch coverage indicate which parts of the code are executed during testing but fail to reveal if tests adequately detect defects. For instance, consider a simple function calculating a client price by applying a margin to a market price. Achieving 100% line coverage with a test for a zero-margin scenario does not guarantee detection of errors, such as changing an addition to a subtraction, as the test might still pass.
Complicating matters further, when introducing conditional logic or external dependencies mocked with frameworks like Mockito, 100% branch coverage can be attained without robust error detection. Default mock behaviors might always return zero, masking issues in conditional expressions. Thus, coverage metrics primarily highlight untested code but do not affirm the protective value of existing tests.
This gap necessitates advanced techniques to validate test efficacy, ensuring that modifications or bugs trigger failures. Mutation testing emerges as a solution, systematically introducing faults—termed mutants—into the code and observing if the test suite identifies them.
Implementing Mutation Testing with PIT
PIT, an open-source Java tool, operationalizes mutation testing by generating mutants and rerunning tests against each. If a test fails, the mutant is “killed,” indicating effective detection; if tests pass, the mutant “survives,” signaling a weakness in the test suite.
Integration into continuous integration pipelines is straightforward. After standard compilation and testing, PIT analyzes specified packages for code under test and corresponding test classes. It focuses on unit tests due to their speed and lack of side effects, avoiding interactions with databases or file systems that could complicate results.
PIT’s report details line-by-line coverage and mutation survival, highlighting areas where code executes but faults go undetected. Configuration options address common pitfalls: excluding logging statements to prevent false positives, as frameworks like Log4j or SLF4J calls do not impact functional outcomes; timeouts for mutants creating infinite loops; and parallel execution on multi-core machines to mitigate performance overhead from repeated test runs.
Optimizations include leveraging line coverage to run only relevant tests per mutant and incremental analysis to focus on changed code since the last run. These features make PIT viable for nightly builds, though not yet for every commit in fast-paced environments.
A SonarQube plugin extends PIT’s utility by creating violations for lines covered but not protected against mutants and introducing a “mutation coverage” metric. This represents the percentage of mutants killed; for example, 70% mutation coverage implies a 70% chance of detecting introduced anomalies.
Practical Implications and Recommendations
Adopting PIT requires team maturity in testing practices; starting with mutation testing without established TDD might be premature. For teams with solid unit tests, PIT reveals subtle deficiencies, encouraging refinements that bolster code reliability.
In real projects, well-TDD’ed code often shows high mutation coverage, aligning with 70-80% line coverage thresholds as acceptable benchmarks. Performance tuning, such as multi-threading and incremental modes, addresses scalability concerns.
Ultimately, PIT transforms testing from a coverage-focused exercise to one emphasizing defect detection, fostering more resilient software. Its ease of use—via command line, Ant, Gradle, or Maven—democratizes advanced quality assurance, urging developers to integrate it for comprehensive test validation.
Links:
[DevoxxFR2012] Toward Sustainable Software Development – Quality, Productivity, and Longevity in Software Engineering
Frédéric Dubois brings ten years of experience in JEE architecture, agile practices, and software quality. A pragmatist at heart, he focuses on continuous improvement, knowledge sharing, and sustainable delivery over rigid processes.
This article expands Frédéric Dubois’s 2012 talk into a manifesto for sustainable software development. Rejecting the idea that quality is expensive, he proves that technical excellence drives long-term productivity. A three-year-old application should not be unmaintainable. Yet many teams face escalating costs with each new feature. Dubois challenged the audience: productivity is not about delivering more features faster today, but about maintaining velocity tomorrow, next year, and five years from now.
The True Cost of Technical Debt
Quality and productivity are intimately linked, but not in the way most assume. High quality reduces defects, simplifies evolution, and prevents technical debt. Low quality creates a vicious cycle of bugs, rework, and frustration. Dubois shared a case study: a banking application delivered on time but with poor design. Two years later, a simple change required three months of work. The same team, using TDD and refactoring, built a similar system in half the time with one-tenth the defects.
Agile Practices for Long-Term Velocity
Agile practices, when applied pragmatically, enable sustainability. Short feedback loops, automated tests, and collective ownership prevent knowledge silos. Fixed-price contracts and outsourcing often incentivize cutting corners. Transparency, shared metrics, and demo-driven development align business and technical goals.
Links
Relevant links include the original video at YouTube: Toward Sustainable Development.