dddominio/common
Common utilities for the DDDominio ecosystem: shared helpers, base classes, and cross-package abstractions to standardize behavior and reduce duplication across domain-driven Laravel/PHP packages.
## Technical Evaluation
### **Architecture Fit**
- **DDD Alignment**: The package is purpose-built for DDD, offering standardized implementations for **entities, value objects, aggregates, repositories, and domain events**. This aligns perfectly with Laravel projects aiming for **clean architecture** or **microservices** where bounded contexts are critical. The package’s abstractions (e.g., `AggregateRoot`, `RepositoryInterface`) enforce DDD principles without locking teams into a monolithic framework.
- **Layered Architecture**: Complements Laravel’s **MVC/Service Layer** pattern by:
- Isolating domain logic in **entities/value objects** (Domain Layer).
- Delegating persistence to **custom repositories** (Infrastructure Layer), which can wrap Eloquent or other ORMs.
- **Ubiquitous Language**: Encourages alignment between technical and business teams by providing **type-safe domain primitives** (e.g., `Money`, `Email`) that mirror real-world concepts.
### **Integration Feasibility**
- **Laravel Synergy**:
- **Service Container**: The package’s interfaces (e.g., `RepositoryInterface`) can be bound to Laravel’s container, enabling dependency injection for domain objects.
- **Events**: Domain events can integrate with Laravel’s **event system** or **queue workers** for async processing.
- **Testing**: Works seamlessly with Laravel’s **PestPHP/PHPUnit** for unit/integration tests (e.g., testing domain invariants).
- **Incremental Adoption**:
- Start with **entities/value objects** (low risk, high reward).
- Gradually introduce **repositories** and **domain events** as confidence grows.
- **ORM Flexibility**:
- Repositories can abstract **Eloquent, Query Builder, or even external APIs**, making the package adaptable to non-DB use cases (e.g., GraphQL APIs).
### **Technical Risk**
- **Immaturity**: With **0 stars/dependents**, risks include:
- **Undocumented edge cases** (e.g., event dispatching, repository transactions).
- **Lack of Laravel-specific optimizations** (e.g., Eloquent integration quirks).
- **Performance Overhead**:
- Reflection-based DDD patterns (e.g., dynamic event publishing) may introduce latency. **Benchmark critical paths** (e.g., aggregate loading).
- **Design Assumptions**:
- Potential conflicts with Laravel’s **conventions** (e.g., UUIDs vs. auto-increment IDs, event naming).
- Unclear support for **CQRS** or **event sourcing** (may require additional packages).
- **Testing Gaps**:
- Limited test coverage in the package could expose **domain logic bugs** (e.g., invariant violations).
### **Key Questions**
1. **DDD Maturity**: Is the team’s DDD adoption **strategic** (e.g., greenfield project) or **tactical** (e.g., refactoring legacy code)? This impacts integration scope.
2. **Persistence Strategy**:
- Will repositories use **Eloquent**, **raw queries**, or a **custom ORM**? Clarify mapping strategies (e.g., single-table inheritance for aggregates).
3. **Event Handling**:
- Does the package support **Laravel’s event system** natively, or will a **custom dispatcher** be needed?
- How are **domain events** serialized/deserialized (e.g., JSON, custom format)?
4. **Alternatives**:
- Compare with **Spatie’s Laravel DDD**, **Fruitcake’s DDD**, or **Symfony’s DDD bundles** for maturity and Laravel-specific features.
5. **Long-Term Viability**:
- What’s the **maintenance roadmap** for the package? Will it evolve alongside Laravel?
6. **Tooling**:
- Does the package integrate with **Laravel Forge/Sail** for deployment or **Laravel Horizon** for event processing?
---
## Integration Approach
### **Stack Fit**
- **Laravel Ecosystem**:
- **Composer**: Seamless installation via `composer require dddominio/common`.
- **Service Container**: Bind package interfaces to Laravel’s container for DI (e.g., repositories, event dispatchers).
- **Events**: Leverage Laravel’s **event system** or **queue workers** for async domain events.
- **Testing**: Compatible with **PestPHP**, **PHPUnit**, and **Mockery** for testing domain logic.
- **Architecture Patterns**:
- **Clean Architecture**: Place domain layer in `app/Domain`; infrastructure (repositories) in `app/Infrastructure`.
- **Hexagonal Architecture**: Use the package’s ports (e.g., `RepositoryInterface`) to decouple domain from Laravel’s Eloquent.
- **Tooling**:
- **IDE Support**: PHPStorm’s DDD plugins can enhance navigation for entities/aggregates.
- **CI/CD**: Add tests for domain invariants to pre-commit hooks.
### **Migration Path**
1. **Phase 1: Domain Primitives (1–2 weeks)**
- Replace **plain PHP classes** with `DDDominio\Common\Entity` and `DDDominio\Common\ValueObject`.
- Example:
```php
// Before
class User {
public function __construct(public string $id, public string $name) {}
}
// After
use DDDominio\Common\Entity;
class User extends Entity {
public function __construct(
public string $id,
public string $name
) {}
}
```
- **Validation**: Write unit tests for immutability, identity, and equality.
2. **Phase 2: Repositories (2–3 weeks)**
- Implement `DDDominio\Common\Repository\RepositoryInterface` for aggregates.
- Example:
```php
class UserRepository implements RepositoryInterface {
public function find(string $id): ?User {
return UserModel::find($id)->toDomain(); // Custom mapper
}
}
```
- **Binding**: Register repositories in Laravel’s container:
```php
$this->app->bind(UserRepository::class, function ($app) {
return new EloquentUserRepository(new UserModel());
});
```
- **Persistence**: Decide on **ORM strategy** (e.g., Eloquent, raw queries) and create mappers.
3. **Phase 3: Domain Events (1–2 weeks)**
- Map `DDDominio\Common\Domain\Event` to Laravel events or a custom dispatcher.
- Example:
```php
use DDDominio\Common\Domain\Event\DomainEvent;
class OrderCreated implements DomainEvent {
public function __construct(public string $orderId) {}
}
// Dispatch in entity:
$this->domainEventDispatcher->dispatch(new OrderCreated($orderId));
```
- **Integration**: Use Laravel’s **event listeners** or **queue workers** for async processing.
4. **Phase 4: Domain Services (Ongoing)**
- Encapsulate **business logic** in services (e.g., `OrderService`) using injected repositories/entities.
- Example:
```php
class OrderService {
public function __construct(
private UserRepository $userRepository,
private OrderRepository $orderRepository
) {}
public function createOrder(string $userId, array $items) {
$user = $this->userRepository->find($userId);
// Business logic...
}
}
```
### **Compatibility**
- **Laravel Versions**: Test with **Laravel 10.x** (PHP 8.1+). Check for breaking changes in newer Laravel releases.
- **Package Dependencies**:
- Audit for conflicts with **Eloquent**, **Livewire**, or other ORM/event packages.
- Example conflict: If the package uses `symfony/event-dispatcher`, ensure Laravel’s event system doesn’t clash.
- **Customization**:
- Override package defaults (e.g., **UUID generation**, **event naming**) via config or service providers.
- Example: Publish the package’s config:
```bash
php artisan vendor:publish --provider="DDDominio\Common\CommonServiceProvider"
```
### **Sequencing**
- **Pilot Module**: Start with a **low-risk domain** (e.g., `User`, `Product`) to validate integration.
- **Incremental Rollout**:
1. **Entities/Value Objects**: Replace 1–2 domain models.
2. **Repositories**: Implement for critical aggregates (e.g., `Order`).
3. **Events**: Add domain events for **audit logs** or **notifications**.
- **Parallel Development**:
- Maintain **dual implementations** (e.g., Eloquent + DDDominio) during migration.
- Use **feature flags** to toggle between old/new domain logic.
---
## Operational Impact
### **Maintenance**
- **Dependency Management**:
- Monitor the package for **breaking changes** (e.g., interface modifications).
- Pin versions in `composer.json` to avoid surprises:
```json
"require": {
"dddominio/common": "^1.0"
}
```
- **Custom Code**:
- Isolate package-specific logic (e.g., repository implementations) in **separate classes** for easier updates.
- Example: Use **adapters** to abstract away package changes:
```php
class EloquentUserRepositoryAdapter implements UserRepository {
public function __construct
How can I help you explore Laravel packages today?