domain-driven-design

Use the same terminology as domain experts. Code should read like business documentation.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "domain-driven-design" with this command: npx skills add nguyenhuuca/assessment/nguyenhuuca-assessment-domain-driven-design

Domain-Driven Design

Core Concepts

Ubiquitous Language

Use the same terminology as domain experts. Code should read like business documentation.

Bounded Context

A boundary within which a particular domain model is defined and applicable.

Context Map

Shows how bounded contexts relate to each other.

Building Blocks

Entity

Has identity that persists over time. Equality based on ID.

@Entity @Data @EqualsAndHashCode(onlyExplicitlyIncluded = true) public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @EqualsAndHashCode.Include private Long id;

@Embedded
private Email email;

private String name;

@Builder.Default
private Instant createdAt = Instant.now();

}

Value Object

Immutable, equality based on attributes.

@Embeddable @Value public class Email { private String value;

private Email(String value) {
    this.value = value;
}

public static Email of(String value) {
    if (value == null || !value.contains("@")) {
        throw new IllegalArgumentException("Invalid email");
    }
    return new Email(value);
}

// Lombok @Value makes it immutable and generates equals/hashCode

}

Aggregate

Cluster of entities and value objects with a root entity.

@Entity @Data public class Order { // Aggregate Root @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "order_id")
private List<OrderItem> items = new ArrayList<>();

private Long userId;

@Enumerated(EnumType.STRING)
private OrderStatus status;

// Business logic in domain model
public void addItem(Long productId, int quantity) {
    // Business rules enforced here
    if (this.status != OrderStatus.DRAFT) {
        throw new IllegalStateException("Cannot add items to submitted order");
    }
    OrderItem item = OrderItem.builder()
        .productId(productId)
        .quantity(quantity)
        .build();
    this.items.add(item);
}

public Money getTotal() {
    return items.stream()
        .map(OrderItem::getSubtotal)
        .reduce(Money.zero(), Money::add);
}

public void submit() {
    if (items.isEmpty()) {
        throw new IllegalStateException("Cannot submit empty order");
    }
    this.status = OrderStatus.SUBMITTED;
}

}

Repository

Abstracts data access for aggregates.

@Repository public interface OrderRepository extends JpaRepository<Order, Long> { Optional<Order> findById(Long id);

@Query("SELECT o FROM Order o LEFT JOIN FETCH o.items WHERE o.id = :id")
Optional&#x3C;Order> findByIdWithItems(@Param("id") Long id);

List&#x3C;Order> findByUserIdAndStatus(Long userId, OrderStatus status);

}

Domain Event

Something that happened in the domain.

@Value @Builder public class OrderPlaced { Long orderId; Long userId; Instant occurredAt; }

// Publishing domain events with Spring @Service @Transactional public class OrderService { private final OrderRepository orderRepository; private final ApplicationEventPublisher eventPublisher;

public void placeOrder(Long orderId) {
    Order order = orderRepository.findById(orderId)
        .orElseThrow(() -> new OrderNotFoundException(orderId));

    order.submit();
    orderRepository.save(order);

    // Publish domain event
    OrderPlaced event = OrderPlaced.builder()
        .orderId(order.getId())
        .userId(order.getUserId())
        .occurredAt(Instant.now())
        .build();
    eventPublisher.publishEvent(event);
}

}

// Event listener @Component public class OrderEventHandler { @EventListener @Async public void handleOrderPlaced(OrderPlaced event) { // Send confirmation email, update inventory, etc. } }

Strategic Patterns

Anti-Corruption Layer

Translate between your model and external systems.

Shared Kernel

Shared subset of domain model between contexts.

Customer-Supplier

Upstream provides what downstream needs.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

implementing-code

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

refactoring-code

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

python

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

test-driven-development

No summary provided by upstream source.

Repository SourceNeeds Review