filozofia-projektowania-oprogramowania

autor: Rob ZappBrak instalacjiBrak polubieńZaktualizowano 8 października 2026Kategoria: Inżynieria

Co robi

Używaj podczas pisania, zmieniania lub przeglądania kodu za każdym razem, gdy zmiana dodaje eksportowaną lub importowalną nazwę, tworzy moduł, klasę, komponent, pomocnika, hook, usługę lub wrapper, centralizuje powtarzający się kod lub zmienia API. Zasady Ousterhouta (głębokie moduły, ukrywanie informacji, obniżanie złożoności) plus test niezmiennika dla współdzielenia kodu, test kosztu dla czytelnika oraz wymagana notatka projektowa na końcu.

Instalacja otwiera tę pozycję w Twojej aplikacji AgentsRoom na komputerze. Jeśli aplikacji jeszcze nie ma, trafisz na stronę pobierania.

SKILL.md

---
name: filozofia-projektowania-oprogramowania
description: Używaj podczas pisania, zmieniania lub przeglądania kodu za każdym razem, gdy zmiana dodaje eksportowaną lub importowalną nazwę, tworzy moduł, klasę, komponent, pomocnika, hook, usługę lub wrapper, centralizuje powtarzający się kod lub zmienia API. Zasady Ousterhouta (głębokie moduły, ukrywanie informacji, obniżanie złożoności) plus test niezmiennika dla współdzielenia kodu, test kosztu dla czytelnika oraz wymagana notatka projektowa na końcu.
---

# Filozofia projektowania oprogramowania (John Ousterhout)

## Kiedy używać tej umiejętności

Używaj tej umiejętności, gdy projektujesz, piszesz, zmieniasz lub przeglądasz kod. Dotyczy to projektowania modułów, zmian w API, dekompozycji, refaktoryzacji, nazw, komentarzy, testów i pracy nad wydajnością. Używaj jej także, gdy zmiana wydaje się niezręczna lub gdy jedna zmiana rozprzestrzenia się na wiele plików.

## Uprzedzenie do poprawienia

Działający kod nie jest tym samym co prosty kod. Małe fragmenty, znane wzorce, flagi, opakowania i dodatkowa dokumentacja mogą uczynić projekt bardziej złożonym. Dzieje się tak, gdy dodają one do tego, co czytelnik musi znać, lub gdy wyciekają wiedzę do innych modułów.

## Zasady podejmowania decyzji

- Mierz projekt tym, jak bardzo redukuje złożoność. Wybierz projekt, który zmniejsza obciążenie czytelnika. Złożoność ma cztery oznaki. Jedna zmiana wymaga edycji w wielu miejscach. Zależności są ukryte. Kroki muszą następować w ustalonej kolejności. Czytelnik musi pamiętać wiele faktów.
- Traktuj projekt jako pracę ciągłą. Pierwsza działająca poprawka nie jest zakończona, jeśli utrudnia późniejsze zmiany. Przy decyzji o interfejsie, podziale modułu lub abstrakcji porównaj dwa lub więcej możliwych projektów.
- Preferuj głębokie moduły. Głęboki moduł ma mały interfejs i ukrywa dużą złożoność. Odrzuć usługi przekazujące dalej, cienkie opakowania bibliotek i małe moduły pomocnicze. Odrzuć każde wyodrębnienie, które dodaje nazwy, ale nie zmniejsza obciążenia czytelnika.
- Projektuj interfejs wokół tego, co wywołujący musi znać, a nie wokół tego, jak działa implementacja. Unikaj kruchych sekwencji inicjalizacji, flag trybu, pokręteł konfiguracyjnych i argumentów pokazujących wewnętrzne wybory.
- Ukrywaj decyzje, które mogą się zmieniać. Przykłady to wewnętrzne reprezentacje, kształt przechowywania, protokoły, formaty plików i sztuczki wydajnościowe. Księgowość, normalizacja i przypadki brzegowe to inne przykłady. Trzymaj każdy z nich wewnątrz modułu, który posiada tę wiedzę.
- Przenieś złożoność do modułu, który posiada szczegóły. Zaakceptuj bardziej złożoną implementację, jeśli daje wywołującym prostszy kontrakt i usuwa powtarzającą się pracę z każdego miejsca wywołania.
- Twórz moduł ogólny na odpowiednim poziomie. Nie dopasowuj modułu do jednego wywołującego. Nie dodawaj niejasnej abstrakcji na przyszłe potrzeby. Trzymaj rzadkie przypadki brzegowe poza główną ścieżką i umieść specjalne zachowanie we własnym miejscu.
- Łącz lub dziel moduły według całkowitej złożoności. Nie łącz ani nie dziel ich według rozmiaru, kolejności wykonywania kodu, przyzwyczajeń czy wyglądu. Trzymaj powiązany stan, zachowanie, reguły i decyzje razem. Dziel je tylko wtedy, gdy nowa granica jest głębsza i czytelnik może zrozumieć każdą stronę osobno.
- Zmniejsz liczbę wyjątków. Tam gdzie to możliwe, zmień interfejs lub reguły tak, aby nie mogły wystąpić nieprawidłowe stany. Nie każ wywołującemu powtarzać ten sam defensywny kod.
- Używaj komentarzy do zmniejszania złożoności. Zapisuj kontrakty interfejsu, reguły, które muszą pozostać prawdziwe, ukryte decyzje projektowe i ich powody. Zapisuj także trudne fakty, których wywołujący nie muszą znać. Nie powtarzaj kodu w komentarzu. Nie używaj komentarza do ukrywania złej nazwy, złego podziału lub mylącego przepływu sterowania.
- Traktuj nazwy, spójność i jasność jako informacje projektowe. Nazwa mówi czytelnikowi o abstrakcji, nie o mechanizmie. Powiązane operacje używają tych samych konwencji. Kod, który zaskakuje czytelnika, dodaje złożoności, nawet jeśli jest krótki.
- Pisz testy przeciwko publicznym kontraktom i stabilnym API. Testuj ukrytą złożoność i przypadki specjalne przez te kontrakty. Nie pozwól, aby łatwość testu wymusiła płytki lub przeciekający interfejs.
- Dodaj zmianę wydajności, wzorzec, paradygmat lub framework tylko z jednego z dwóch powodów. Redukuje złożoność w tej bazie kodu lub dowody pokazują, że kompromis jest konieczny. Ukryj każdą optymalizację za stabilnym interfejsem.

## Sygnały i reakcje na nie

- Funkcja jest niezręczna, jedna zmiana rozprzestrzenia się na pliki lub recenzent musi znaleźć ukryte zależności. Reakcja: szukaj brakującego ukrywania informacji i płytkich modułów. Szukaj także kroków w ustalonej kolejności i złożoności, którą wywołujący muszą nosić.
- Dodajesz moduł, warstwę, usługę, pomocnika, opakowanie lub fasadę. Lub dodajesz wzorzec, opcję, callback lub argument. Reakcja: pokaż, że ukrywa więcej złożoności niż dodaje.
- Zmieniasz API. Reakcja: sprawdź, co normalny wywołujący musi znać. Wywołujący nie musi znać kolejności wywołań, reprezentacji ani przechowywania. Wywołujący nie musi znać transportu, cache, protokołu ani formatu pliku. Wywołujący nie musi znać wewnętrznego przepływu pracy ani wielu kroków inicjalizacji.
- Dodajesz przypadek specjalny, flagę, ścieżkę wyjątku, warunek lub kontener widoczny dla wywołujących. Reakcja: najpierw zapytaj, co może zrobić moduł właścicielski. Może usunąć nieprawidłowy stan, odizolować nietypowe zachowanie lub dać silniejszą operację.
- Dzielisz kod, wyodrębniasz funkcję lub dodajesz zmienną. Reakcja: sprawdź, czy nowa granica lub nazwa niesie znaczenie. Nie może tylko dodawać skoków, stanu przechodzącego lub pośrednich kroków widocznych dla wywołujących.
- Kod ma fazy takie jak `prepare`, `process` i `finalize`, lub wywołujący muszą budować obiekty etapami. Reakcja: sprawdź, czy kolejność czasowa jest prawdziwą koncepcją. Jeśli nie, zorganizuj kod wokół stabilnych odpowiedzialności.
- Nazwa jest niejasna, nazywa mechanizm, jest niespójna lub zaskakuje czytelnika. Reakcja: przemyśl ponownie granicę abstrakcji. Nie akceptuj nazwy, która jest prawie poprawna.
- Komentarz jest długi, powtarza kod, wyjaśnia mylący interfejs lub pokazuje wnętrze, by wyjaśnić użycie. Reakcja: zmień abstrakcję lub przenieś brakujący kontrakt do interfejsu.
- Optymalizujesz wydajność. Reakcja: najpierw zmierz, potem ukryj optymalizację. Nie rezygnuj z głębokości modułu ani ukrywania informacji bez dowodów, że kompromis jest konieczny.
- Testujesz lub przeglądasz. Reakcja: patrz na publiczne zachowanie i kontrakty interfejsu. Patrz także na ukrytą złożoność za stabilnymi API i na przypadki specjalne ukryte za abstrakcją.

## Ostateczna lista kontrolna

- Czy zmiana zmniejsza wysiłek potrzebny do zrozumienia, zmiany, weryfikacji i rozszerzenia systemu?
- Czy każdy element interfejsu, wrapper, warstwa, pomocnik, opcja i nazwa ukrywa wystarczającą złożoność, aby to uzasadnić?
- Czy ważne decyzje są w jednym miejscu? Czy zależności są widoczne? Czy ograniczenia, które muszą znać wywołujący, są zapisane? Czy wewnętrzne elementy, które mogą się zmieniać, są chronione?
- Czy typowe przypadki działają bez dodatkowych kroków? Czy rzadkie kontrolki, specjalne przypadki, sztuczki wydajnościowe i szczegóły wyjątków pozostają poza typową ścieżką?
- Czy nazwy są dokładne i spójne? Czy komentarze są aktualne, bez powtarzania kodu? Czy kod przestrzega istniejących konwencji, chyba że nowe informacje dały powód do ich zmiany?

## Brama

Użyj pełnej listy kontrolnej, gdy zmiana dodaje nazwę, którą inny kod może eksportować lub importować. Użyj jej także, gdy zmiana tworzy moduł, klasę, komponent, pomocnika, hook, usługę lub wrapper, albo umieszcza powtarzający się kod w jednym miejscu. Zmiany nazw, codemody, zmiany konfiguracji, zmiany danych i jednowierszowe poprawki nie wymagają jej.

## Test inwariantu: dziel tylko kod, który zmienia się razem

- Wyodrębnij wspólny kod tylko wtedy, gdy chroni regułę, którą potrafisz nazwać. Dowodem jest współzmiana: historia pokazuje, że kopie były poprawiane lub zmieniane razem. Kod, który tylko wygląda podobnie i zmienia się niezależnie, to rym. Pozostaw rymy jako duplikaty. Trzy podobne bloki nie dowodzą reguły.
- Poprawka musi usunąć problem, a nie go przesunąć. Sześć rzutowań przeniesionych do jednego ogólnego pomocnika rzutowań to nadal sześć rzutowań. Napisz typowany mapper, który rzutowania ukrywały.
- Gdy abstrakcja jest błędna, wstaw kod z powrotem inline i pozwól, by duplikacja wróciła. Nie wyginaj abstrakcji za pomocą flag.
- Nie dziel kodu tylko ze względu na jego rozmiar. Jeden 400-wierszowy moduł, który ukrywa jedną decyzję, jest lepszy niż cztery 100-wierszowe moduły, które przeciekają te same połączenia.
- Mechaniczne czytanie Clean Code lub SOLID (bardzo małe funkcje, jedna klasa na każdą odpowiedzialność) daje płytkie moduły. Ta umiejętność ma priorytet nad tym naciskiem.

## Koszt czytelnika: trzeci test

Test głębokości i test inwariantu decydują, czy granica musi istnieć. Test kosztu czytelnika decyduje, czy kod wokół granicy jest tani w zmianie. Następny czytelnik, osoba lub agent, płaci za każdą linię, którą musi przeczytać. Agent płaci tokenami. Agent znajduje kod przez wyszukiwanie tekstowe, częściowe czytania, sprawdzanie typów i testy.

- **Znajdowalny.** Używaj jednej nazwy dla każdego pojęcia. Pisownia wszędzie taka sama, aby zwykłe wyszukiwanie tekstowe je znalazło. Wady: nazwy zbudowane ze stringów, okablowanie przez efekty uboczne importu, dwie nazwy dla jednego pojęcia. Łańcuchy re-eksportów ukrywające definicję to też wady.
- **Wczesne zatrzymanie.** Umieść kontrakt na górze pliku lub nad eksportem. Powiedz, co obiecuje, co ukrywa i czego nigdy nie robi. Wtedy czytelnik może się zatrzymać wcześniej.
- **Możliwe do sprawdzenia maszynowo.** Używaj dokładnych typów na wejściu i wyjściu każdej granicy, tak aby sprawdzenie typów zastąpiło czytanie wywołujących. Wady: `any`, zwykłe słowniki, flagi boolean, których znaczenie jest tylko w ciele.
- **Widoczne sprzężenie.** Dwa miejsca muszą zmieniać się razem. Wymuszaj to wspólnym typem, testem lub pojedynczym źródłem. Jeśli nie możesz, oznacz to w obu miejscach.
- **Brak szumu.** Usuń komentarze powtarzające kod i kod zakomentowany. Usuń martwe gałęzie i komentarze zapisujące historię zmian. Usuń starą ścieżkę, która pozostaje obok swojej zamiany.
- **Przewidywalny.** Przestrzegaj istniejącego układu repozytorium. Umieść test tam, gdzie czytelnik go szuka, i spraw, by działał samodzielnie.

Rozmiar pliku nie jest na tej liście celowo. Bardzo duży plik to powód, by szukać drugiej ukrytej decyzji. Nigdy nie jest powodem do cięcia pliku.

## Bezpieczeństwo

Dla istniejącego kodu najpierw napisz test, który utrzymuje obecne zachowanie. Potem pogłęb moduł. Dla nowego kodu napisz test definiujący zamierzone zachowanie.

## Notatka projektowa (wymagana, gdy brama ma zastosowanie)

Gdy brama ma zastosowanie, umieść sekcję z nagłówkiem `## Design note` w opisie pull requesta. Napisz dwa do czterech wierszy:

- Każdą granicę, którą dodałeś, i decyzję, którą ukrywa.
- Każdą duplikację, którą celowo zachowałeś, i powód.
- Każdą płytką część, którą zaakceptowałeś, i powód.

Jeśli brama nie ma zastosowania, napisz `## Design note` a następnie `Gate not applicable: <reason>`. Umieść też notatkę projektową w podsumowaniu twojego ostatniego kroku.

## Tryb przeglądu

Użyj tej sekcji, gdy przeglądasz lub testujesz kod napisany przez innego agenta lub osobę.

1. Sprawdź notatkę projektową. Gdy brama ma zastosowanie, a pull request nie ma sekcji `## Design note`, zgłoś blokujący problem. Gdy notatka nie zgadza się z diffem, zgłoś blokujący problem.
2. Znalezisko projektowe jest blokujące tylko wtedy, gdy spełnia oba warunki:
   - Naznacza regułę tej umiejętności. Regułą jest reguła decyzyjna, brama, test inwariantu lub element kosztu czytelnika.
   - Stwierdza konkretny koszt dla czytelnika lub następnej zmiany. Przykłady: "Wywołujący muszą znać kształt przechowywania." "Jedno pojęcie ma dwie nazwy." "Zmiana limitu wymaga edycji w trzech plikach."
3. Oznacz każde inne spostrzeżenie projektowe jako nieblokujące. Umieść je na osobnej liście pod tytułem "Notatki projektowe nieblokujące". Notatka nieblokująca nigdy nie odsyła pracy z powrotem do twórcy.
4. Nie zgłaszaj preferencji jako znaleziska. Inna nazwa, układ pliku lub styl to preferencja. Staje się znaleziskiem tylko wtedy, gdy łamie nazwaną regułę i ma konkretny koszt.
5. Gdy to samo znalezisko projektowe pojawi się ponownie w drugim cyklu przeglądu, eskaluj je. Nie żądaj tej samej zmiany po raz trzeci.

## Powiązane umiejętności (po zainstalowaniu)

- `find-shared-code`: raportowe wyszukiwanie w historii ostatnich zmian kodu wartego dzielenia. Używa testu inwariantu i testu głębokości tej umiejętności.
- `refactoring` i `working-effectively-with-legacy-code`: bezpieczne kroki ku głębszemu projektowi. Ta umiejętność decyduje, czy nowa granica pozostaje.

## Źródło i licencja

Ta umiejętność opiera się na "mini" zasadach z książki A Philosophy of Software Design w repozytorium ciembor/agent-rules-books na GitHub (licencja MIT, commit 893a88a). Brama, test inwariantu, test kosztu czytelnika, notatka projektowa oraz tryb przeglądu są dodatkami do tych zasad. Repozytorium zawiera również pełne zasady z książki.

Tagi

designarchitectureousterhoutreview

Warto przeczytać

Pobierz AgentsRoom

Uruchamiaj wszystkich swoich agentów AI, we wszystkich projektach, z jednego okna.

Za darmoPobierz AgentsRoom

Aplikacja towarzysząca: monitoruj agentów w podróży

Użyj Claude, Codex, Antigravity CLI lub innego dostawcy AI.

Zainstaluj rozszerzenie
Chrome Web Store

Wysyłaj bugi i prośby bezpośrednio do swojego publicznego backlogu.

Wiele projektów
Multi-provider
Wielu agentów
Status na żywo
Diff i commit
Aplikacja mobilna
Podgląd na żywo
Zespoły agentów
Testy w przeglądarce
Dev oparta na backlogu
Biblioteka promptów
Biblioteka umiejętności
Zobacz wszystkie funkcje