CtrlK
BlogDocsLog inGet started
Tessl Logo

pantheon-ai/software-design-principles

Apply software design principles across architecture and implementation using deterministic decision workflows, SOLID checks, structural patterns, and anti-pattern detection; use when reviewing designs, refactoring modules, or resolving maintainability and coupling risks.

Does it follow best practices?

Evaluation99%

1.01x

Agent success when using this tile

Validation for skill structure

Overview
Skills
Evals
Files

entity-rich-not-anemic.mdreferences/

title:
Build Rich Domain Models Not Anemic Data Structures
impact:
HIGH
impactDescription:
centralizes business logic, prevents scattered rules
tags:
entity, domain-model, anemic, behavior

Build Rich Domain Models Not Anemic Data Structures

Entities should contain behavior, not just data. Anemic domain models push business logic into services, scattering rules and duplicating validation.

Incorrect (anemic domain model):

// domain/entities/Subscription.java
public class Subscription {
    private String id;
    private String planId;
    private LocalDate startDate;
    private LocalDate endDate;
    private String status;

    // Only getters and setters - no behavior
    public String getStatus() { return status; }
    public void setStatus(String status) { this.status = status; }
    public LocalDate getEndDate() { return endDate; }
    public void setEndDate(LocalDate endDate) { this.endDate = endDate; }
}

// application/services/SubscriptionService.java
public class SubscriptionService {
    public void cancel(Subscription sub) {
        if (!sub.getStatus().equals("active")) {
            throw new IllegalStateException("Cannot cancel");
        }
        sub.setStatus("cancelled");
        sub.setEndDate(LocalDate.now());
    }

    public void renew(Subscription sub, int months) {
        if (!sub.getStatus().equals("active")) {
            throw new IllegalStateException("Cannot renew");
        }
        sub.setEndDate(sub.getEndDate().plusMonths(months));
    }
    // Logic scattered across many services
}

Correct (rich domain model):

// domain/entities/Subscription.java
public class Subscription {
    private final SubscriptionId id;
    private final PlanId planId;
    private final LocalDate startDate;
    private LocalDate endDate;
    private SubscriptionStatus status;

    public void cancel() {
        ensureActive();
        this.status = SubscriptionStatus.CANCELLED;
        this.endDate = LocalDate.now();
    }

    public void renew(Period extension) {
        ensureActive();
        if (extension.getMonths() < 1) {
            throw new InvalidExtensionPeriodException(extension);
        }
        this.endDate = this.endDate.plus(extension);
    }

    public boolean isExpired() {
        return LocalDate.now().isAfter(this.endDate);
    }

    public boolean canUpgradeTo(Plan newPlan) {
        return this.status == SubscriptionStatus.ACTIVE
            && newPlan.isUpgradeFrom(this.planId);
    }

    private void ensureActive() {
        if (this.status != SubscriptionStatus.ACTIVE) {
            throw new InactiveSubscriptionException(this.id);
        }
    }
}

// application/usecases/CancelSubscriptionUseCase.java
public class CancelSubscriptionUseCase {
    public void execute(SubscriptionId id) {
        Subscription sub = repository.findById(id);
        sub.cancel();  // Business logic in entity
        repository.save(sub);
    }
}

Benefits:

  • Business rules live with the data they operate on
  • Impossible to forget validation when manipulating data
  • Entity documents its own capabilities and constraints

Reference: Anemic Domain Model Anti-pattern

Install with Tessl CLI

npx tessl i pantheon-ai/software-design-principles@0.1.4

SKILL-FULL.md

SKILL.md

tile.json