CtrlK
BlogDocsLog inGet started
Tessl Logo

evilissimo/software-design

Use before implementing or refactoring software. Contains two skills: (1) Modular Software Design — for designing module boundaries, APIs, layers, abstractions, services, repositories, adapters, or architecture, helping reduce total system complexity by creating deep modules, hiding implementation knowledge, avoiding leakage and pass-through APIs, comparing alternative designs, documenting interfaces before coding, and critiquing existing architecture; and (2) Software Testing — for writing unit tests, integration tests, or end-to-end tests, creating mocks/stubs/fakes, designing a testing strategy, doing TDD, reviewing test quality, fixing flaky tests, or refactoring test suites, generating risk-focused test plans, picking appropriate test levels, choosing between mocks/fakes/real dependencies, and applying Arrange-Act-Assert patterns with concrete examples.

88

Quality

88%

Does it follow best practices?

Impact

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

module-design-examples.mdskills/modular-software-design-skill/examples/

Module Design Examples

Use these examples as patterns while designing or reviewing modules.

Example 1: Shallow Wrapper vs Deep Use Case Module

Bad shallow wrapper:

class OrderService:
    def create_order(self, request):
        return self.order_repository.create_order(request)

Why bad:

  • Adds a layer but no abstraction.
  • Leaks repository shape upward.
  • Hides no validation, policy, mapping, or invariant.

Better deep module:

class OrderPlacement:
    def place_order(self, customer_id, cart_id, payment_method_id):
        cart = self.carts.load(cart_id)
        customer = self.customers.load(customer_id)

        order = Order.from_cart(customer, cart)
        order.require_valid_shipping_address()
        order.require_available_inventory()

        authorization = self.payments.authorize(order.total, payment_method_id)
        reservation = self.inventory.reserve(order.items)

        return self.orders.save_confirmed(order, authorization, reservation)

Why better:

  • Caller intent is one operation: place_order.
  • Validation, payment, inventory, mapping, and persistence sequencing are hidden.
  • Future changes to ordering rules are localized.

Example 2: Leaky Domain Logic vs Hidden Representation

Bad leaky code:

def cancel_order(order_row):
    if order_row["status_code"] == 7:
        raise Exception("Already shipped")

    order_row["status_code"] = 9
    db.orders.update(order_row)

Why bad:

  • Domain logic depends on database representation.
  • Status codes leak into business logic.
  • Persistence and policy are mixed.

Better domain abstraction:

class Order:
    def cancel(self):
        if self.has_shipped():
            raise OrderCannotBeCancelled("Shipped orders cannot be cancelled.")

        self.status = OrderStatus.CANCELLED

Why better:

  • Domain code speaks domain language.
  • Storage representation is hidden by mapping code.
  • The cancellation invariant has one owner.

Example 3: Pass-Through Variables vs Owned Policy

Bad pass-through variables:

def generate_invoice(order, locale, tax_table, rounding_mode, currency_rules):
    ...

def email_invoice(order, locale, tax_table, rounding_mode, currency_rules):
    invoice = generate_invoice(order, locale, tax_table, rounding_mode, currency_rules)
    ...

Why bad:

  • Callers must know tax and currency details.
  • Parameters spread through layers that do not own them.
  • Every new rule expands public signatures.

Better owned policy:

class InvoiceGenerator:
    def generate_for(self, order):
        tax = self.tax_policy.calculate(order)
        total = self.currency_policy.round(order.subtotal + tax)
        return Invoice(order, tax, total)

Why better:

  • Policy details are hidden.
  • Callers provide the domain object.
  • Future tax/currency changes are localized.

Example 4: Temporal Decomposition vs Conceptual Decomposition

Bad temporal modules:

RequestParser
RequestValidator
RequestProcessor
ResponseBuilder

Problem:

  • Modules mirror execution order.
  • Shared domain knowledge leaks across steps.
  • Changes often touch every stage.

Better conceptual modules:

SubscriptionSignup
EligibilityPolicy
BillingAccount
WelcomeMessage

Why better:

  • Modules correspond to concepts and hidden decisions.
  • Eligibility, billing, and messaging can evolve independently.

Example 5: Duplicate Layer Abstractions

Bad layered pass-through stack:

UserController.get_user
UserService.get_user
UserManager.get_user
UserRepository.get_user
UserDAO.get_user

Problem:

  • Each layer exposes the same abstraction.
  • Most methods pass through.
  • The design adds files without reducing complexity.

Better distinct layers:

HTTP layer: translate request/response details.
Application layer: load an active member profile use case.
Domain layer: represent member eligibility and account status.
Infrastructure layer: hide user, membership, and permission storage.

Example operation:

class MemberProfileQuery:
    def load_active_profile(self, member_id):
        user = self.users.fetch(member_id)
        membership = self.memberships.fetch_current(member_id)
        permissions = self.permissions.resolve(member_id)

        if not user.active or not membership.current:
            return None

        return MemberProfile(user, membership, permissions)

Why better:

  • The application operation provides a new abstraction.
  • Callers do not coordinate repositories manually.
  • Storage and joining details stay below the interface.

skills

modular-software-design-skill

examples

module-design-examples.md

SKILL.md

tile.json