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

usecase-explicit-dependencies.mdreferences/

title:
Declare All Dependencies Explicitly in Constructor
impact:
HIGH
impactDescription:
enables testing, documents requirements, prevents hidden coupling
tags:
usecase, dependencies, constructor, injection

Declare All Dependencies Explicitly in Constructor

Use cases should receive all dependencies through their constructor. Hidden dependencies (service locators, singletons, static calls) make testing difficult and hide coupling.

Incorrect (hidden dependencies):

public class PlaceOrderUseCase {
    public OrderConfirmation execute(PlaceOrderCommand command) {
        // Hidden dependencies - impossible to test or trace
        var customer = CustomerRepository.getInstance().find(command.customerId());
        var inventory = InventoryService.getInventory();

        for (var item : command.items()) {
            if (!inventory.isAvailable(item)) {
                throw new OutOfStockException(item);
            }
        }

        var order = new Order(customer, command.items());

        // More hidden dependencies
        Database.getConnection().save(order);
        EmailService.send(customer.email(), "Order placed");
        EventBus.publish(new OrderPlacedEvent(order));

        return new OrderConfirmation(order.id());
    }
}

// Testing requires mocking static methods - complex and brittle

Correct (explicit constructor dependencies):

public class PlaceOrderUseCase {
    private final CustomerRepository customers;
    private final InventoryChecker inventory;
    private final OrderRepository orders;
    private final NotificationPort notifications;
    private final EventPublisher events;

    public PlaceOrderUseCase(
        CustomerRepository customers,
        InventoryChecker inventory,
        OrderRepository orders,
        NotificationPort notifications,
        EventPublisher events
    ) {
        this.customers = customers;
        this.inventory = inventory;
        this.orders = orders;
        this.notifications = notifications;
        this.events = events;
    }

    public OrderConfirmation execute(PlaceOrderCommand command) {
        var customer = customers.find(command.customerId());

        for (var item : command.items()) {
            if (!inventory.isAvailable(item)) {
                throw new OutOfStockException(item);
            }
        }

        var order = new Order(customer, command.items());
        orders.save(order);

        notifications.orderPlaced(customer, order);
        events.publish(new OrderPlacedEvent(order));

        return new OrderConfirmation(order.id());
    }
}

// Testing is straightforward
@Test
void placesOrderWhenInventoryAvailable() {
    var customers = mock(CustomerRepository.class);
    var inventory = mock(InventoryChecker.class);
    var orders = mock(OrderRepository.class);
    // ... configure mocks

    var useCase = new PlaceOrderUseCase(customers, inventory, orders, ...);
    var result = useCase.execute(command);

    verify(orders).save(any(Order.class));
}

Benefits:

  • Dependencies visible in constructor signature
  • Tests substitute any dependency with test doubles
  • Coupling is explicit and measurable

Reference: Dependency Injection Principles

Install with Tessl CLI

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

SKILL-FULL.md

SKILL.md

tile.json