Slovník pojmů
Deptrac
Adresáře samy o sobě architekturu nevynutí. Deptrac převádí domluvené hranice mezi vrstvami do kontroly, která může selhat už v pull requestu.
Stručná definice
Kontrola toho, kdo smí záviset na kom.
Deptrac analyzuje odkazy mezi třídami, rozhraními, traity a dalšími prvky kódu. Ty nejdříve zařadí do vrstev, například Domain, Application, Infrastructure a UI. Pravidla pak řeknou, které vrstvy se smějí používat; neplatný směr závislosti vypíše jako porušení.
Nejde o nástroj, který rozhodne, zda je aplikace dobře navržená. Umožní však průběžně hlídat konkrétní rozhodnutí týmu: například aby doménové pravidlo neimportovalo ORM, controller nepracoval přímo s databázovým adaptérem a infrastruktura zůstala na okraji systému.
Použití
Kde automatické hranice dávají smysl
Kontrola se vyplatí tam, kde se aplikace rozvíjí delší dobu a nesprávný směr závislosti by postupně zhoršoval změny i testování.
- modulární monolit s více doménovými moduly
- Clean nebo hexagonální architektura s oddělením logiky a adaptérů
- interní systém, kde HTTP, CLI a fronta sdílejí stejné aplikační případy
- e-shop s odděleným katalogem, objednávkami, skladem a integracemi
- omezení přímého používání frameworku nebo vybraných Composer balíčků mimo infrastrukturu
- CI kontrola, že nový pull request neobchází domluvené hranice
Praktický příklad
Čtyři vrstvy importu objednávky
V modulu objednávek drží Domain pravidla a hodnotové objekty. Application obsahuje případ použití ImportMarketplaceOrder a jeho port pro uložení objednávky. Infrastructure implementuje tento port přes databázi nebo HTTP klienta. UI přijme HTTP požadavek nebo CLI příkaz a předá jej aplikační vrstvě.
Pokud by controller začal přímo volat Doctrine repository, nebo Domain importoval Laravel či Symfony třídu, Deptrac může změnu odmítnout. Není tím potvrzeno, že import funguje; je pouze ověřeno, že se neobešla zvolená hranice.
deptrac:
paths: [./src]
layers:
- name: Domain
collectors: [{ type: classLike, value: '^App\\Domain\\.*' }]
- name: Application
collectors: [{ type: classLike, value: '^App\\Application\\.*' }]
- name: Infrastructure
collectors: [{ type: classLike, value: '^App\\Infrastructure\\.*' }]
- name: UI
collectors: [{ type: classLike, value: '^App\\UI\\.*' }]
ruleset:
Domain: ~
Application: [Domain]
Infrastructure: [Application, Domain]
UI: [Application]
Jak funguje
Od kódu k architektonickému pravidlu
Konfigurace má popsat skutečnou hranici aplikace, ne jen mechanicky kopírovat názvy adresářů.
- Cesty Deptrac načte určené adresáře a sestaví mapu závislostí mezi prvky PHP kódu.
- Collectory Collector rozhodne, které prvky patří do vrstvy; může vybírat například podle plného názvu třídy, adresáře, atributu, rozhraní nebo Composer balíčku.
- Vrstvy Pojmenované skupiny vyjadřují pohled na aplikaci. Jeden prvek může podle konfigurace patřit i do více vrstev, což je důvod kontrolovat výstup a varování.
- Ruleset Pravidla povolí konkrétní směr závislostí. Závislost mezi vrstvami je ve výchozím stavu zakázaná, dokud ji ruleset nepovolí.
- Report a CI Analýza ukáže soubor, řádek a nepovolený směr. CI pak může blokovat nová porušení před mergem.
Hlavní pojmy
Vrstvy, collectory a pravidla
Deptrac nekontroluje jednu univerzální architekturu. Kontroluje model, který aplikace sama popíše.
Layers
Vrstvy jsou skupiny prvků kódu, například Domain nebo UI. Nejsou automaticky stejné jako adresáře, i když je adresář často praktickým výchozím bodem.
Collectors
Collectory přiřazují prvky do vrstvy. Běžný classLike collector porovnává plně kvalifikovaný název; directory sleduje cestu souboru a composer může vymezit používání balíčku.
Ruleset
Ruleset vyjadřuje povolené závislosti. Application může znát Domain; Infrastructure může implementovat port definovaný v Application; UI má volat Application, ne databázový adaptér.
Porušení a uncovered
Porušení je nepovolený odkaz mezi vrstvami. Uncovered závislost znamená, že analyzovaný prvek odkazuje na třídu, která není přiřazena k žádné vrstvě; nejde sama o sobě o porušení rulesetu.
Vztah k ostatním kontrolám
Jiná otázka než PHPStan, PHPUnit nebo DI
Tyto nástroje se doplňují, ale každý zachycuje jiný typ rizika.
- Deptrac a PHPStan
- PHPStan ověřuje typy, neplatná volání a kontrakty jednotlivých výrazů. Deptrac ověřuje, zda je vůbec přípustné, aby třída z jedné vrstvy používala jinou vrstvu.
- Deptrac a PHPUnit
- PHPUnit aplikaci spouští v testovacím scénáři a ověřuje chování. Deptrac kód nespouští a neprokazuje funkčnost use casu.
- Deptrac a dependency injection
- DI je runtime způsob sestavení objektů. Deptrac sleduje statické odkazy v kódu; správně injektovaná služba může stále porušovat architektonickou hranici.
- Diagramy
- Formáttery mohou vytvořit například Graphviz nebo Mermaid výstup. Diagram pomáhá architekturu prohlédnout, ale pravidla v CI jsou to, co ji průběžně vynucuje.
Výhody a omezení
Ochrana hranic, ne náhrada návrhu
Přínosy
- architektonický úmysl je čitelný jako verzovaná konfigurace
- porušení se objeví u konkrétní změny, ne až při obtížném refaktoringu
- pomáhá zachovat nezávislost modulů a doménové logiky na frameworku
- stejná kontrola se opakuje lokálně i v CI
Omezení a časté chyby
- zelený report neříká, zda vrstvy dávají businessově smysl
- příliš obecné regulární výrazy a vrstvy mohou vytvářet falešný pocit kontroly
- složitá konfigurace a mnoho výjimek mohou být dražší než chráněná část aplikace
- adresář Domain bez skutečných pravidel není automaticky doménový model
Hranice použití
Pravidla mají růst spolu se skutečnou složitostí projektu.
Malý skript nebo jednoduchý administrativní formulář nepotřebuje čtyři vrstvy jen proto, aby prošel Deptracem. U dlouhodobého modulu s externími API, frontou, databází a více vstupními body se naopak vyplatí chránit, aby technické detaily nepronikaly do aplikační a doménové logiky.
Pro starší aplikaci lze známá porušení dočasně vynechat pomocí skip_violations nebo vygenerované baseline. Výjimky mají mít důvod a vlastníka; jejich opakované rozšiřování bez odstraňování znamená, že CI již nechrání novou změnu dostatečně.
Na co myslet
Udržovat pravidla jako součást aplikace
Užitečný report je konkrétní, srozumitelný týmu a vychází z reálného směru závislostí.
- začít několika významnými hranicemi místo kompletní mapy všech tříd
- pojmenovat vrstvy podle odpovědnosti, ne podle módního vzoru
- reportovat uncovered závislosti a rozhodovat, zda je třeba je pokrýt
- nechat Deptrac běžet v CI spolu s testy a typovou analýzou
- výjimky a baseline pravidelně zmenšovat a kontrolovat při review
Časté otázky
Co Deptrac ověřuje
Nahradí Deptrac PHPStan nebo PHPUnit?
Ne. PHPStan hledá typové a kontraktní chyby, PHPUnit ověřuje chování spuštěné aplikace. Deptrac kontroluje jen povolený směr závislostí mezi vrstvami.
Je Deptrac nutný pro každou PHP aplikaci?
Ne. Největší přínos má u dlouhodobě rozvíjených modulů s jasně oddělenými odpovědnostmi. U malého, přímočarého projektu může být konfigurace zbytečná režie.
Stačí rozdělit třídy do adresářů?
Ne. Adresář je organizační pomůcka, ale bez rulesetu nic nebrání controlleru importovat infrastrukturní repository nebo doméně použít frameworkovou třídu.
Jsou baseline a skip_violations chyba?
Ne nutně. U existujícího projektu dovolí zavést kontrolu postupně. Musí ale být konkrétní, zdůvodněné a postupně se zmenšovat; jinak jen skrývají porušení.
Jak architektonické hranice používám v praxi
Architekturu chráním jen tam, kde zjednodušuje bezpečné změny.
Ve veřejném projektu scheduling jsou moduly členěné na Domain, Application, Infrastructure a UI. Konfigurace Deptracu ověřuje vybrané závislosti; jde o konkrétní ukázku, ne univerzální šablonu pro každou aplikaci.