Содержание
Коротко
Кросс-платформенные CLI и утилиты на Node.js часто превращаются в лабиринт if (process.platform === …). На Dev.to показали, как паттерны Strategy и Factory собирают утилиту для освобождения порта (EADDRINUSE): команды разных ОС прячутся за интерфейсами, ядро остаётся тестируемым.
Что произошло
Типичная боль локальной разработки: сервер не стартует, потому что порт занят. На Windows нужны netstat и taskkill, на macOS и Linux — lsof и kill. Если размазать эти ветки по всему коду, нарушается принцип единственной ответственности, unit-тесты превращаются в моки shell, а каждая новая ОС — ещё один switch.
Автор выстраивает слой так. TypeScript-интерфейсы описывают контракт «найти процесс на порту / завершить» без строк shell в бизнес-логике. Factory выбирает платформенную реализацию Strategy. Исполнитель команд без состояния запускает argv-массивы и не склеивает пользовательский ввод в одну строку — меньше риска внедрения в shell.
Сверху — общий API и CLI на одном ядре: и программный вызов из другого пакета, и терминальная команда делят одну реализацию. Пример домена — «освободить порт перед dev-сервером», но тот же каркас подходит для любой environmental variance: разные бинарники, сетевые утилиты, обработка ошибок.
Почему это важно
npm-пакеты, которые «работают у меня на Mac», регулярно падают в Linux CI или у коллег на Windows. Вынос платформенных деталей в Strategy делает поведение предсказуемым и подменяемым в тестах — вы подставляете fake-реализацию, а не парсите настоящий вывод lsof.
Для full-stack команд это шаблон не только для CLI. Любой адаптер к внешним системам — облако, CI, локальный Docker — выигрывает от разделения «политика vs механизм»: ядро знает что нужно сделать, Strategy знает как на конкретной платформе.
На практике
- Опишите интерфейс домена (PortManager, FileLocker и т.п.) до первой shell-команды.
- Одна Factory на точку выбора платформы; не размазывайте
platformпо десяти файлам. - Runner принимает массив аргументов, не строку
exec(`kill ${pid}`)— особенно если pid когда-нибудь придёт извне. - Тесты: fake Strategy с записью вызовов; интеграционные — только на целевой ОС в matrix CI.
- CLI (
commander/yargs) — тонкая обёртка над тем же сервисом, что экспортирует"exports"вpackage.json.
Итог
Factory и Strategy в Node.js — не академическая схема, а способ держать кросс-платформенный npm-пакет читаемым. Материал на Dev.to с кодом полезен, если ваши утилиты раздуваются от switch (os.platform()).