# Laravel Solutions: Pattern Avanzati, Debugging e Domande da Colloquio 2026 > Padroneggia le soluzioni Laravel con pattern architetturali avanzati, tecniche di debugging e preparazione ai colloqui. Service class, repository pattern, debugging con Telescope e domande frequenti per sviluppatori Laravel. - Published: 2026-08-25 - Updated: 2026-08-25 - Author: Anthony Fillion-Maillet - Tags: laravel, php, debugging, design-patterns, interview - Reading time: 12 min --- Le soluzioni Laravel per applicazioni in produzione richiedono competenze che vanno oltre le operazioni CRUD di base. La differenza tra sviluppatori Laravel junior e senior emerge nella strutturazione del codice, nel debugging dei problemi e nelle risposte alle domande architetturali durante i colloqui. > **Cosa cercano i recruiter** > > I ruoli senior Laravel richiedono ai candidati di spiegare il Service Container, dimostrare workflow di debugging con Telescope o Debugbar e giustificare quando utilizzare pattern come Repository rispetto a query Eloquent dirette. ## Service Class: Estrarre la Business Logic dai Controller I controller in Laravel gestiscono gli aspetti HTTP: ricevere richieste, validare input e restituire risposte. La business logic appartiene a service class dedicate, rendendo il codice testabile e riutilizzabile tra controller, comandi e job. ```php // app/Services/OrderService.php // Service class encapsulating order business logic namespace App\Services; use App\Models\Order; use App\Models\User; use App\Exceptions\InsufficientStockException; use App\Jobs\SendOrderConfirmationEmail; use Illuminate\Support\Facades\DB; class OrderService { public function __construct( private InventoryService $inventory, private PaymentService $payment ) {} /** * Create an order with full validation and side effects * * @throws InsufficientStockException */ public function createOrder(User $user, array $items, string $paymentMethod): Order { // Validate stock availability before starting transaction foreach ($items as $item) { if (!$this->inventory->hasStock($item['product_id'], $item['quantity'])) { throw new InsufficientStockException($item['product_id']); } } return DB::transaction(function () use ($user, $items, $paymentMethod) { // Create order record $order = $user->orders()->create([ 'status' => 'pending', 'total' => $this->calculateTotal($items), ]); // Attach order items foreach ($items as $item) { $order->items()->create($item); $this->inventory->decrementStock($item['product_id'], $item['quantity']); } // Process payment $this->payment->charge($user, $order->total, $paymentMethod); $order->update(['status' => 'paid']); // Queue confirmation email SendOrderConfirmationEmail::dispatch($order); return $order; }); } private function calculateTotal(array $items): int { return collect($items)->sum(fn($item) => $item['price'] * $item['quantity']); } } ``` ```php // app/Http/Controllers/OrderController.php // Controller delegating to service class namespace App\Http\Controllers; use App\Http\Requests\CreateOrderRequest; use App\Services\OrderService; use Illuminate\Http\JsonResponse; class OrderController extends Controller { public function __construct( private OrderService $orderService ) {} public function store(CreateOrderRequest $request): JsonResponse { $order = $this->orderService->createOrder( $request->user(), $request->validated('items'), $request->validated('payment_method') ); return response()->json(['order_id' => $order->id], 201); } } ``` Le service class possono essere iniettate ovunque in Laravel: controller, comandi, altri servizi o classi job. La [documentazione del Service Container](https://laravel.com/docs/11.x/container) tratta la risoluzione automatica e il binding. ## Repository Pattern: Quando Eloquent Diretto Non Basta Il repository pattern aggiunge un livello di astrazione tra la business logic e l'accesso ai dati. Questo pattern si rivela prezioso quando le applicazioni devono cambiare sorgenti dati, cachare i risultati delle query in modo trasparente o isolare logica di query complessa. > **Contesto del Colloquio** > > Ai candidati viene spesso chiesto se utilizzano il repository pattern con Laravel. La risposta corretta dipende dal contesto: i repository aggiungono valore per applicazioni grandi con requisiti di dati complessi, ma creano astrazione non necessaria per applicazioni CRUD semplici. ```php // app/Repositories/Contracts/UserRepositoryInterface.php // Interface defining the contract namespace App\Repositories\Contracts; use App\Models\User; use Illuminate\Support\Collection; interface UserRepositoryInterface { public function findById(int $id): ?User; public function findByEmail(string $email): ?User; public function getActiveUsers(): Collection; public function getUsersWithRecentOrders(int $days = 30): Collection; public function create(array $data): User; public function update(User $user, array $data): User; } ``` ```php // app/Repositories/EloquentUserRepository.php // Eloquent implementation of the repository namespace App\Repositories; use App\Models\User; use App\Repositories\Contracts\UserRepositoryInterface; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; class EloquentUserRepository implements UserRepositoryInterface { public function findById(int $id): ?User { return Cache::remember( "user.{$id}", now()->addMinutes(10), fn() => User::find($id) ); } public function findByEmail(string $email): ?User { return User::where('email', $email)->first(); } public function getActiveUsers(): Collection { return User::where('status', 'active') ->orderBy('name') ->get(); } public function getUsersWithRecentOrders(int $days = 30): Collection { return User::whereHas('orders', function ($query) use ($days) { $query->where('created_at', '>=', now()->subDays($days)); }) ->with(['orders' => fn($q) => $q->latest()->limit(5)]) ->get(); } public function create(array $data): User { $user = User::create($data); Cache::forget("user.{$user->id}"); return $user; } public function update(User $user, array $data): User { $user->update($data); Cache::forget("user.{$user->id}"); return $user->fresh(); } } ``` ```php // app/Providers/RepositoryServiceProvider.php // Binding interface to implementation namespace App\Providers; use App\Repositories\Contracts\UserRepositoryInterface; use App\Repositories\EloquentUserRepository; use Illuminate\Support\ServiceProvider; class RepositoryServiceProvider extends ServiceProvider { public function register(): void { $this->app->bind( UserRepositoryInterface::class, EloquentUserRepository::class ); } } ``` L'implementazione del repository gestisce la cache internamente, mantenendo le service class focalizzate sulle regole di business piuttosto che sull'invalidazione della cache. ## Debugging delle Applicazioni Laravel con Telescope [Laravel Telescope](https://laravel.com/docs/11.x/telescope) fornisce un assistente di debug che registra richieste, eccezioni, query al database, job e altro. Il debugging in produzione richiede la comprensione di quali metriche sono importanti e come filtrare il rumore. ```php // config/telescope.php // Telescope configuration for different environments return [ 'enabled' => env('TELESCOPE_ENABLED', true), // Only record slow queries in production 'query' => [ 'slow' => env('TELESCOPE_SLOW_QUERY_THRESHOLD', 100), // milliseconds ], // Prune old entries to manage database size 'storage' => [ 'database' => [ 'connection' => env('DB_CONNECTION', 'mysql'), 'chunk' => 1000, ], ], ]; ``` ```php // app/Providers/TelescopeServiceProvider.php // Custom filtering for Telescope entries namespace App\Providers; use Laravel\Telescope\IncomingEntry; use Laravel\Telescope\Telescope; use Laravel\Telescope\TelescopeApplicationServiceProvider; class TelescopeServiceProvider extends TelescopeApplicationServiceProvider { public function register(): void { Telescope::night(); $this->hideSensitiveRequestDetails(); // Filter out noise in production Telescope::filter(function (IncomingEntry $entry) { // Always record exceptions and slow queries if ($entry->isException()) { return true; } if ($entry->isSlowQuery()) { return true; } // Skip health check endpoints if ($entry->isRequest() && str_starts_with($entry->content['uri'] ?? '', '/health')) { return false; } // Skip static asset requests if ($entry->isRequest() && preg_match('/\.(css|js|png|jpg|svg)$/', $entry->content['uri'] ?? '')) { return false; } // Record everything in local environment if ($this->app->environment('local')) { return true; } // Production: only record failures and slow operations return $entry->isFailedRequest() || $entry->isFailedJob() || $entry->hasMonitoredTag(); }); } protected function hideSensitiveRequestDetails(): void { // Hide sensitive data from Telescope UI Telescope::hideRequestParameters(['password', 'password_confirmation', 'token']); Telescope::hideRequestHeaders(['authorization', 'cookie']); } } ``` Il metodo `isSlowQuery()` segnala le query al database che superano la soglia configurata. L'analisi delle query lente rivela indici mancanti e problemi N+1 che anche strumenti di profiling come [Debugbar](https://github.com/barryvdh/laravel-debugbar) rilevano. ## Domande da Colloquio Comuni e Risposte Efficaci I colloqui tecnici per posizioni Laravel seguono schemi ricorrenti. Le domande seguenti appaiono frequentemente, e le risposte dimostrano la profondità che i recruiter si aspettano. ### Cos'è il Service Container e Perché è Importante? Il Service Container è il [container di dependency injection](https://laravel.com/docs/11.x/container) di Laravel. Gestisce le dipendenze delle classi ed esegue la dependency injection automaticamente. Quando il costruttore di un controller ha come type-hint `OrderService`, il container risolve e inietta un'istanza. ```php // Automatic resolution: container reads type hints and builds dependencies public function __construct(OrderService $service) { // $service is automatically instantiated and injected } // Manual binding for interfaces or complex setup $this->app->bind(PaymentGateway::class, function ($app) { return new StripeGateway( config('services.stripe.key'), config('services.stripe.secret') ); }); // Singleton: same instance throughout the request $this->app->singleton(MetricsCollector::class, function ($app) { return new MetricsCollector( $app->make(Cache::class) ); }); ``` Il container abilita l'accoppiamento lasco: le classi dipendono da astrazioni (interfacce) piuttosto che da implementazioni concrete, rendendo semplice il testing e lo scambio di implementazioni. ### Come Gestisce Laravel le Transazioni Database? Laravel racchiude le operazioni database in transazioni usando il metodo `DB::transaction()`. Le transazioni garantiscono l'atomicità: o tutte le operazioni hanno successo, o tutte vengono annullate. ```php // Simple transaction with automatic rollback on exception DB::transaction(function () { $user = User::create(['email' => 'test@example.com']); $user->profile()->create(['bio' => 'New user']); // If profile creation fails, user creation rolls back }); // Manual transaction control for complex flows DB::beginTransaction(); try { $order = Order::create($data); PaymentGateway::charge($order->total); DB::commit(); } catch (PaymentFailedException $e) { DB::rollBack(); throw $e; } // Nested transactions use savepoints DB::transaction(function () { User::create(['email' => 'outer@test.com']); DB::transaction(function () { // This creates a savepoint Profile::create(['user_id' => 1]); }); // Inner failure only rolls back to savepoint }); ``` I recruiter spesso chiedono informazioni sui deadlock. La risposta: Laravel riprova le transazioni che falliscono a causa di deadlock (configurabile tramite il secondo argomento di `DB::transaction()`). ### Spiegare il Middleware e Fornire un Caso d'Uso Reale Il [Middleware](/technologies/laravel/interview-questions/middleware) filtra le richieste HTTP che entrano nell'applicazione. Ogni middleware può ispezionare, modificare o rifiutare le richieste prima che raggiungano i controller. ```php // app/Http/Middleware/EnsureTeamMember.php // Custom middleware checking team membership namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; class EnsureTeamMember { public function handle(Request $request, Closure $next, string $role = 'member'): Response { $team = $request->route('team'); if (!$request->user()->belongsToTeam($team)) { abort(403, 'You are not a member of this team.'); } if ($role === 'admin' && !$request->user()->isTeamAdmin($team)) { abort(403, 'Admin access required.'); } return $next($request); } } ``` ```php // routes/web.php // Applying middleware to routes Route::middleware(['auth', 'team.member:admin'])->group(function () { Route::get('/teams/{team}/settings', [TeamController::class, 'settings']); Route::put('/teams/{team}/settings', [TeamController::class, 'updateSettings']); }); ``` Il middleware viene eseguito in ordine. Il middleware di autenticazione dovrebbe essere eseguito prima del middleware di autorizzazione, e il middleware di logging tipicamente avvolge tutto. ## Risolvere il Problema delle Query N+1 Il problema N+1 genera una query per la collection iniziale più una query per elemento quando si accede alle relazioni. Una lista di 100 articoli con autori produce 101 query invece di 2. ```php // Problem: 101 queries for 100 articles $articles = Article::all(); foreach ($articles as $article) { echo $article->author->name; // Each access triggers a query } // Solution: eager load with 2 queries total $articles = Article::with('author')->get(); foreach ($articles as $article) { echo $article->author->name; // No additional queries } // Nested eager loading for complex relationships $articles = Article::with([ 'author.profile', 'comments' => fn($query) => $query->latest()->limit(5), 'comments.user', 'tags', ])->get(); ``` Laravel può [prevenire il lazy loading](/technologies/laravel/interview-questions/database-migrations) in sviluppo per individuare i problemi N+1 precocemente: ```php // app/Providers/AppServiceProvider.php use Illuminate\Database\Eloquent\Model; public function boot(): void { Model::preventLazyLoading(!$this->app->isProduction()); } ``` Con questa impostazione, l'accesso a una relazione non caricata lancia un'eccezione in sviluppo, forzando l'eager loading esplicito. ## Action Class per Operazioni a Scopo Singolo Le action class incapsulano singole operazioni che possono essere invocate da molteplici punti di ingresso. A differenza delle service class che raggruppano metodi correlati, le action gestiscono un singolo compito con input e output chiari. ```php // app/Actions/CreateUserAction.php // Single-purpose action class namespace App\Actions; use App\Models\User; use App\Notifications\WelcomeNotification; use Illuminate\Support\Facades\Hash; class CreateUserAction { public function execute(array $data): User { $user = User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => Hash::make($data['password']), ]); $user->notify(new WelcomeNotification()); return $user; } } ``` ```php // Usage in controller public function store(RegisterRequest $request, CreateUserAction $action) { $user = $action->execute($request->validated()); return redirect()->route('dashboard'); } // Usage in command public function handle(CreateUserAction $action) { $user = $action->execute([ 'name' => $this->argument('name'), 'email' => $this->argument('email'), 'password' => $this->argument('password'), ]); $this->info("Created user: {$user->id}"); } // Usage in test public function test_user_creation(): void { $action = new CreateUserAction(); $user = $action->execute([ 'name' => 'Test User', 'email' => 'test@example.com', 'password' => 'password', ]); $this->assertDatabaseHas('users', ['email' => 'test@example.com']); } ``` Le action class funzionano bene con il [sistema di job](/technologies/laravel/interview-questions/queues-jobs) di Laravel: l'action contiene la logica, e il job gestisce il queueing e il comportamento di retry. ## Architettura Event-Driven con Eventi e Listener Gli eventi disaccoppiano il momento in cui qualcosa accade dalle reazioni a quell'evento. Quando viene effettuato un ordine, viene lanciato l'evento `OrderPlaced`. I listener gestiscono l'invio di email, l'aggiornamento delle analytics e la notifica ai magazzini in modo indipendente. ```php // app/Events/OrderPlaced.php // Event class carrying order data namespace App\Events; use App\Models\Order; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class OrderPlaced { use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct( public Order $order ) {} } ``` ```php // app/Listeners/SendOrderConfirmation.php // Queued listener for email namespace App\Listeners; use App\Events\OrderPlaced; use App\Notifications\OrderConfirmationNotification; use Illuminate\Contracts\Queue\ShouldQueue; class SendOrderConfirmation implements ShouldQueue { public function handle(OrderPlaced $event): void { $event->order->user->notify( new OrderConfirmationNotification($event->order) ); } } ``` ```php // app/Listeners/UpdateInventoryAnalytics.php // Another listener for the same event namespace App\Listeners; use App\Events\OrderPlaced; use App\Services\AnalyticsService; use Illuminate\Contracts\Queue\ShouldQueue; class UpdateInventoryAnalytics implements ShouldQueue { public function __construct( private AnalyticsService $analytics ) {} public function handle(OrderPlaced $event): void { foreach ($event->order->items as $item) { $this->analytics->recordSale( $item->product_id, $item->quantity, $event->order->created_at ); } } } ``` ```php // Dispatching the event OrderPlaced::dispatch($order); // Or using the event helper event(new OrderPlaced($order)); ``` I listener che implementano `ShouldQueue` vengono eseguiti in modo asincrono, impedendo alle operazioni lente di bloccare la risposta HTTP. ## Punti Chiave per gli Sviluppatori Laravel - Le service class estraggono la business logic dai controller, migliorando la testabilità e consentendo il riutilizzo tra contesti HTTP, CLI e code - Il repository pattern aggiunge valore quando le applicazioni necessitano di caching, astrazione delle sorgenti dati o incapsulamento di query complesse, ma crea overhead per CRUD semplice - I filtri di Telescope riducono il rumore in produzione registrando solo eccezioni, query lente e operazioni fallite - Il Service Container gestisce la dependency injection automaticamente attraverso i type hint, con binding espliciti per interfacce e setup complessi - I problemi N+1 scompaiono con l'eager loading via `with()`, e `Model::preventLazyLoading()` individua gli eager load mancanti durante lo sviluppo - Le action class gestiscono operazioni a scopo singolo invocabili da controller, comandi, test e job - Gli eventi disaccoppiano "cosa è successo" da "cosa dovrebbe succedere dopo", con listener in coda che gestiscono gli effetti collaterali in modo asincrono - Le risposte ai colloqui dovrebbero dimostrare comprensione dei trade-off: quando i pattern aiutano rispetto a quando aggiungono complessità non necessaria --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/it/blog/laravel/laravel-solutions-advanced-patterns-debugging-interview