In my last post I wrote about a PR I closed on purpose, because the maintainers were already fixing the same bug. That was a lesson in picking issues better. Over a few months and several repos, I settled on a simple routine. This post is that routine, so you can skip the mistakes I made.
Step 1: Check that the project is alive
Before I read any code, I open the repo and look at three things:
- Were PRs merged in the last few weeks?
- How fast do maintainers reply on issues and PRs?
- Do outside contributors get their PRs merged, or only the team?
A project with no replies is a waiting room. I would rather spend my time where someone will read my work.
Step 2: Check that nobody else is on it
This is the step I skipped with Riptide. Now I check:
- Is the issue assigned?
- Are there comments saying "I'm working on this"?
- Is there a linked PR, open or closed?
Then, before I write any code, I leave a short comment: "I'd like to work on this, is anyone already on it?" It takes one minute and can save a week.
Step 3: Read how maintainers review similar PRs
I open three or four merged PRs that touch the same area. I look at what the reviewers asked for: naming, where tests go, how big the change was. Most projects have unwritten rules, and the closed PRs are where they live.
Step 4: Reproduce it on the latest master
If the issue is a bug, I reproduce it on the current main branch first. Sometimes it is already fixed, and sometimes it only happens in an old version. Writing a fix for something that is not broken wastes everyone's time.
Step 5: Keep it small and prove it with a test
I pick the smallest change that solves the problem. Then I write a test that fails without my fix and passes with it. If the test passes before my change, it proves nothing.
How I look for bugs, not just pick them
The best thing I learned is to look for the root cause, not just one symptom.
In Picnic's error-prone-support, I found a bug where a check rewrites code by building a new format string from the original source text. If the original text contains a %, the rewritten string breaks at runtime. Here is the idea, simplified:
// Simplified idea: a literal from the user's code gets copied // into a new format string without escaping. String literal = "100%"; // contains a percent sign String format = "Value: " + literal; // now the % looks like a format placeholder String.format(format); // crashes at runtime I reported it as issue #2336 with a minimal repro, checked first that it was not a duplicate, and offered to send a fix with a regression test if the maintainers wanted one.
Later I found a second bug with the same root cause (building fixes from raw source text), and another contributor beat me to reporting it. That was fine. It confirmed the method works, because the root cause pointed to the same area. And if someone else has already said what I wanted to say, I do not add a comment just to be seen. I comment only when I have something new.
My checklist, short version
- Is the project alive and does it merge outside PRs?
- Is anyone already on the issue? Ask first.
- How do maintainers review similar PRs?
- Does it still reproduce on the latest master?
- Small change, plus a test that fails without the fix.
Proof of my work
Everything here is public, so you can check it yourself:
- PicnicSupermarket/error-prone-support issue #2336: a reproducible bug report
- PicnicSupermarket/error-prone-support #2275: extended
RequireNonNullExpressionrule (merged) - Adyen/adyen-java-api-library #1952: regex fix, shipped in SDK v42.0.0 (merged)
- zalando/logbook #2301, #2326, #2327 and #2328: Logbook changes (merged)
- Sionna Visualizer: my side project, a 6G + AI dashboard (live demo)
- My GitHub: all my repos and contributions
Next post: Sionna Visualizer, why a Java backend developer is building a 6G + AI dashboard.
If you are a maintainer, a recruiter or a team looking for someone who learns in public and works carefully, my DMs are open. Tell me in the comments how you choose your issues.