ImpactGate is een tool die is ontworpen om structureel verval in softwareprojecten te detecteren en te voorkomen. Het berekent de 'change-impact' van een wijziging met een formule die rekening houdt met de bestaande complexiteit van de container (zoals een klasse of methode) en het aantal gewijzigde regels. Hierdoor wordt het toevoegen van code aan reeds complexe bestanden zwaarder gescoord dan het toevoegen van nieuwe bestanden.
De tool biedt diverse integratiemogelijkheden:
- Lokaal: Gebruik als CLI, via Docker of als Git pre-commit hook.
- CI/CD: Naadloze integratie met GitHub Actions, GitLab CI en Jenkins.
Een geavanceerde functie is de 'grading curve', waarbij wijzigingen niet tegen een vaste drempelwaarde worden getoetst, maar op basis van percentielen binnen een distributie van projecthistorie en seed-data. Gebruikers kunnen via een configuratiebestand (.impact-gate.yml) bepalen of de tool enkel waarschuwt of wijzigingen volledig blokkeert.
ImpactGate: Code Review via de Change Impact Measure
Website: https://impactgate.officefloor.net
Wat is structureel verval?
Structureel verval is de ophoping van complexiteit in bestaande structuren. Een voorbeeld hiervan is een 'god-method' die een extra vertakking krijgt, of een 'god-class' die een extra methode krijgt. De tool scoort een wijziging ten opzichte van een basislijn (standaard main) met de volgende change-impact formule:
impact = fileschanged Σ max(WMCother, 1) CC * Δlines (over gewijzigde functies)
Hierbij is WMC_other de complexiteit die al aanwezig is in de container die wordt bewerkt, gemeten in de staat vóór de wijziging. Het importeren van een volledig nieuw bestand of een nieuwe klasse is daarom "goedkoop", omdat er nog niets aanwezig was. Het toevoegen van code aan een reeds zware klasse is daarentegen "duur". Dit vormt het signaal voor structureel verval.
Voor de theoretische onderbouwing van deze formule kan worden verwezen naar het artikel Measuring the Blast Radius of Change op de OfficeFloor-blog.
Wanneer de impact te hoog is, vraagt de tool om de wijziging te vereenvoudigen of de betreffende code te refactoren. De tool kan worden ingesteld om enkel te waarschuwen (rapportage) of om de wijziging volledig te blokkeren (de build laten falen).
Installatie
Via pip:
pip install impact-gate # installeert het `impact-gate` commando
Via Docker (zonder installatie): Gebruik de gepubliceerde image (git is inbegrepen; mount de repo naar /repo om te kunnen scoren):
docker run --rm -v "$PWD:/repo" ghcr.io/officefloor/impact-gate \
score --mode range --base origin/main
Voor lokale ontwikkeling:
python -m venv .venv && . .venv/bin/activate
pip install -e '.[dev]' # editable install inclusief test-dependencies
Gebruik
CLI Commando's
- Staged wijzigingen (pre-commit): Vergelijking tussen staged en HEAD (standaard).
``bash impact-gate score ``
- Niet-gecommitteerde lokale wijzigingen: Vergelijking tussen working tree en HEAD.
``bash impact-gate score --mode worktree ``
- CI of PR review: Vergelijking tussen de committed branch en main (
merge-base..HEAD).
``bash impact-gate score --mode range --base origin/main --format json ``
- Drempelwaarden en handhaving instellen: (Kan ook in
.impact-gate.yml).
``bash impact-gate score --warn-at 50000 --block-at 200000 --enforcement block ``
Exit codes:
0: OK of waarschuwing (de wijziging is toegestaan).
2: Geblokkeerd (impact is te hoog bij --enforcement block).
1: Gebruiks- of omgevingsfout.
Rapportage en filtering
Elk rapport bevat een lijst met bestanden die in aanmerking komen voor refactoring, gerangschikt naar hun aandeel in de totale impact. Terwijl het totaalcijfer op wijzigingsniveau bepaalt of de commit door mag, wijst de ranglijst per bestand aan waar het verval zich concentreert. Zo wordt een bestand dat langzaam uitgroeit tot een 'god-class' zichtbaar voordat het daadwerkelijk wijzigingen blokkeert.
Bestanden waarvan de diff groter is dan maxdifflines (standaard 200.000) worden beschouwd als gegenereerde dumps of externe blobs. De tool slaat deze over om vervorming van de score en vertraging te voorkomen. Deze bestanden worden vermeld onder 'skipped'.
Git pre-commit hook
Om elke commit lokaal te controleren vóór de CI-fase:
# Installeert .git/hooks/pre-commit
impact-gate install-hook
Bij handhaving via .impact-gate.yml wordt een commit met een te hoge impact geblokkeerd. Bij de instelling warn (of off) wordt het rapport geprint maar gaat de commit door. Gebruik --force om een bestaande hook te overschrijven.
Gebruik met het pre-commit framework: Voeg de volgende definitie toe aan .pre-commit-config.yaml:
repos:
- repo: https://github.com/officefloor/ImpactGate
rev: v0.3.0
hooks:
- id: impact-gate
Beoordeling via een distributie (De Curve)
Het instellen van een vaste drempelwaarde is lastig, omdat de impact van een typische wijziging sterk verschilt per taal en project. In plaats van een vast getal kan een wijziging worden beoordeeld op basis van het percentiel binnen een distributie.
Baseline maken: Bouw of ververs de impact-distributie van het project op basis van de merge-historie:
impact-gate baseline --base-ref main
# Schrijft naar .impact-gate-baseline.json
Beoordelen op percentiel:
impact-gate score --curve --warn-percentile 90 --block-percentile 98
De beoordeling combineert twee distributies:
- Seed prior: Per-taal percentieltabellen gebaseerd op een corpus van 20 open-source repo's.
- Project baseline: De eigen distributie van het project, gebaseerd op de merge-historie van de mainline.
De weging van het project wordt bepaald door $w = n / (n + K)$, waarbij $n$ het aantal gelande wijzigingen is en $K$ (curvepriorweight, standaard 200) de hoeveelheid historie is die nodig is om het project zwaarder te laten wegen dan de seed.
Configuratie via .impact-gate.yml
De configuratie kan in de root van de repository worden geplaatst:
warn_at: 50000 # Impact waarbij een waarschuwing wordt gegeven
block_at: 200000 # Impact waarbij de wijziging wordt geblokkeerd
enforcement: warn # Opties: off, warn, of block.
tolerance: 1.0 # Vermenigvuldigingsfactor voor drempelwaarden (bijv. 1.1 is milder)
# measure_config: .impact-measure.yml # Optioneel: voor ignore globs en taal-overrides
# Grading curve (percentiel-beoordeling)
curve_enabled: false # Indien true, worden warn_at/block_at genegeerd
warn_percentile: 90 # Waarschuwing bij dit percentiel of hoger
block_percentile: 98 # Blokkeren bij dit percentiel of hoger
curve_prior_weight: 200 # K in w = n/(n+K)
baseline_file: .impact-gate-baseline.json # Locatie van de baseline-cache
CLI-flags hebben prioriteit boven het configuratiebestand.
Integratie met CI/CD
GitHub Actions
Voeg een workflow toe aan de repository. De action scoort de PR-branch tegen de base-branch en plaatst een samenvatting. fetch-depth: 0 is vereist.
name: Change impact
on: pull_request
permissions:
contents: read
pull-requests: write # Nodig voor het plaatsen van de PR-comment
jobs:
impact:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: officefloor/ImpactGate@v0
with:
enforcement: warn
De score verschijnt in de job-summary en als een 'sticky comment' op de PR. In block mode faalt de job wanneer de drempelwaarde wordt overschreden.
GitLab CI
Gebruik de kant-en-klare job uit ci/gitlab-ci.yml of include deze remote:
include:
- remote: 'https://raw.githubusercontent.com/officefloor/ImpactGate/v0/ci/gitlab-ci.yml'
Het draait op merge-request pipelines en gebruikt de gepubliceerde Docker image. Indien een GITLAB_TOKEN (met api scope) is ingesteld, wordt er een sticky note in de MR geplaatst.
Jenkins
Een pipeline snippet is beschikbaar in ci/Jenkinsfile. Dit draait de Docker image op een agent met Docker, scoort de wijziging tegen de target branch (standaard origin/main) en archiveert het rapport.
Roadmap
- Core CLI: Score staged, worktree of range. Warn of block. Text, JSON, markdown. (Klaar)
- GitHub Action: Composite action, job-summary rapport en sticky PR comment. (Klaar)
- Baseline en grading curve: Project profiling en blending van seed-corpus met projectdistributie. (Klaar)
- Distributie: pip install, Docker image en version-tagged Action (@v0). (Klaar)
- CI-plugins: GitLab CI template en Jenkins pipeline snippet. (Klaar)
- Hooks: Git pre-commit hook en ondersteuning voor pre-commit framework. (Klaar)
- IDE: Integratie via LSP met een live indicator tijdens het programmeren. (Toekomst)
ImpactGate: Code Review via de Change Impact Measure
Website: https://impactgate.officefloor.net
Wat is structureel verval?
Structureel verval is de ophoping van complexiteit in bestaande structuren. Een voorbeeld hiervan is een 'god-method' die een extra vertakking krijgt, of een 'god-class' die een extra methode krijgt. De tool scoort een wijziging ten opzichte van een basislijn (standaard main) met de volgende change-impact formule:
impact = fileschanged Σ max(WMCother, 1) CC * Δlines (over gewijzigde functies)
Hierbij is WMC_other de complexiteit die al aanwezig is in de container die wordt bewerkt, gemeten in de staat vóór de wijziging. Het importeren van een volledig nieuw bestand of een nieuwe klasse is daarom "goedkoop", omdat er nog niets aanwezig was. Het toevoegen van code aan een reeds zware klasse is daarentegen "duur". Dit vormt het signaal voor structureel verval.
Voor de theoretische onderbouwing van deze formule kan worden verwezen naar het artikel Measuring the Blast Radius of Change op de OfficeFloor-blog.
Wanneer de impact te hoog is, vraagt de tool om de wijziging te vereenvoudigen of de betreffende code te refactoren. De tool kan worden ingesteld om enkel te waarschuwen (rapportage) of om de wijziging volledig te blokkeren (de build laten falen).
Installatie
Via pip:
pip install impact-gate # installeert het `impact-gate` commando
Via Docker (zonder installatie): Gebruik de gepubliceerde image (git is inbegrepen; mount de repo naar /repo om te kunnen scoren):
docker run --rm -v "$PWD:/repo" ghcr.io/officefloor/impact-gate \
score --mode range --base origin/main
Voor lokale ontwikkeling:
python -m venv .venv && . .venv/bin/activate
pip install -e '.[dev]' # editable install inclusief test-dependencies
Gebruik
CLI Commando's
- Staged wijzigingen (pre-commit): Vergelijking tussen staged en HEAD (standaard).
``bash impact-gate score ``
- Niet-gecommitteerde lokale wijzigingen: Vergelijking tussen working tree en HEAD.
``bash impact-gate score --mode worktree ``
- CI of PR review: Vergelijking tussen de committed branch en main (
merge-base..HEAD).
``bash impact-gate score --mode range --base origin/main --format json ``
- Drempelwaarden en handhaving instellen: (Kan ook in
.impact-gate.yml).
``bash impact-gate score --warn-at 50000 --block-at 200000 --enforcement block ``
Exit codes:
0: OK of waarschuwing (de wijziging is toegestaan).
2: Geblokkeerd (impact is te hoog bij --enforcement block).
1: Gebruiks- of omgevingsfout.
Rapportage en filtering
Elk rapport bevat een lijst met bestanden die in aanmerking komen voor refactoring, gerangschikt naar hun aandeel in de totale impact. Terwijl het totaalcijfer op wijzigingsniveau bepaalt of de commit door mag, wijst de ranglijst per bestand aan waar het verval zich concentreert. Zo wordt een bestand dat langzaam uitgroeit tot een 'god-class' zichtbaar voordat het daadwerkelijk wijzigingen blokkeert.
Bestanden waarvan de diff groter is dan maxdifflines (standaard 200.000) worden beschouwd als gegenereerde dumps of externe blobs. De tool slaat deze over om vervorming van de score en vertraging te voorkomen. Deze bestanden worden vermeld onder 'skipped'.
Git pre-commit hook
Om elke commit lokaal te controleren vóór de CI-fase:
# Installeert .git/hooks/pre-commit
impact-gate install-hook
Bij handhaving via .impact-gate.yml wordt een commit met een te hoge impact geblokkeerd. Bij de instelling warn (of off) wordt het rapport geprint maar gaat de commit door. Gebruik --force om een bestaande hook te overschrijven.
Gebruik met het pre-commit framework: Voeg de volgende definitie toe aan .pre-commit-config.yaml:
repos:
- repo: https://github.com/officefloor/ImpactGate
rev: v0.3.0
hooks:
- id: impact-gate
Beoordeling via een distributie (De Curve)
Het instellen van een vaste drempelwaarde is lastig, omdat de impact van een typische wijziging sterk verschilt per taal en project. In plaats van een vast getal kan een wijziging worden beoordeeld op basis van het percentiel binnen een distributie.
Baseline maken: Bouw of ververs de impact-distributie van het project op basis van de merge-historie:
impact-gate baseline --base-ref main
# Schrijft naar .impact-gate-baseline.json
Beoordelen op percentiel:
impact-gate score --curve --warn-percentile 90 --block-percentile 98
De beoordeling combineert twee distributies:
- Seed prior: Per-taal percentieltabellen gebaseerd op een corpus van 20 open-source repo's.
- Project baseline: De eigen distributie van het project, gebaseerd op de merge-historie van de mainline.
De weging van het project wordt bepaald door $w = n / (n + K)$, waarbij $n$ het aantal gelande wijzigingen is en $K$ (curvepriorweight, standaard 200) de hoeveelheid historie is die nodig is om het project zwaarder te laten wegen dan de seed.
Configuratie via .impact-gate.yml
De configuratie kan in de root van de repository worden geplaatst:
warn_at: 50000 # Impact waarbij een waarschuwing wordt gegeven
block_at: 200000 # Impact waarbij de wijziging wordt geblokkeerd
enforcement: warn # Opties: off, warn, of block.
tolerance: 1.0 # Vermenigvuldigingsfactor voor drempelwaarden (bijv. 1.1 is milder)
# measure_config: .impact-measure.yml # Optioneel: voor ignore globs en taal-overrides
# Grading curve (percentiel-beoordeling)
curve_enabled: false # Indien true, worden warn_at/block_at genegeerd
warn_percentile: 90 # Waarschuwing bij dit percentiel of hoger
block_percentile: 98 # Blokkeren bij dit percentiel of hoger
curve_prior_weight: 200 # K in w = n/(n+K)
baseline_file: .impact-gate-baseline.json # Locatie van de baseline-cache
CLI-flags hebben prioriteit boven het configuratiebestand.
Integratie met CI/CD
GitHub Actions
Voeg een workflow toe aan de repository. De action scoort de PR-branch tegen de base-branch en plaatst een samenvatting. fetch-depth: 0 is vereist.
name: Change impact
on: pull_request
permissions:
contents: read
pull-requests: write # Nodig voor het plaatsen van de PR-comment
jobs:
impact:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: officefloor/ImpactGate@v0
with:
enforcement: warn
De score verschijnt in de job-summary en als een 'sticky comment' op de PR. In block mode faalt de job wanneer de drempelwaarde wordt overschreden.
GitLab CI
Gebruik de kant-en-klare job uit ci/gitlab-ci.yml of include deze remote:
include:
- remote: 'https://raw.githubusercontent.com/officefloor/ImpactGate/v0/ci/gitlab-ci.yml'
Het draait op merge-request pipelines en gebruikt de gepubliceerde Docker image. Indien een GITLAB_TOKEN (met api scope) is ingesteld, wordt er een sticky note in de MR geplaatst.
Jenkins
Een pipeline snippet is beschikbaar in ci/Jenkinsfile. Dit draait de Docker image op een agent met Docker, scoort de wijziging tegen de target branch (standaard origin/main) en archiveert het rapport.
Roadmap
- Core CLI: Score staged, worktree of range. Warn of block. Text, JSON, markdown. (Klaar)
- GitHub Action: Composite action, job-summary rapport en sticky PR comment. (Klaar)
- Baseline en grading curve: Project profiling en blending van seed-corpus met projectdistributie. (Klaar)
- Distributie: pip install, Docker image en version-tagged Action (@v0). (Klaar)
- CI-plugins: GitLab CI template en Jenkins pipeline snippet. (Klaar)
- Hooks: Git pre-commit hook en ondersteuning voor pre-commit framework. (Klaar)
- IDE: Integratie via LSP met een live indicator tijdens het programmeren. (Toekomst)