Files
AgentCompany/builtin-skills/software-engineer/clean-code/references/func-dry.md
T
ZacharyZhang-NY e74dafcd36 Silence render-disposed spam, unbreak bundled skills, drop board wake
Three independently ugly bugs that all fed the same log flood:

* Electron's `WebFrameMain.send` writes every "Render frame was disposed"
  to stderr via `console.error`. When the worker fans a second
  agent-event past a reloading renderer, we produced thousands of
  identical lines and stalled the main loop on stderr I/O. Added a
  `mainFrame.detached` guard so the send is short-circuited before
  Electron's own catch block fires, and installed a targeted filter in
  `suppress-warnings.ts` (now actually imported from the entry point)
  so the specific `console.error("Error sending from webFrameMain:"…)`
  noise never reaches the terminal. Any other payload still surfaces.

* `dispatchAgentMessage` accepted the human-reader sentinel as a wake
  target when an agent replied to `__board__` — `wakeAgentIfPossible`
  then called `db.getAgent("__board__")`, threw, and the dispatcher
  kept repeating on every send. Strip `HUMAN_SENDER_ID` at
  `resolveMessageWakeTargets`, and keep a defense-in-depth guard in the
  heartbeat so a stray caller (future automation fan-out) cannot
  reintroduce the crash.

* Pi's skills loader rejects any SKILL.md whose frontmatter `name`
  diverges from its parent directory. The four bundled `my-writing-style`
  copies declared `name: writing-style-skill`, so every install emitted
  a warning and dropped the skill. They also lived as orphan gitlinks
  (mode 160000 without .gitmodules), and the global `*.md` gitignore
  hid every other SKILL.md from version control. Fixed the frontmatter
  to match the dir, converted the dangling submodules to plain trees,
  and allowlisted `builtin-skills/**/*.md` so a fresh clone carries the
  catalogue instead of silently losing it.
2026-04-20 08:13:48 -04:00

2.7 KiB
Raw Blame History

title, impact, impactDescription, tags
title impact impactDescription tags
Do Not Repeat Yourself CRITICAL prevents N× maintenance burden func, dry, duplication, abstraction

Do Not Repeat Yourself

Duplication is the root of all evil in software. When an algorithm changes, you must change it in multiple places. When you fix a bug, you must remember to fix it everywhere.

Incorrect (duplicated logic):

public void processNewEmployee(Employee employee) {
    if (employee.getName() == null || employee.getName().trim().isEmpty()) {
        throw new ValidationException("Name is required");
    }
    if (employee.getEmail() == null || !employee.getEmail().contains("@")) {
        throw new ValidationException("Valid email is required");
    }
    employeeRepository.save(employee);
    emailService.sendWelcome(employee.getEmail());
}

public void updateEmployee(Employee employee) {
    if (employee.getName() == null || employee.getName().trim().isEmpty()) {
        throw new ValidationException("Name is required");  // Duplicated
    }
    if (employee.getEmail() == null || !employee.getEmail().contains("@")) {
        throw new ValidationException("Valid email is required");  // Duplicated
    }
    employeeRepository.update(employee);
}

Correct (extracted common logic):

public void processNewEmployee(Employee employee) {
    validateEmployee(employee);
    employeeRepository.save(employee);
    emailService.sendWelcome(employee.getEmail());
}

public void updateEmployee(Employee employee) {
    validateEmployee(employee);
    employeeRepository.update(employee);
}

private void validateEmployee(Employee employee) {
    requireNonEmpty(employee.getName(), "Name is required");
    requireValidEmail(employee.getEmail());
}

private void requireNonEmpty(String value, String message) {
    if (value == null || value.trim().isEmpty()) {
        throw new ValidationException(message);
    }
}

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

When NOT to apply DRY:

  • Coincidental duplication: Two code blocks look similar but serve different purposes and will evolve independently. Extracting a shared function creates a false coupling that makes both harder to change later.
  • Premature abstraction: If the code has only been duplicated once, wait. The third occurrence reveals the true abstraction. Premature extraction often produces awkward, over-parameterized helpers.
  • Cross-boundary duplication: Sometimes duplication across microservices or bounded contexts is preferable to introducing a shared library that couples the services.

Reference: Clean Code, Chapter 3: Functions