філософія дизайну програмного забезпечення

від Rob ZappЩе немає встановленьЩе немає вподобаньОновлено 8 жовтня 2026 р.Категорія: Інженерія

Що це робить

Використовуйте під час написання, зміни або перегляду коду щоразу, коли зміна додає експортовану або імпортовану назву, створює модуль, клас, компонент, допоміжний елемент, хук, сервіс або обгортку, централізує повторюваний код або змінює API. Правила Оустерхоута (глибокі модулі, приховування інформації, зниження складності) плюс інваріантний тест для спільного використання коду, тест вартості для читача та обов’язкова примітка з дизайну в кінці.

Встановлення відкриє цей запис у вашому настільному додатку AgentsRoom. Якщо додаток ще не встановлено, вас перенаправить на сторінку завантаження.

SKILL.md

---
name: філософія дизайну програмного забезпечення
description: Використовуйте під час написання, зміни або перегляду коду щоразу, коли зміна додає експортовану або імпортовану назву, створює модуль, клас, компонент, допоміжний елемент, хук, сервіс або обгортку, централізує повторюваний код або змінює API. Правила Оустерхоута (глибокі модулі, приховування інформації, зниження складності) плюс інваріантний тест для спільного використання коду, тест вартості для читача та обов’язкова примітка з дизайну в кінці.
---

# Філософія розробки програмного забезпечення (John Ousterhout)

## Коли використовувати цей навик

Використовуйте цей навик, коли ви проектуєте, пишете, змінюєте або переглядаєте код. Він застосовується до проєктування модулів, змін API, декомпозиції, рефакторингу, імен, коментарів, тестів і роботи з продуктивністю. Використовуйте його також, коли зміна здається незручною або коли одна зміна поширюється на багато файлів.

## Упередження, яке потрібно виправити

Працюючий код не те саме, що простий код. Малі частини, знайомі шаблони, прапорці, обгортки та додаткова документація можуть ускладнювати дизайн. Вони це роблять, коли додають те, що читач повинен знати, або коли витікає знання в інші модулі.

## Правила прийняття рішень

- Оцінюйте дизайн за тим, наскільки він знижує складність. Віддавайте перевагу дизайну, який зменшує навантаження на читача. Складність має чотири ознаки. Одна зміна вимагає редагування в багатьох місцях. Залежності приховані. Кроки повинні відбуватися у фіксованому порядку. Читач повинен тримати в пам’яті багато фактів.
- Розглядайте дизайн як безперервну роботу. Перший патч, що працює, не є завершеним, якщо він ускладнює подальші зміни. Для рішення про інтерфейс, розділення модуля або абстракцію порівнюйте два або більше можливих дизайнів.
- Віддавайте перевагу глибоким модулям. Глибокий модуль має невеликий інтерфейс і приховує велику кількість складності. Відкидайте сервіси-проходи, тонкі обгортки бібліотек і малі допоміжні модулі. Відкидайте будь-яке вилучення, що додає імена, але не зменшує навантаження на читача.
- Проєктуйте інтерфейс навколо того, що повинен знати викликаючий, а не навколо того, як працює реалізація. Уникайте крихких послідовностей налаштувань, прапорців режимів, конфігураційних регуляторів і аргументів, що показують внутрішні вибори.
- Приховуйте рішення, які можуть змінюватися. Прикладами є внутрішні представлення, форма зберігання, протоколи, формати файлів і трюки з продуктивністю. Облік, нормалізація та крайні випадки: інші приклади. Тримайте кожен з них всередині модуля, що володіє знаннями.
- Переносьте складність у модуль, що володіє деталями. Приймайте більш складну реалізацію, коли вона дає викликаючим простіший контракт і усуває повторну роботу на кожному місці виклику.
- Робіть модуль загальним на правильному рівні. Не підганяйте модуль під одного викликача. Не додавайте нечітку абстракцію для майбутніх потреб. Тримайте рідкісні крайні випадки поза основним шляхом і розміщуйте спеціальну поведінку у власному місці.
- Об’єднуйте або розділяйте модулі за загальною складністю. Не об’єднуйте і не розділяйте їх за розміром, за порядком виконання коду, за звичкою або за зовнішнім виглядом. Тримайте разом пов’язаний стан, поведінку, правила і рішення. Розділяйте їх лише тоді, коли нова межа є глибшою і читач може зрозуміти кожну сторону окремо.
- Зменшуйте кількість винятків. За можливості змінюйте інтерфейс або правила так, щоб недійсні стани не могли виникати. Не змушуйте кожного викликача повторювати однаковий захисний код.
- Використовуйте коментарі для зменшення складності. Записуйте контракти інтерфейсу, правила, які мають залишатися істинними, приховані рішення дизайну та їхні причини. Також записуйте складні факти, які викликачі не повинні знати. Не повторюйте код у коментарі. Не використовуйте коментар, щоб приховати погану назву, погане розділення або заплутаний контрольний потік.
- Розглядайте імена, послідовність і ясність як інформацію про дизайн. Ім’я повідомляє читачеві абстракцію, а не механізм. Пов’язані операції використовують однакові конвенції. Код, що дивує читача, додає складності, навіть якщо він короткий.
- Пишіть тести проти публічних контрактів і стабільних API. Тестуйте приховану складність і спеціальні випадки через ці контракти. Не дозволяйте легкості тесту змушувати вас робити поверхневий або «протікаючий» інтерфейс.
- Додавайте зміну продуктивності, шаблон, парадигму або фреймворк лише з однієї з двох причин. Вона знижує складність у цій кодовій базі або є докази, що компроміс необхідний. Приховуйте кожну оптимізацію за стабільним інтерфейсом.

## Сигнали та реакція на кожен

- Функція незручна, або одна зміна поширюється на файли, або рецензент повинен знаходити приховані залежності. Реакція: шукайте відсутнє приховування інформації та поверхневі модулі. Також шукайте кроки у фіксованому порядку і складність, яку несуть викликачі.
- Ви додаєте модуль, шар, сервіс, помічник, обгортку або фасад. Або додаєте шаблон, опцію, зворотний виклик або аргумент. Реакція: покажіть, що це приховує більше складності, ніж додає.
- Ви змінюєте API. Реакція: перевірте, що повинен знати звичайний викликач. Викликач не повинен знати порядок викликів, представлення або зберігання. Викликач не повинен знати транспорт, кеш, протокол або формат файлу. Викликач не повинен знати внутрішній робочий процес або багато кроків налаштування.
- Ви додаєте спеціальний випадок, прапорець, шлях винятку, умову або контейнер, який бачать викликачі. Реакція: спочатку запитайте, що може зробити власний модуль замість цього. Він може усунути недійсний стан, ізолювати незвичайну поведінку або надати більш сильну операцію.
- Ви розділяєте код, вилучаєте функцію або додаєте змінну. Реакція: перевірте, що нова межа або ім’я має значення. Воно не повинно лише додавати переходи, стан, що проходить, або проміжні кроки, які бачать викликачі.
- Код має фази, такі як `prepare`, `process` і `finalize`, або викликачі повинні будувати об’єкти поетапно. Реакція: перевірте, що часовий порядок: це справжня концепція. Якщо ні, організуйте код навколо стабільних обов’язків.
- Ім’я нечітке, називає механізм, не послідовне або дивує читача. Реакція: подумайте знову про межу абстракції. Не приймайте ім’я, яке майже правильне.
- Коментар довгий, повторює код, пояснює заплутаний інтерфейс або показує внутрішні деталі для пояснення використання. Реакція: змініть абстракцію або перенесіть відсутній контракт в інтерфейс.
- Ви оптимізуєте продуктивність. Реакція: спочатку виміряйте, потім приховуйте оптимізацію. Не відмовляйтеся від глибини модуля або приховування інформації без доказів, що компроміс необхідний.
- Ви тестуєте або переглядаєте. Реакція: дивіться на публічну поведінку та контракти інтерфейсу. Також дивіться на приховану складність за стабільними API і на спеціальні випадки, що тримаються за абстракцією.

## Остаточний чек-лист

- Чи зменшує зміна зусилля на розуміння, зміну, перевірку та розширення системи?
- Чи приховує кожен елемент інтерфейсу, обгортка, шар, допоміжна функція, опція та ім'я достатньо складності, щоб це було виправдано?
- Чи важливі рішення зосереджені в одному місці? Чи видимі залежності? Чи записані обмеження, які потрібні викликачам? Чи захищені внутрішні частини, які можуть змінюватися?
- Чи працюють поширені випадки без додаткових кроків? Чи залишаються рідкісні контролі, особливі випадки, трюки з продуктивністю та деталі винятків поза загальним шляхом?
- Чи точні та послідовні імена? Чи актуальні коментарі, без повторення коду? Чи дотримується код існуючих конвенцій, якщо немає нової інформації, що виправдовує їх зміну?

## Gate

Використовуйте повний чеклист, коли зміна додає ім'я, яке інший код може експортувати або імпортувати. Використовуйте його також, коли зміна створює модуль, клас, компонент, допоміжну функцію, хук, сервіс або обгортку, або поміщає повторюваний код в одне місце. Перейменування, codemods, зміни конфігурації, зміни даних та одно-рядкові виправлення не потребують цього.

## Тест інваріанту: ділитися лише кодом, що змінюється разом

- Витягуйте спільний код лише тоді, коли він захищає правило, яке ви можете назвати. Доказом є спільна зміна: історія показує, що копії виправлялися або змінювалися разом. Код, який лише виглядає схожим і змінюється незалежно,: це рима. Залишайте рими як дублікати. Три схожі блоки не доводять правило.
- Виправлення має усувати проблему, а не переносити її. Шість приведень, перенесених в один загальний допоміжний привід, все одно залишаються шістьма приведеннями. Напишіть типізований мапер, який приховували приведення.
- Коли абстракція неправильна, поверніть код назад у лінійний вигляд і дозвольте дублюванню повернутися. Не викривляйте абстракцію прапорцями.
- Не розбивайте код лише через його розмір. Один модуль на 400 рядків, що приховує одне рішення, кращий за чотири модулі по 100 рядків, які пропускають ті ж з'єднання.
- Механічне читання Clean Code або SOLID (дуже маленькі функції, один клас на кожну відповідальність) дає поверхневі модулі. Ця навичка має пріоритет над цим тиском.

## Вартість для читача: третій тест

Тест глибини та тест інваріанту визначають, чи має існувати межа. Тест вартості для читача визначає, чи легко змінювати код навколо межі. Наступний читач, людина або агент, платить за кожен рядок, який він мусить прочитати. Агент платить токенами. Агент знаходить код за текстовим пошуком, частковим читанням, типізацією та тестами.

- **Знаходжуваність.** Використовуйте одне ім'я для кожної концепції. Пишіть його однаково всюди, щоб простий текстовий пошук знаходив його. Дефекти: імена, побудовані зі стрічок, з'єднання через побічні ефекти імпорту, два імені для однієї концепції. Ланцюги реекспорту, що приховують визначення, також є дефектами.
- **Раннє зупинення.** Помістіть контракт на початку файлу або над експортом. Скажіть, що він обіцяє, що приховує і що ніколи не робить. Тоді читач може зупинитися раніше.
- **Машинна перевірка.** Використовуйте точні типи на вході та виході кожної межі, щоб типізація замінила читання викликачів. Дефекти: `any`, прості словники, булеві прапорці, значення яких відоме лише в тілі.
- **Видиме зв’язування.** Два місця мають змінюватися разом. Забезпечте це спільним типом, тестом або одним джерелом. Якщо не можете, позначте це в обох місцях.
- **Без шуму.** Видаліть коментарі, що повторюють код, і закоментований код. Видаліть мертві гілки та коментарі, що фіксують історію змін. Видаліть старий шлях, що стоїть поруч із заміною.
- **Передбачуваність.** Дотримуйтеся існуючого розташування репозиторію. Помістіть тест там, де його шукає читач, і зробіть так, щоб він запускався окремо.

Розмір файлу навмисно не включений у цей список. Дуже великий файл: це причина шукати другу приховану логіку. Це ніколи не причина розрізати файл.

## Безпека

Для існуючого коду спочатку напишіть тест, що фіксує поточну поведінку. Потім зробіть модуль глибшим. Для нового коду напишіть тест, що визначає бажану поведінку.

## Примітка про дизайн (обов’язково, коли застосовується gate)

Коли застосовується gate, додайте розділ із заголовком `## Design note` у опис pull request. Напишіть два-чотири рядки:

- Кожну межу, яку ви додали, і рішення, яке вона приховує.
- Кожне дублювання, яке ви залишили навмисно, і причину.
- Кожну поверхневу частину, яку ви прийняли, і причину.

Якщо gate не застосовується, напишіть `## Design note`, а потім `Gate not applicable: <причина>`. Також додайте примітку про дизайн у підсумок вашого фінального кроку.

## Режим рев’ю

Використовуйте цей розділ, коли ви переглядаєте або тестуєте код, написаний іншим агентом або людиною.

1. Перевірте примітку про дизайн. Коли застосовується gate і в pull request немає розділу `## Design note`, повідомте про блокуючу знахідку. Коли примітка не відповідає diff, повідомте про блокуючу знахідку.
2. Знаходження про дизайн є блокуючим лише тоді, коли виконуються обидві умови:
   - Воно називає правило цієї навички. Правило: це правило прийняття рішення, gate, тест інваріанту або пункт вартості для читача.
   - Воно вказує конкретну вартість для читача або для наступної зміни. Приклади: "Викликачі мають знати форму зберігання." "Одна концепція має два імені." "Зміна кришки потребує редагувань у трьох файлах."
3. Позначайте всі інші спостереження про дизайн як неблокуючі. Помістіть їх у окремий список із заголовком "Non-blocking design notes". Неблокуюча примітка ніколи не повертає роботу назад до розробника.
4. Не повідомляйте про перевагу як про знахідку. Інше ім'я, розташування файлу або стиль: це перевага. Вона стає знахідкою лише тоді, коли порушує назване правило і має конкретну вартість.
5. Коли та сама знахідка про дизайн повертається вдруге, підвищуйте її пріоритет. Не просіть ту саму зміну втретє.

## Пов’язані навички (коли встановлені)

- `find-shared-code`: пошук лише для звітування про нещодавню історію коду, вартий спільного використання. Використовує тест інваріанту та тест глибини цієї навички.
- `refactoring` та `working-effectively-with-legacy-code`: безпечні кроки до глибшого дизайну. Ця навичка вирішує, чи залишиться нова межа.

## Джерело та ліцензія

Цей навик базується на «міні» правилах з книги A Philosophy of Software Design у репозиторії ciembor/agent-rules-books на GitHub (ліцензія MIT, коміт 893a88a). Ворота, тест інваріанту, тест вартості читача, нотатка про дизайн і режим перегляду є доповненнями до цих правил. У репозиторії також зберігаються повні правила книги.

Теги

дизайнархітектураousterhoutперегляд

Корисні матеріали

Завантажити AgentsRoom

Запускайте всіх своїх AI-агентів на всіх своїх проєктах з одного вікна.

БезкоштовноЗавантажити AgentsRoom

Додаток-компаньйон: контролюйте своїх агентів на ходу

Використовуйте свого: Claude, Codex, Antigravity CLI або іншого AI-провайдера.

Отримати розширення
Chrome Web Store

Надсилайте баги та запити прямо у свій публічний беклог.

Кілька проектів
Багато постачальників
Кілька агентів
Статус в реальному часі
Різниця файлів і коміт
Мобільний компаньйон
Попередній перегляд в реальному часі
Команди агентів
Автоматизація браузера
Розробка, орієнтована на беклог
Бібліотека підказок
Бібліотека навичок
Переглянути всі функції