yonatankarp/software-design-skills

arch-fitness-functions

Use when enforcing architectural characteristics through automation — phrases like "architecture fitness function", "evolutionary architecture", "architecture tests", "ArchUnit", "dependency rules in CI", "automated architecture checks", "guardrails", "drif…

소스 보기

사용 방법

  1. 설치 명령을 복사하고 자신의 에이전트 환경에 설치하기 전에 소스 패키지를 확인하세요.
  2. 필요한 도구, 인증 정보, 지원 환경은 원본 문서에서 확인하세요.
  3. 입력과 원하는 산출물을 설명하고 출처와 결과를 대조하세요.
npx skills add https://github.com/yonatankarp/software-design-skills --skill arch-fitness-functions

시작 전 확인

  • 설치에는 모델 구독, API 한도, 파일 접근 권한이 포함되지 않습니다.
  • 별점 수와 설치 수는 활동 지표이며 독립적인 품질·보안 검증이 아닙니다.
원본 Skill 문서

원본 저장소의 제목, 예시, 코드, 표, 링크, 이미지를 유지해 표시합니다.

One-line summary

Encode architectural intent as automated checks that run on every change. If the architecture says "the domain layer doesn't depend on Spring", a fitness function fails the build when it does.

When to use this skill

  • An architecture decision matters and needs to stay true over time (dependency direction, layer boundaries, no cyclic dependencies, performance budgets).
  • Teams are large enough that informal "we agreed not to do X" doesn't hold across all PRs.
  • Migration projects (arch-strangler-fig) where you want to enforce that new code lives in the new shape and not the legacy.
  • Any architectural decision where you'd otherwise rely on code review to catch drift.

When NOT to use this skill

  • Tiny project, single developer, no scaling problem.
  • The architectural property is genuinely subjective and not automatable (taste, aesthetics, naming style on edge cases).
  • Over-policing — every architectural rule has a cost; only enforce what you would block a PR over.

Core content

A fitness function is a test that asserts an architectural property. Like unit tests, they:

  • Run automatically in CI on every change.
  • Fail the build if violated.
  • Document the architectural intent in executable form.

Categories of fitness function (Ford, Parsons, Kua, Building Evolutionary Architectures):

  • Atomic vs holistic. Atomic checks a single property (no cycles in this module). Holistic combines multiple properties (performance + correctness under load).
  • Triggered vs continual. Triggered runs on each build (most useful). Continual runs in production (latency budgets, error rates).
  • Static vs dynamic. Static analyses code (dependency direction). Dynamic runs the system (response-time check).

Common static fitness functions (these are the most accessible to start with):

  • Dependency direction. "Module X must not depend on module Y." Enforced via build graph or a dedicated library (ArchUnit for JVM, ts-arch for TypeScript, dependency-cruiser for JS).
  • No cyclic dependencies. Detects accidental cycles introduced by a misplaced import.
  • Naming conventions. "Every class in controller/ must end in Controller." Mostly cosmetic but cheap to enforce.
  • Public API stability. "No new public methods on this interface without a corresponding test." Custom check.
  • Layer boundary violations. "Code in domain/ must not import from infrastructure/." The classic hexagonal check.

Dynamic fitness functions for production architecture:

  • p99 latency under a threshold.
  • Memory usage bounded.
  • Specific business invariants holding (no negative balances; no duplicate orders).

Example with ArchUnit (JVM, the most mature ecosystem):

kotlin
@ArchTest
val domainHasNoSpringDependencies =
    noClasses().that().resideInAPackage("..domain..")
        .should().dependOnClassesThat().resideInAPackage("org.springframework..")

Decision heuristics

  • Start with one or two fitness functions enforcing the architecture's most important property (typically dependency direction). Add as drift surfaces.
  • Make fitness function failures fail the build — a warning that's been ignored for a year is not a fitness function.
  • Treat fitness functions like tests: each has a clear failure message that explains why the rule exists, not just what it checks.
  • Don't write a fitness function for a rule you wouldn't block a PR over.
  • For migration projects, fitness functions can encode "new code goes in path X, not legacy path Y" — invaluable for keeping the migration honest.

Anti-patterns

  • Fitness function that nobody owns. Breaks → someone disables it → bypassed forever.
  • Over-policing. Hundreds of fitness functions enforcing every preference. CI gets slow; developers learn to ignore failures.
  • Style as architecture. "All method names must be camelCase" is a linter rule, not a fitness function. Don't dilute the term.
  • Documentation without automation. Wiki page describing the architecture; no automated check; new joiners violate it within weeks.
  • One-time check. Architecture audit done once, results filed away. Drift accumulates immediately after.

See also

  • arch-layered — layer boundaries are the canonical fitness-function use case.
  • arch-hexagonal — dependency-direction-toward-domain is the canonical hexagonal fitness function.
  • arch-adr — fitness functions encode the what; ADRs explain the why. Both belong together.

References

  • Neal Ford, Rebecca Parsons, Patrick Kua, Building Evolutionary Architectures (O'Reilly, 2nd ed) — the foundational reference.
  • ArchUnit documentation (JVM).
  • Richards & Ford, Fundamentals of Software Architecture, governance / fitness chapters.

관련 작업

같은 저장소의 Skills

더 많은 Skills

모든 Skills
yonatankarp
커뮤니티

arch-adr

Use when recording an architectural decision so future maintainers know why — phrases like "ADR", "architecture decision record", "why did we pick X", "lightweight architecture documentation", "decision log", "should this be an ADR", "tribal knowledge", "we chose this two years ago and now nobody remembers why". Defines the ADR as a short, structured document capturing what was decided, why, alternatives considered, and consequences — written at the time of the decision and kept in the repo.

설치 수
2
GitHub Stars
1
업데이트
5월 19일
yonatankarp
커뮤니티

arch-microservices

Use when designing or reviewing a microservices architecture — phrases like "microservices", "should we split this service", "service boundaries", "bounded context per service", "API gateway", "backend for frontend", "BFF", "service mesh", "microservices vs monolith", "database per service", "data ownership". Defines microservices as independently deployable services aligned with business capabilities — and the discipline of resisting the style until the monolith proves inadequate.

설치 수
2
GitHub Stars
1
업데이트
5월 19일
yonatankarp
커뮤니티

arch-strangler-fig

Use when migrating a legacy system incrementally — phrases like "strangler fig", "strangler pattern", "incremental migration", "monolith to microservices", "rewrite without big bang", "replace legacy in place", "facade in front of the legacy system", "anticorruption layer". Defines Fowler's Strangler Fig as the migration discipline of gradually replacing legacy functionality behind a stable facade, never doing a big-bang rewrite.

설치 수
2
GitHub Stars
1
업데이트
5월 19일
yonatankarp
커뮤니티

ddd-aggregate

Use when designing or critiquing aggregate boundaries — phrases like "aggregate", "aggregate root", "should these be one entity or two", "consistency boundary", "transactional consistency", "this aggregate is huge", "should I reference by ID or by object". Defines aggregates as transactional consistency boundaries and the rules for entity references within and across them.

설치 수
2
GitHub Stars
1
업데이트
5월 19일