Every feature change touches the same file
“Whatever the ticket, the PR edits services/core.ts, the shared types file and three unrelated folders. Merge conflicts are constant and small changes break distant features.”
THE PRINCIPLE
Files that change together belong together. Git history shows where your real boundaries are; lint rules keep them there.
FIRST MOVES
- Find hotspots: files with the most commits in the last six months, weighted by size or complexity. A large, complex file that changes every week is the target; ignore lockfiles, generated code and simple registries (routes, exports) that are meant to change often.
- Run change-coupling analysis: which files appear in the same commits or tickets? Pairs that always co-change across folders show a misplaced boundary: either move them into one module, or remove the hidden dependency that forces the second change.
- Split the hotspot by business capability (what changes for the same reason), not by technical layer, and give each part a single public entry point.
- Turn the intended dependency direction into failing rules in CI (dependency-cruiser, Nx module boundaries, ArchUnit) and burn down existing violations from a baseline.
- Re-run the hotspot and coupling report after a few weeks to check that changes became local.
TOOLS: THEN → NOW
Opinions and architecture diagramsHotspot and change-coupling analysis from git history (git log, CodeScene, code-maat)
Folder conventions enforced in code reviewDependency rules that fail CI: dependency-cruiser, @nx/enforce-module-boundaries, ArchUnit
PATTERN SNAPSHOT
# Hotspots: most-changed files in the last 6 months
git log --since="6 months ago" --name-only --format= | sort | uniq -c | sort -rn | head -20
// .dependency-cruiser.js: features may not import each other's internals
module.exports = {
forbidden: [{
name: "no-cross-feature-imports",
severity: "error",
from: { path: "^src/features/([^/]+)/" },
to: { path: "^src/features/([^/]+)/", pathNot: "^src/features/$1/|^src/features/[^/]+/index\\.ts$" },
}],
};CLOSE THE AI. EXPLAIN THIS.
What does it tell you when two files in different modules appear together in most commits, and what are the two ways to fix it?HOW IT WORKS UNDERNEATH
RELATED SYMPTOMS
SOURCES
Guide reviewed