Skip to content
acc-check-leaky-abstractions logo

Leaky Abstractions Detector

acc-check-leaky-abstractions

Detects leaky abstractions in PHP code. Identifies implementation details exposed in interfaces, concrete returns from abstract methods, framework leakage into domain, and infrastructure concerns in application layer.

SKILL.md

Full skill instructions

Leaky Abstractions Detector

Overview

This skill analyzes PHP codebases for leaky abstractions — situations where implementation details "leak" through interface boundaries, violating encapsulation and creating tight coupling.

Leaky Abstraction Types

TypeDescriptionSeverity
Interface LeakageImplementation details in interfaceCRITICAL
Framework LeakageFramework types in domain/​applicationCRITICAL
Return Type LeakageConcrete types returned from abstractionsWARNING
Parameter LeakageImplementation-specific parametersWARNING
Exception LeakageInfrastructure exceptions crossing boundariesWARNING
Dependency LeakageInner dependencies exposedINFO

Detection Patterns

Phase 1: Interface Leakage

# Doctrine types in interfaces
Grep: "Collection|ArrayCollection|PersistentCollection" --glob "**/​Domain/​**/​*Interface.php"
Grep: "Doctrine\\\\|Illuminate\\\\|Symfony\\\\" --glob "**/​Domain/​**/​*Interface.php"

# Infrastructure types in domain interfaces
Grep: "Redis|Memcached|Elasticsearch|Guzzle|Http" --glob "**/​Domain/​**/​*Interface.php"

# Database types in repository interfaces
Grep: "QueryBuilder|EntityManager|Connection|PDO" --glob "**/​Domain/​**/​*RepositoryInterface.php"

# ORM annotations/​attributes in interfaces
Grep: "#\\[ORM\\\\|@ORM\\\\|@Entity|@Table" --glob "**/​Domain/​**/​*Interface.php"

Example Violations:

// BAD: Leaky interface
interface UserRepositoryInterface
{
    public function findByQuery(QueryBuilder $query): Collection; // Doctrine leak!
}

// GOOD: Clean interface
interface UserRepositoryInterface
{
    /​** @return User[] */
    public function findByCriteria(UserCriteria $criteria): array;
}

Phase 2: Framework Leakage into Domain

# Symfony components in Domain
Grep: "use Symfony\\\\Component\\\\" --glob "**/​Domain/​**/​*.php"
Grep: "use Symfony\\\\Contracts\\\\" --glob "**/​Domain/​**/​*.php"

# Laravel components in Domain
Grep: "use Illuminate\\\\" --glob "**/​Domain/​**/​*.php"

# Doctrine in Domain entities
Grep: "use Doctrine\\\\ORM\\\\Mapping" --glob "**/​Domain/​**/​*.php"
Grep: "#\\[ORM\\\\|@ORM\\\\|@Entity|@Column|@ManyToOne" --glob "**/​Domain/​**/​*.php"

# HTTP in Domain
Grep: "Request|Response|HttpFoundation" --glob "**/​Domain/​**/​*.php"

Domain Should NOT Contain:

  • Framework service containers
  • HTTP request/​response objects
  • ORM annotations (use separate mapping files)
  • Framework validators
  • Framework events (use domain events)

Phase 3: Return Type Leakage

# Concrete class returns from interface methods
Grep: "public function.*\):\s*[A-Z][a-z]+[A-Z]" --glob "**/​*Interface.php"
# Should return interfaces, not concrete classes

# Collection returns instead of arrays
Grep: "): Collection|): ArrayCollection" --glob "**/​Domain/​**/​*Interface.php"

# Nullable entity returns (might indicate infrastructure concern)
Grep: "): \?[A-Z][a-z]+\s*;|): null\|[A-Z]" --glob "**/​*Interface.php"

# Framework response types
Grep: "): Response|): JsonResponse|): View" --glob "**/​Application/​**/​*.php"

Phase 4: Parameter Leakage

# ORM-specific parameters in domain methods
Grep: "function.*EntityManager|function.*Connection" --glob "**/​Domain/​**/​*.php"

# Query parameters
Grep: "function.*QueryBuilder|function.*Criteria\s*\$" --glob "**/​Domain/​**/​*.php"

# HTTP request as parameter
Grep: "function.*Request \$request" --glob "**/​Application/​**/​*UseCase.php"
Grep: "function.*Request \$request" --glob "**/​Application/​**/​*Handler.php"

# Framework config in domain
Grep: "function.*Config|function.*Parameters" --glob "**/​Domain/​**/​*.php"

Phase 5: Exception Leakage

# Database exceptions in domain
Grep: "throw.*Doctrine\\\\|catch.*Doctrine\\\\" --glob "**/​Domain/​**/​*.php"
Grep: "throw.*PDOException|catch.*PDOException" --glob "**/​Domain/​**/​*.php"

# HTTP exceptions in application
Grep: "throw.*HttpException|throw.*NotFoundHttpException" --glob "**/​Application/​**/​*.php"

# Infrastructure exceptions crossing boundaries
Grep: "catch.*\\\\Infrastructure\\\\" --glob "**/​Application/​**/​*.php"

# Missing exception translation
Grep: "catch.*Exception" --glob "**/​Infrastructure/​**/​*Repository.php" -A 3
# Should translate to domain exceptions

Phase 6: Dependency Leakage

# Constructor exposing internal dependencies
Grep: "__construct.*EntityManager|__construct.*Connection" --glob "**/​Application/​**/​*.php"

# Public methods with infrastructure types
Grep: "public function.*Logger|public function.*Cache" --glob "**/​Domain/​**/​*.php"

# Getter exposing internal state
Grep: "public function get.*\(\).*EntityManager|public function get.*\(\).*Repository" --glob "**/​*.php"

Phase 7: Serialization Leakage

# JSON serialization in domain
Grep: "JsonSerializable|jsonSerialize" --glob "**/​Domain/​**/​*.php"

# Symfony serializer attributes in domain
Grep: "#\\[Serializer\\\\|#\\[Groups|@Groups" --glob "**/​Domain/​**/​*.php"

# API platform attributes in domain
Grep: "#\\[ApiResource|#\\[ApiProperty" --glob "**/​Domain/​**/​*.php"

Report Format

# Leaky Abstractions Report

## Summary

| Leak Type | Critical | Warning | Info |
|-----------|----------|---------|------|
| Interface Leakage | 2 | 3 | - |
| Framework Leakage | 4 | 2 | - |
| Return Type Leakage | - | 5 | 3 |
| Parameter Leakage | 1 | 4 | - |
| Exception Leakage | 2 | 3 | - |
| Dependency Leakage | - | 2 | 4 |

**Total Leaks:** 8 critical, 19 warnings, 7 info

## Critical Issues

### LEAK-001: Doctrine Collection in Interface
- **File:** `src/​Domain/​User/​UserRepositoryInterface.php:12`
- **Issue:** ORM-specific type in domain interface
- **Code:**
  ```php
  public function findActive(): Collection;
  • Expected:
    /​** @return User[] */
    public function findActive(): array;
    
  • Impact: Domain tied to Doctrine, cannot switch ORM
  • Skills: acc-create-repository

LEAK-002: Framework in Domain Entity

  • File: src/​Domain/​Order/​Entity/​Order.php:8
  • Issue: Doctrine ORM annotations in domain entity
  • Code:
    use Doctrine\ORM\Mapping as ORM;
    
    #[ORM\Entity]
    #[ORM\Table(name: 'orders')]
    class Order
    
  • Expected: Use XML/​YAML mapping files in Infrastructure
  • Impact: Domain depends on persistence framework

LEAK-003: HTTP Request in UseCase

  • File: src/​Application/​UseCase/​CreateOrderUseCase.php:23
  • Issue: HTTP Request in application layer
  • Code:
    public function __invoke(Request $request): Response
    
  • Expected:
    public function __invoke(CreateOrderCommand $command): OrderId
    
  • Impact: UseCase tied to HTTP, cannot reuse in CLI
  • Skills: acc-create-command, acc-create-use-case

Warning Issues

LEAK-004: PDOException Not Translated

  • File: src/​Infrastructure/​Repository/​DoctrineUserRepository.php:45
  • Issue: Database exception not translated to domain exception
  • Code:
    public function save(User $user): void
    {
        $this->em->persist($user);
        $this->em->flush(); // PDOException can leak!
    }
    
  • Expected:
    public function save(User $user): void
    {
        try {
            $this->em->persist($user);
            $this->em->flush();
        } catch (UniqueConstraintViolationException $e) {
            throw new UserAlreadyExistsException($user->email());
        }
    }
    

LEAK-005: Concrete Return Type

  • File: src/​Application/​Service/​PaymentServiceInterface.php:15
  • Issue: Returns concrete class instead of interface
  • Code:
    public function process(Payment $payment): StripePaymentResult;
    
  • Expected:
    public function process(Payment $payment): PaymentResultInterface;
    

LEAK-006: Infrastructure Logger in Domain

  • File: src/​Domain/​Order/​Service/​OrderValidator.php:12
  • Issue: Logger dependency in domain service
  • Code:
    public function __construct(
        private LoggerInterface $logger,
    ) {}
    
  • Expected: Domain should not log, or use domain events

Abstraction Boundaries

┌─────────────────────────────────────────────────────────────┐
│                    Presentation Layer                        │
│  Request, Response, Controller, View                         │
├─────────────────────────────────────────────────────────────┤
│                    Application Layer                         │
│  Commands, Queries, Handlers, DTOs                          │
│  ❌ No HTTP types, ❌ No framework services                  │
├─────────────────────────────────────────────────────────────┤
│                      Domain Layer                            │
│  Entities, Value Objects, Domain Services, Interfaces        │
│  ❌ No ORM, ❌ No framework, ❌ No infrastructure            │
├─────────────────────────────────────────────────────────────┤
│                   Infrastructure Layer                       │
│  Repositories, Adapters, External Services                   │
│  ✅ ORM, ✅ Framework, ✅ Database                           │
└─────────────────────────────────────────────────────────────┘

Refactoring Strategies

Interface Abstraction

LeakyClean
Collectionarray or custom *Collection
QueryBuilderCriteria or Specification
EntityManagerRepositoryInterface
RequestCommand / Query DTO
ResponseReturn value + Responder

Exception Translation

// Infrastructure layer
try {
    $this->connection->execute($sql);
} catch (UniqueConstraintViolationException $e) {
    throw new DuplicateEmailException($email);
} catch (\PDOException $e) {
    throw new PersistenceException('Failed to save user', 0, $e);
}

Framework Independence

// Instead of Doctrine Collection
interface UserRepositoryInterface
{
    /​** @return User[] */
    public function findActive(): array;
}

// Implementation can use Collection internally
class DoctrineUserRepository implements UserRepositoryInterface
{
    public function findActive(): array
    {
        return $this->createQueryBuilder('u')
            ->where('u.active = true')
            ->getQuery()
            ->getResult(); // Returns array
    }
}

## Quick Analysis Commands

```bash
# Detect leaky abstractions
echo "=== Framework in Domain ===" && \
grep -rn "use Doctrine\\|use Symfony\\|use Illuminate\\" --include="*.php" src/​Domain/ && \
echo "=== ORM in Interfaces ===" && \
grep -rn "Collection|QueryBuilder|EntityManager" --include="*Interface.php" src/ && \
echo "=== HTTP in Application ===" && \
grep -rn "Request|Response|HttpFoundation" --include="*.php" src/​Application/ && \
echo "=== Unhandled Exceptions ===" && \
grep -rn "throw.*PDO\|throw.*Doctrine" --include="*.php" src/​Domain/ src/​Application/

Integration

Works with:

  • acc-structural-auditor — Layer boundary analysis
  • acc-ddd-auditor — Domain purity checks
  • acc-create-repository — Clean repository interfaces
  • acc-create-anti-corruption-layer — External system isolation

References

  • "The Law of Leaky Abstractions" — Joel Spolsky
  • "Clean Architecture" (Robert C. Martin) — Dependency Rule
  • "Domain-Driven Design" (Eric Evans) — Layered Architecture

More skills from diegosouzapw

accessibility logo
diegosouzapw/awesome-omni-skill

accessibility

Accessibility guidelines for VS Code features — covers accessibility help dialogs, accessible views, verbosity settings, accessibility signals, ARIA alerts/status announcements, keyboard navigation, and ARIA labels/roles. Applies to both new interactive UI surfaces and updates to existing feature...

62 1
View
mermaid-diagrams logo
diegosouzapw/awesome-omni-skill

mermaid-diagrams

Mermaid diagram creation for flowcharts, sequences, ERDs, and more. Generate diagrams from text in markdown files. Use for documentation, architecture diagrams, and visual representations. Triggers on mermaid, flowchart, sequence diagram, ERD, entity relationship, gantt chart, pie chart, class di...

62 1
View
tauri2-react-rust logo
diegosouzapw/awesome-omni-skill

tauri2-react-rust

Guides development of cross-platform desktop apps with Tauri 2, TypeScript, React, and Rust. Use when building Tauri apps, implementing IPC, designing Rust backend or TypeScript/React frontend, when researching or cloning a website (open site, snapshot elements), when verifying local dev or built...

62 1
View
fp-ts-errors logo
diegosouzapw/awesome-omni-skill

fp-ts-errors

Handle errors as values using fp-ts Either and TaskEither for cleaner, more predictable TypeScript code. Use when implementing error handling patterns with fp-ts.

62 0
View
ring:pre-dev-research logo
diegosouzapw/awesome-omni-skill

ring:pre-dev-research

Gate 0 research phase for pre-dev workflow. Dispatches 3 parallel research agents to gather codebase patterns, external best practices, and framework documentation BEFORE creating PRD/TRD. Outputs research.md with file:line references.

62 0
View
create-assistant logo
diegosouzapw/awesome-omni-skill

create-assistant

Create and configure Vapi voice AI assistants with models, voices, transcribers, tools, hooks, and advanced settings. Use when building voice agents, phone bots, customer support assistants, or any conversational AI that handles phone or web calls.

62 0
View
codex-headless logo
diegosouzapw/awesome-omni-skill

codex-headless

Delegiere Aufgaben an OpenAI Codex CLI im Headless-Mode. Nutzt ChatGPT Subscription (KEIN API Key). Nur Workspace-Zugriff, KEIN System-Zugriff. Auto-Accept mit --full-auto. Web-Recherche mit --search.

62 0
View
social-media-scheduler logo
diegosouzapw/awesome-omni-skill

social-media-scheduler

Generate a full week of social media content for any topic. Outputs platform-optimized posts for Twitter/X, LinkedIn, and Instagram with hashtags and posting times.

62 0
View
Data Privacy Compliance logo
diegosouzapw/awesome-omni-skill

Data Privacy Compliance

Data privacy and regulatory compliance specialist for GDPR, CCPA, HIPAA, and international data protection laws. Use when implementing privacy controls, conducting data protection impact assessments, ensuring regulatory compliance, or managing data subject rights. Expert in consent management, da...

62 0
View
triple-review logo
diegosouzapw/awesome-omni-skill

triple-review

Reviews a task using the TRIPLE protocol, as the review agent.

62 0
View
Tech Stack & Architecture Decision logo
diegosouzapw/awesome-omni-skill

Tech Stack & Architecture Decision

Define and document the technology stack and architecture decisions for a project. Use when the user needs to choose a tech stack, make architecture decisions, define infrastructure choices, or document technology selections. Triggers on requests like "define the tech stack", "choose technologies...

62 0
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View