Vzor služby v Laravelu: Proč je nesmyslný?

Proč je vzor služby v projektech Laravel nepořádek Na stránkách Vzor služby začalo jako ušlechtilá myšlenka: oddělit obchodní logiku od kontrolérů, aby bylo vše čisté. V reálných...

Poptat web

11. 11. 2025

Vzor služby v Laravelu: Proč je nesmyslný?

Proč je vzor služby v projektech Laravel nepořádek

Na stránkách Vzor služby začalo jako ušlechtilá myšlenka: oddělit obchodní logiku od kontrolérů, aby bylo vše čisté. V reálných projektech Laravel se však stala jednou z nejvíce zneužívaných a nepochopených architektonických možností. To, co mělo přinést přehlednost, se často mění ve skládku špatně umístěné logiky.

Probereme si, proč k tomu dochází, jak to vede k chaosu v kódu a jaké lepší vzory můžete použít místo toho.

Hlavní problém: ztratil svůj smysl

V projektech Laravel je termín Služba se stala univerzální nálepkou. Když si vývojáři nejsou jisti, kam umístit logiku, často vytvoří třídu "služba" jako rychlé řešení. Časem se tyto třídy rozrostou bez struktury a účelu.

V praxi se děje toto:

1. Služby podobné úložišti

Vývojáři používají "službu" pro zpracování databázových dotazů, která duplikuje to, k čemu je určen správný vzor úložiště (tj. Eloquent).

// app/Services/UserService.php
class UserService {
public function all()
{
return User::all();
}
 
public function active()
{
return User::where('active', true)->get();
}
}

To nepřináší žádnou přidanou hodnotu, je to jen zbytečný obal kolem modelu. V systému Laravel, vzor úložiště vůbec nepotřebujete.. Eloquent ORM již is vrstvy úložiště. Poskytuje abstrakci dotazů, mapování dat a expresivní syntaxi.

Logika by měla být přímo v modelu pomocí obory dotazů or vlastní tvůrci dotazů.

// app/Models/User.php
class User extends Model {
public function scopeActive($query)
{
return $query->where('active', true);
}
}
$users = User::active()->get();

Je čistší, čitelnější a dokonale odpovídá konvencím Laravelu. Není potřeba žádné další úložiště nebo vrstva služeb, která by obalovala Eloquent.

2. Služby subkontrolérů

Někteří vývojáři přenášejí veškerou práci s řadiči do třídy služeb. Kontrolér se tak stává prázdnou skořápkou, zatímco služba se stává přebujelým pseudokontrolérem.

// app/Services/UserService.php
class UserService {
public function store(array $data)
{
$user = User::create($data);
 
UserRegistered::dispatch($user);
 
// more user creation logic ...
 
return $user;
}
}
 
// app/Http/Controllers/UserController.php
class UserController {
public function store(Request $request, UserService $service)
{
return $service->store($request->validated());
}
}

Místo toho udělejte toto:

// app/Actions/CreateUser.php
class CreateUser {
public function execute(array $data): User
{
return User::create($data);
}
}
 
// app/Http/Controllers/UserController.php
class UserController {
public function store(StoreUserRequest $request, CreateUser $action)
{
$user = $action->execute($request->validated());
 
UserRegistered::dispatch($user);
 
return response()->json($user);
}
}

3. Modelové akční služby

Častým zneužitím vzoru služby je. "Modelová akční služba" přístup, kdy vývojáři seskupují všechny operace související s jedním modelem do jedné obrovské třídy.

// app/Services/UserService.php
class UserService {
public function create(array $data) { ... }
public function deactivate(User $user) { ... }
public function update(User $user) { ... }
}

Na první pohled vypadá organizovaně, protože vše, co se týká User model je na jednom místě. Ale jak projekt roste, stává se z toho problém. přebujelá, neudržovatelná třída. Každá metoda se zabývá různými problémy, jako je obchodní logika, oznámení, integrace a změny stavu, a to vše je spojeno dohromady.

Místo toho použijte Akční vzor oddělit každé chování do vlastní zaměřené třídy.

app/
├── Actions/
│ ├── ActivateUser.php
│ ├── DeactivateUser.php
│ ├── PromoteUser.php
│ └── SendWelcomeEmail.php

Každá akce zpracovává pouze jednu úlohu, což z vašeho kódu činí:

  • Snadnější testování
  • Jednodušší uvažování
  • Konzistentní struktura

Příklad:

// app/Actions/ActivateUser.php
class ActivateUser {
public function execute(User $user): User
{
$user->update(['active' => true]);
return $user;
}
}

Pak ve vrstvě řadiče nebo služby:

public function activate(User $user, ActivateUser $action)
{
return response()->json($action->execute($user));
}

Toto oddělení udržuje logiku modulární, předvídatelnou a dokonale sladěnou s čistým stylem architektury Laravel.

4. Komunální služby nebo služby

Dalším častým zneužitím je přeměna servisních tříd na užitkové kontejnery, generické pomocníky, které vykonávají nesouvisející, průřezové úlohy.

// app/Services/HelperService.php
class HelperService {
public function formatDate($date) { ... }
public function slugify($string) { ... }
public function toMoneyFormat($value) { ... }
}

Na první pohled se zdá, že je vhodné centralizovat "užitečné" funkce. Ale v okamžiku, kdy sem začnete přidávat náhodné pomocníky, se tato třída stane různé skládky, neurčitá "služba", která nikam nepatří.

Lepší přístup:

app/
├── Utilities/
│ ├── CurrencyConverter.php
│ └── HtmlToMarkdownConverter.php

Každý pomocník má jasná, jednotná odpovědnost a popisný název.

Hlavní myšlenkou je: Komunální služby nejsou služby. Jsou to pomocníci, kteří jsou lehké, kontextově agnostické nástroje a zaslouží si svůj vlastní domov.

5. Integrační služby třetích stran

Integrační logika (například Stripe nebo AWS) často končí v obecných "službách", což opět zvyšuje zmatek.

// app/Services/StripeService.php
class StripeService {
public function charge(User $user, $amount) { ... }
}

Ty patří do vyhrazeného Integrace oboru názvů nebo adresáře.

app/
├── Integrations/
│ └── Stripe/
│ ├── StripeClient.php
│ ├── StripeCharge.php
│ └── StripeWebhookHandler.php

Každá integrace má správnou strukturu a účel.

Proč je to nebezpečné

Když se vzor služby stane univerzálním:

  • Pojmenování ztrácí smysl - "Co tato služba vlastně dělá?" je častá otázka.
  • Údržba se stává bolestivou - Změna logiky znamená hledání v libovolných metodách služby.
  • Testování je těžší - Příliš obecné třídy závisí na příliš mnoha částech aplikace.
  • Přestávky v týmové komunikaci - Každý vývojář si pojem "služba" vykládá jinak.

Lepší přístup: Použijte správný vzor pro správnou práci

Laravel vám poskytuje flexibilitu, díky níž můžete svou logiku uspořádat přehledně. Místo jedné neurčité vrstvy "služby" používejte konkrétní vzory a pojmenování, které vyjadřují záměr.

Zneužití Problém Správný vzor Příklad adresáře
Služby podobné úložištím Logika duplicitních dat Použití vestavěného úložiště Eloquent ORM (built-in Repository) app/Models/User.php
Služby subkontrolérů Přemrštěná, chybně umístěná logika HTTP Akční vzor app/Actions/CreateUser.php
Model Action Services Smíšené chování v jedné třídě Akční vzor app/Actions/ActivateUser.php
Komunální/podpůrné služby Odkladiště pro pomocníky Podpůrné třídy / pomocníci app/Support/DateHelper.php
Integrační služby třetích stran Smíšená integrace a doménová logika Integrační vrstva app/Integrations/Stripe/StripeCharge.php

Příklad: Čistá struktura bez servisního nepořádku

app/
├── Actions/
│ └── CreateUser.php
├── Http/
│ └── Controllers/
│ └── UserController.php
├── Integrations/
│ └── Stripe/
│ └── StripeCharge.php
├── Models/
│ └── User.php
└── Utilities/
└── CurrencyConverter.php

Díky této struktuře vždy víte, kam logiku umístit a kde ji později najít. Obecný adresář "Service" není vůbec potřeba.

Závěrečné myšlenky

Vzor Service se v Laravelu stal nepořádkem, protože přestal mít smysl. Stal se z něj odpadkový koš pro kód, o kterém vývojáři nevěděli, kam ho zařadit. Řešením není neustále vylepšovat koncept "služby", ale je třeba přestat ji používat jako výchozí.

Použijte Eloquent ORM jako úložiště, Akce pro akce prováděné na modelech, Integrace pro externí rozhraní API a Podpora pro sdílené pomocníky nebo nástroje. Nechť struktura a pojmenování sdělují záměr. Takto vytvoříte projekty Laravel, které zůstanou čisté, udržovatelné a škálovatelné.

Původní článek publikoval Nabil Hassen.