DEV Community

Timevolt
Timevolt

Posted on

The GitHub Chronicles: A New Hope

The Quest Begins (The "Why")

I remember staring at my GitHub profile one rainy Sunday, feeling like a side‑kick in a movie where the hero never gets the spotlight. My repos were a handful of personal projects, a few forked repos with a single‑line typo fix, and a lingering sense that recruiters would swipe left faster than I could say “push”. I’d heard the mantra “contribute to open source” a hundred times, but every time I tried, I ended up scrolling through issues labeled “good first issue”, picking something trivial like “Fix spelling of ‘recieve’”, and watching my PR sit idle for weeks.

The problem wasn’t lack of effort—it was lack of impact. I was treating open source like a side quest for experience points instead of the main storyline where your actions actually change the world. I wanted a contribution that would make maintainers nod, that would show I understood the codebase, and that would give recruiters something tangible to talk about.

The Revelation (The Insight)

The breakthrough came when I stopped looking for “easy” issues and started hunting for bugs that needed a test. I realized that the most valuable thing you can give a project isn’t just a fix—it’s proof that the fix works and won’t regress later. Writing a failing test that reproduces the bug, then making it pass, does three things at once:

  1. It shows you’ve read the code – you had to understand the flow enough to craft a test.
  2. It reduces risk for maintainers – they get a safety net for future changes.
  3. It creates a clear, review‑friendly PR – the test + fix is a self‑contained story that’s easy to verify.

In other words, the technique is: Find a reproducible bug, write a failing test that captures it, fix the bug, and submit a PR with a crisp commit message and a PR description that explains the problem, the test, and the solution.

Wielding the Power (Code & Examples)

Let’s make this concrete with a real example from a popular repo: expressjs/express. I noticed an issue where res.json() would throw a TypeError when passed a circular JSON object (a classic “I’m stuck in a loop” scenario). The project already had a test suite, but there was no test for this edge case.

Before – The “Typo‑Fix” Approach (What NOT to Do)

# Bad PR
- Fix typo in README: change “recieve” to “receive”
Enter fullscreen mode Exit fullscreen mode

Why it falls short:

  • Zero functional value.
  • No demonstration of coding ability.
  • Maintainers see it as noise; it rarely gets merged quickly.

After – The Test‑First Fix (The Victory)

Step 1: Reproduce the bug in a test

// test/circular-json.test.js
const express = require('express');
const app = express();

describe('res.json() with circular objects', () => {
  it('should not throw on circular JSON', () => {
    const res = {
      json: function(obj) { return obj; }, // simplified mock
    };
    const a = {};
    const b = { a };
    a.b = b; // circular reference

    // The actual call we want to test
    const fn = () => res.json(a);
    expect(fn).not.toThrow(); // <-- this should pass after the fix
  });
});
Enter fullscreen mode Exit fullscreen mode

Step 2: Run the test – it fails

$ npm test
> express@ test
> mocha "test/**/*.test.js"

  res.json() with circular objects
    ✕ should not throw on circular JSON

  1) res.json() with circular objects
       should not throw on circular JSON:
     TypeError: Converting circular structure to JSON
Enter fullscreen mode Exit fullscreen mode

Step 3: Fix the bug in the source

In lib/response.js, the original json method looked like this:

res.json = function (obj) {
  if (typeof obj !== 'object' || obj === null) {
    throw new TypeError('obj must be an object');
  }
  this.setHeader('Content-Type', 'application/json');
  this.send(JSON.stringify(obj));
};
Enter fullscreen mode Exit fullscreen mode

The fix adds a simple circular‑reference detector (or falls back to a safe serializer). For brevity, here’s a minimal safe version:

const circularReplacer = () => {
  const seen = new WeakSet();
  return (key, value) => {
    if (typeof value === "object" && value !== null) {
      if (seen.has(value)) {
        return '[Circular]';
      }
      seen.add(value);
    }
    return value;
  };
};

res.json = function (obj) {
  if (typeof obj !== 'object' || obj === null) {
    throw new TypeError('obj must be an object');
  }
  this.setHeader('Content-Type', 'application/json');
  this.send(JSON.stringify(obj, circularReplacer()));
};
Enter fullscreen mode Exit fullscreen mode

Step 4: Run the test again – it passes

$ npm test
  res.json() with circular objects
    ✓ should not throw on circular JSON
Enter fullscreen mode Exit fullscreen mode

Step 5: Craft the PR

Title: fix(res.json): handle circular JSON objects safely

Description:

## Problem
Calling `res.json()` with a circular object throws `TypeError: Converting circular structure to JSON`, crashing the response.

## Solution
Added a simple circular‑reference replacer to `JSON.stringify` inside `res.json`. The replacer replaces repeated references with the string "[Circular]" so the response is always valid JSON.

## Tests
- Added `test/circular-json.test.js` that asserts `res.json` does not throw on circular objects.
- All existing tests continue to pass.

## Checklist
- [x] Code follows the project's style guide
- [x] Added tests for the new behavior
- [x] Updated documentation (none needed for this internal change)
Enter fullscreen mode Exit fullscreen mode

Commit message (exact wording, as requested):

fix(res.json): safely serialize circular objects

- Detect circular references via a WeakSet replacer
- Replace cycles with "[Circular]" to avoid TypeError
- Add test covering the edge case
Enter fullscreen mode Exit fullscreen mode

What NOT to Do (Traps to Avoid)

  1. Don’t just add the fix without a test – maintainers have no guarantee it won’t regress.
  2. Don’t write a massive refactor – a huge PR is harder to review and may hide the core change.
  3. Don’t ignore the contribution template – skipping the checklist or description makes the PR feel lazy.

Why This New Power Matters

When you ship a PR like the one above, you’re not just adding a line of code; you’re demonstrating a complete engineering loop: identify a problem, create a safety net, solve it, and communicate clearly. Recruiters see that you can work inside an existing codebase, respect its processes, and add measurable value.

Your GitHub profile transforms from a collection of stray stars to a showcase of impactful contributions. Maintainers start recognizing your name, and you may even get invited to triage issues or become a contributor. In short, you go from being a side‑kick to a trusted ally in the open‑source saga.

Your Next Quest

  1. Pick a project you use or admire that has a “good first issue” label.
  2. Search its issue tracker for bugs that lack a test (look for comments like “needs a test” or “reproduce”).
  3. Clone the repo, write a failing test that reproduces the bug, run it to see it fail.
  4. Fix the bug, make the test pass, and ensure the rest of the suite still green.
  5. Open a PR using the exact commit message and description format above (feel free to adapt the wording to your voice).
  6. Celebrate when it gets merged—then watch your contributor graph grow a little taller.

Ready to level up? Grab an issue, write that test, and let your PR do the talking. May the force be with your commits! 🚀

Top comments (0)