Aller au contenu principal
Développement

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.

ADR Fitness functions Deptrac CI/CD GitHub Actions PHP Architecture

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 Facturation et Catalogue. Toute communication passe par App\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.

Dans la même veine