Absolutely, this is a common point of confusion—partly because the terms overlap and different communities use them differently. Here's a breakdown with practical Laravely-PHP examples:
1. Definitions & Differences
1. Use Case
- What: Represents a specific business interaction or operation—as described by the user's needs.
- Role: Encapsulates application logic for a single, meaningful action.
- Example: "Login", "Register", "TransferFunds".
2. Application Service
- What: A layer that orchestrates domain entities, integrating domain logic with infrastructure.
- Role: Coordinates tasks between domain models, repositories and possibly other systems (emails, events, etc).
- Sometimes: In many DDD applications, the Application Service and the Use Case are the same. The service is named according to the use case.
3. Action
- What: Laravely naming convention, where each task (sometimes a "single action") is encapsulated in its own class. Not a formal DDD term.
- Role: Helps break up controllers, keeps code clean, and makes things reusable/testable.
- Example: "AuthenticateUserAction", "SendWelcomeEmailAction".
2. How They Relate
- Usually:
- In "classic" DDD, the Application Service is the Use Case (e.g.,
LoginUserServicehandles the "Login User" use case). - "Action" is a code-organization idea from Laravel and not part of DDD proper, but it plays a similar role.
- In "classic" DDD, the Application Service is the Use Case (e.g.,
3. Where Do DTOs and Domain Services Fit?
- DTOs (Data Transfer Objects):
Used to carry data between layers (controller → service, etc), without passing raw requests or Eloquent Models to your domain. - Domain Services:
Implement domain logic that doesn’t naturally fit a single entity/value object (e.g., money transfer between accounts).
4. Practical Example
Let's imagine a Login feature in Laravel + DDD style.
Directory Example:
app
└── Application
└── UseCases
└── LoginUser.php
└── DTOs
└── LoginUserDTO.php
└── Domain
└── User
└── Entities
└── User.php
└── Services
└── PasswordHasher.php
A. The DTO
<?php
namespace App\Application\DTOs;
class LoginUserDTO
{
public string $email;
public string $password;
public function __construct(string $email, string $password)
{
$this->email = $email;
$this->password = $password;
}
}
B. The Use Case (or ApplicationService)
<?php
namespace App\Application\UseCases;
use App\Application\DTOs\LoginUserDTO;
use App\Domain\User\Repositories\UserRepository;
use App\Domain\User\Services\PasswordHasher;
class LoginUser
{
private UserRepository $users;
private PasswordHasher $hasher;
public function __construct(UserRepository $users, PasswordHasher $hasher)
{
$this->users = $users;
$this->hasher = $hasher;
}
public function execute(LoginUserDTO $dto): ?string
{
$user = $this->users->findByEmail($dto->email);
if (!$user || ! $this->hasher->verify($dto->password, $user->password_hash)) {
return null; // login fails
}
// Generate and return JWT or session, etc
return $user->getJwtToken();
}
}
C. The Controller
public function login(Request $request, LoginUser $loginUser)
{
$dto = new LoginUserDTO($request->email, $request->password);
$token = $loginUser->execute($dto);
if (! $token) {
return response()->json(['error' => 'Invalid credentials'], 401);
}
return response()->json(['token' => $token]);
}
5. So, Which To Use?
- For pure DDD-inspired architecture:
- Use Use Cases (each one in its own "ApplicationService"/"UseCase" class).
- The name can be LoginUser, LoginUserUseCase, or LoginUserService (be consistent!).
- For Laravel-style single job classes:
- You might call them Actions, but if possible, stick to use-case language—it communicates intent better.
6. Summary Table
| Term | DDD Proper? | Role | Practical Example |
|---|---|---|---|
| Use Case | YES | Encapsulates business operation | LoginUser |
| Application Service | YES | Orchestrates use case & domain objects | LoginUserService |
| Action | NO (Laravel) | Single action, task-based class | LoginUserAction |
- DTOs carry data between layers.
- Domain services contain domain logic not tied to one entity.
7. Key Takeaways
- Use Case == Application Service in most DDD setups.
- Action is a Laravel-ism, but can follow same principles.
- Name classes according to the business operation.
- DTOs are for data transport, Domain Services for cross-entity logic.
In essence:
Don’t get too hung up on naming: focus on clear layers, clear responsibilities, and let your code communicate intent!
References:
- Vaughn Vernon, "Implementing Domain-Driven Design" (see Application Layer chapter)
- Laracasts: Practical Patterns - Actions
Hope this helps clear things up!