javascript-interview-questions' deepMerge carries the highest risk — 1 function to address first

deepMerge in coding-exercise/deep-merge-nested-objects/solution.js is the sole high-band hotspot in sudheerj/javascript-interview-questions, combining cyclomatic complexity 11 and fan-out 6 with 154 days of inactivity and a 100% bug-fix commit ratio.

Stephen Collins ·
oss javascript refactoring code-health
Activity Risk8.97Low
Hottest FunctiondeepMerge

Key Points

What is cyclomatic complexity and why does it matter in javascript-interview-questions?

Cyclomatic complexity counts the number of independent execution paths through a function — every `if`, `else`, loop, `&&`, `||`, and `case` branch adds one to the total. A higher count means more paths that can execute, each of which needs a test case and each of which is a surface for a bug. In javascript-interview-questions, `deepMerge` has a cyclomatic complexity of 11, which means eleven distinct paths through a function whose job is to serve as a readable reference implementation — more branching than a teaching example typically benefits from. Reducing that count through decomposition would make the function both easier to test exhaustively and easier for a reader to follow.

How do I reduce cyclomatic complexity in JavaScript?

The most effective first step is the extract-method refactoring: identify the largest independent branch cluster inside the function and pull it into its own named function, reducing the parent's path count immediately. A cyclomatic complexity above 10 is a reasonable threshold to start decomposing; above 15, splitting is strongly advisable. For `deepMerge` specifically, separating the type-guard logic ("is this value a plain object?") from the merge-strategy logic into distinct helper functions would reduce complexity while making each piece independently testable. Replacing multi-branch conditionals with early-return guards (sometimes called a guard clause or "bouncer pattern") is a complementary technique that flattens the decision tree without adding new functions.

Is javascript-interview-questions actively maintained?

Based on the structural data at commit 997037d, the repository shows no recent commit activity on its analyzed functions — `deepMerge`, the highest-risk function, has had zero commits in the last 30 days and has not been touched in 154 days. All 34 analyzed functions fall into either the "debt" or "ok" quadrant, meaning none are in active churn right now. That said, low recent activity on analyzed functions does not mean the repository is abandoned — it may simply reflect a stable period or contributions outside the analyzed function set. The structural debt in `deepMerge` is worth addressing, but it is a maintenance backlog item rather than a live regression concern.

How do I reproduce this analysis?

Clone sudheerj/javascript-interview-questions and run `git checkout 997037d` to pin to the exact analyzed commit. Then run `hotspots analyze . --mode snapshot --explain-patterns --force` using the Hotspots CLI, available at github.com/hotspots-dev/hotspots. The same command works on any local git repository without additional configuration.

What does activity-weighted risk mean?

Activity-weighted risk is a combined score that multiplies a function's structural complexity — derived from cyclomatic complexity, nesting depth, and fan-out — by its recent commit frequency, so that functions which are both hard to understand and actively changing score highest. A highly complex function that has not been touched in years scores lower than a moderately complex function being edited every week, because the dormant function poses lower near-term regression risk. In javascript-interview-questions, `deepMerge` scores 8.97 entirely on structural grounds, with zero recent commits pulling that score up — meaning the risk is about what happens the next time someone edits it, not about what is happening right now. This framing helps teams distinguish between technical debt to schedule and live regression risk to address immediately.

sudheerj/javascript-interview-questions is a JavaScript interview-prep reference with 34 analyzed functions — none critical, one high-band, and 33 in the lowest-risk tier. That single outlier is deepMerge in coding-exercise/deep-merge-nested-objects/solution.js, which lands in the debt quadrant: structurally complex but completely dormant, with zero commits in the last 30 days and 154 days elapsed since it was last touched. Its activity-weighted risk score of 8.97 is driven entirely by structural complexity, meaning the risk is not about what is changing now — it is about the blast radius when someone eventually does change it.

The table below ranks functions by activity-weighted risk — a score that multiplies structural complexity by recent commit frequency. A function that is both hard to understand (high cyclomatic complexity) and actively changing is a higher priority than one that is complex but untouched. CC = cyclomatic complexity (independent execution paths); ND = max nesting depth; FO = fan-out (distinct callees).

Top Hotspot

FunctionFileRiskCCNDFO
deepMergecoding-exercise/deep-merge-nested-objects/solution.js9.01126

A repository with 33 functions sitting comfortably in the “ok” quadrant makes the one outlier easy to find and easy to act on. There is no noisy churn to filter through, no competing fire-quadrant emergencies — just one function that has quietly accumulated enough structural complexity to warrant attention before the next development push.

deepMergecoding-exercise/deep-merge-nested-objects/solution.js

The name and path make the function’s purpose clear: it is the reference implementation for a deep-merge coding exercise, responsible for recursively combining nested objects. That recursive, multi-case nature is precisely why the metrics look the way they do.

With a cyclomatic complexity of 11, deepMerge has eleven independent execution paths — each one a required test case and a potential edge case for object merging (null inputs, array vs. plain-object discrimination, prototype handling, circular reference behavior). A CC of 11 sits just above the “moderate” threshold of 10, which would be unremarkable in production application code but is worth scrutinizing in a function whose entire purpose is to serve as a clear, teachable example. A fan-out of 6 means the function reaches out to six distinct callees; for a solution file in an educational context, that breadth of coupling suggests the implementation may be doing more orchestration than a reader would expect from a focused exercise answer. The max nesting depth of 2 is the one structural relief here — the logic is not deeply nested, which limits how hard it is to trace a single path through the code.

The external signals sharpen the picture. The file has exactly one commit in its history, and that commit is bug-linked — yielding a bug-fix commit ratio of 1.0. That is the strongest possible ratio, meaning every recorded change to this file has been associated with a defect. The external signal note is important to keep in mind: this does not prove the current implementation is broken, but it does mean the file’s entire recorded history is a correction. Combined with 154 days of inactivity and no authors active in the last 90 days, there is no ongoing ownership to catch a regression if the function is reopened.

The concrete recommendation is to treat this as structural debt that warrants refactoring before the next contribution touches it. Specifically: decompose the eleven execution paths into named helper predicates or sub-functions (for example, separating the “is this a plain object” guard from the “merge strategy” logic), reduce fan-out by consolidating related callees, and add a test suite that covers each of the CC-implied paths before refactoring begins. For an educational repository, a lower-complexity version of deepMerge with clearly named sub-steps would also serve readers better — the goal of the file is demonstration, and a function with CC 11 and FO 6 is harder to learn from than one decomposed into self-documenting pieces.

Key Takeaways

  • deepMerge is the only function worth prioritizing right now. With an activity-weighted risk score of 8.97, CC 11, and FO 6, it is the sole high-band hotspot across 34 analyzed functions. The rest of the repository sits in the low-risk tier.
  • The debt quadrant means act before the next change, not urgently today. deepMerge has not been touched in 154 days and has no recent owners — the risk is blast-radius risk, not live regression risk. Schedule a refactoring pass before the next contributor edits this file cold.
  • The 100% bug-fix commit ratio is a historical flag, not a verdict. The file’s single commit was bug-linked. Before expanding this exercise or adding related examples, add test coverage across deepMerge’s eleven execution paths to establish a safety net.

Reproduce This Analysis

git clone https://github.com/sudheerj/javascript-interview-questions
cd javascript-interview-questions
git checkout 997037d44b45d5320626ade1d765eb4341b4ad3f
hotspots analyze . --mode snapshot --explain-patterns --force

To run the same analysis on your own codebase, run hotspots analyze . --mode snapshot in any local git repo — no configuration required.

Hotspots highlights structural and activity risk — not “bad code.” Findings are a prioritization aid, not a bug predictor. Editorial policy →

Run this on your own codebase

Hotspots runs locally in under a minute — no account, no data leaves your machine.

macOS
$ brew install Stephen-Collins-tech/tap/hotspots
Linux / cargo
$ cargo install hotspots-cli
Run in any repo
$ hotspots analyze .
★ Star on GitHub