Nebezpečný single responsibility principle

3 min

Single responsibility principle (SRP) je definován následujícím způsobem: “Class or module should have one, and only one, reason to change.”[1], neboli “třída nebo modul by měly mít pouze jeden důvod ke změně”. V tomto článku si ukážeme, proč je tato definice nepřesná a v mnoha případech i nebezpečná, a představíme novou definici, která mnohem lépe vystihuje, co vlastně single responsibility principle (SRP) znamená.

Nepřesná definice

Předchozí definice vyvolává otázku: Co je „důvod ke změně“? Na internetu můžeme najít mnoho lidí, kteří si vykládají důvod ke změně různými způsoby. Pro ukázku uvedu několik příkladů:

  • Můžeme najít mnoho lidí, kteří si SRP vyloží tak, že jedna třída by měla mít pouze jednu metodu (1, 2, 3).
  • Někteří lidé si SRP vyloží jako důvod, proč obalovat metody wrapper metodami, které nic nedělají (4).
  • Dále můžeme najít programátory, kteří říkají, že bychom měli volání new vždy obalovat do factory tříd, jelikož vytváření objektu je zodpovědností samostatné třídy (5).
  • Tato otázka na Stack Overflow popisuje aplikaci, ve které programátoři rozbili mnoho tříd na menší, jelikož jejich metody považovali za „důvod ke změně“. Výsledek byl podle autora horší kód než ten, se kterým začali.

Mohli byste říct, že tito lidé nerozumí SRP a použili ho špatně. To je možná pravda, ale krásně to demonstruje problém definice SRP. Jak vlastně víte, že vaše použití SRP je to správné?

SRP může znamenat prakticky cokoliv, co si programátor vymyslí, a v mnoha případech nevede ke zlepšení kódu.

Uncle Bob (tvůrce SRP) si tyto problémy sám uvědomuje a proto v novějších článcích používá lepší definici, která mnohem lépe popisuje, co SRP znamená.

Lepší definice

Novější definice od Uncle Boba zní takto:

“Gather together things that change for the same reasons and at the same times. Separate things that change for different reasons or at different times.” 6

Příklad: Představme si aplikaci, která obsahuje třídu X s metodami A, B, C. V průběhu několika měsíců přijde spousta požadavků na změny a vy si všimnete, že v 90 % případů se mění metody A a B společně. V tu chvíli můžeme říci, že třída X porušuje SRP, a měli bychom metodu C vyjmout a vložit do jiné třídy.

Opačný příklad: V jiné aplikaci máme třídy X a Y, kdy každá má jednu metodu. Opět přijdou požadavky na změnu a my si všimneme, že ve většině případů se mění třídy X a Y společně. V tu chvíli bychom měli třídy X a Y spojit do jedné, protože porušují SRP.

Všimněte si, že SRP není možné aplikovat bez znalosti budoucích požadavků. 7 Často ale můžeme hádat, jak se bude aplikace měnit, a třídy rozdělit na základě těchto odhadů. Pokud se v našem odhadu spleteme, můžeme třídy jednoduše zrefaktorovat tak, aby odpovídaly SRP.

V mnoha případech je také vhodné metody ponechat v jedné třídě a počkat na další požadavky. Tento jev popisuje i Martin Fowler v knize Refactoring (2nd edition):

“You’ve probably read guidelines that a class should be a crisp abstraction, only handle a few clear responsibilities, and so on. In practice, classes grow. You add some operations here, a bit of data there. You add a responsibility to a class feeling that it’s not worth a separate class—but as that responsibility grows and breeds, the class becomes too complicated. Soon, your class is as crisp as a microwaved duck.”

Kdy použít starou definici?

Nikdy. Nejlepší je pravděpodobně starou definici úplně zapomenout a tvářit se, jako že neexistuje. Stará definice může být reprezentována mnoha způsoby, které často neodpovídají originální myšlence SRP. Naopak nová definice poměrně přesně vystihuje, co měl Uncle Bob na mysli, když se snažil SRP poprvé popsat. Originální článek, ze kterého vycházel, totiž porovnává změny modulů v aplikaci při změně požadavků.

Závěr

  • Nepoužívejte definici SRP, která zní: “Class or module should have one responsibility” nebo “Class or module should have one, and only one, reason to change”. Je nepřesná a může být i nebezpečná.
  • Používejte následující definici: “Gather together things that change for the same reasons and at the same times. Separate things that change for different reasons or at different times.” Je novější a lépe vystihuje originální myšlenku.