Vos ADR ne servent à rien si le code les ignore fitness functions et CI/CD
20 ADR dans /adr, et le code a dérivé. ADR-0005 interdisait le couplage entre Facturation et Catalogue il y a maintenant 7 imports croisés. Voici comment faire appliquer les décisions par la machine.
Cet article conclut la série sur les ADR. Si vous découvrez le concept, commencez par l'article 1. L'article 2 couvre l'installation et les templates.
La dérive silencieuse
Votre équipe a 20 ADR dans /adr. Personne ne les relit. Le code a évolué. ADR-0005 était pourtant clair :
"Pas de couplage direct entre les modules
FacturationetCatalogue. Toute communication passe parApp\Shared."
Il y a aujourd'hui 7 imports App\Catalogue dans des classes de App\Facturation. L'ADR est correct. Le code ne l'est plus. Et personne n'a rien détecté.
La réponse honnête à "combien de nos ADR sont encore respectés ?" dans un projet actif de 2 ans sans outillage : moins qu'on ne le croit. Les fitness functions répondent à ça.
Ce que sont les fitness functions
Une fitness function est un test automatisé qui vérifie qu'une décision architecturale est toujours respectée dans le code.
Ce n'est pas un test unitaire. Un test unitaire vérifie que le code fait ce qu'il doit faire. Une fitness function vérifie que le code est ce qu'il doit être — que sa structure, ses dépendances, et ses couplages respectent les décisions prises.
Implémentation PHP/Symfony
PHPUnit + réflexion — zéro dépendance supplémentaire
<?php
// tests/Architecture/FacturationArchitectureTest.php
// @enforces ADR-0005 — No direct coupling between Facturation and Catalogue modules
namespace App\Tests\Architecture;
use PHPUnit\Framework\TestCase;
class FacturationArchitectureTest extends TestCase
{
public function testFacturationDoesNotImportCatalogue(): void
{
$facturationPath = __DIR__ . '/../../src/Facturation';
$violations = [];
$iterator = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($facturationPath)
);
foreach ($iterator as $file) {
if ($file->getExtension() !== 'php') {
continue;
}
$content = file_get_contents($file->getPathname());
if (str_contains($content, 'App\\Catalogue')) {
$violations[] = $file->getPathname();
}
}
$this->assertEmpty(
$violations,
sprintf(
"ADR-0005 violation: %d file(s) in App\\Facturation import App\\Catalogue directly.\n%s",
count($violations),
implode("\n", $violations)
)
);
}
}
Deptrac — l'outil dédié aux dépendances PHP
composer require --dev qossmic/deptrac-shim
# deptrac.yaml
parameters:
paths: ['src']
layers:
- name: Facturation
collectors:
- type: className
regex: ^App\\Facturation\\
- name: Catalogue
collectors:
- type: className
regex: ^App\\Catalogue\\
- name: Shared
collectors:
- type: className
regex: ^App\\Shared\\
ruleset:
Facturation:
- Shared
Catalogue:
- Shared
./vendor/bin/deptrac analyse --config-file=deptrac.yaml
Intégration CI/CD avec GitHub Actions
# .github/workflows/adr-fitness.yml
name: ADR Fitness Functions
on:
pull_request:
branches: [main, develop]
jobs:
architecture-check:
name: Check architecture constraints
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
- name: Install dependencies
run: composer install --no-dev --optimize-autoloader
- name: Run Deptrac
run: |
composer require --dev qossmic/deptrac-shim
./vendor/bin/deptrac analyse --config-file=deptrac.yaml
continue-on-error: false
- name: Run PHPUnit architecture tests
run: ./vendor/bin/phpunit tests/Architecture/
Le paramètre continue-on-error: false est intentionnel. Si Deptrac ou PHPUnit détecte une violation, le workflow échoue et la PR ne peut pas être mergée.
Decision Guardian : surfacer les ADR pertinents sur les PRs
"Ces décisions s'appliquent à vos changements : ADR-0003 (doctrine/migrations), ADR-0007 (structure des modules métier)."
Deptrac bloque, Decision Guardian rappelle. Les deux se complètent.
Ce que cette série couvre — et ce qu'elle ne couvre pas
- Article 1 : comprendre ce qu'est un ADR et rédiger le premier en 15 minutes
- Article 2 : installer, choisir un template, intégrer à Git
- Article 3 : faire appliquer les décisions par la machine
Les ADR sont un investissement d'équipe sur le long terme. En solo, c'est un investissement envers votre futur vous-même.
Le workflow GitHub Actions complet et la configuration Deptrac sont disponibles dans le repo de la série sur GitHub CodexLab.