16 komentářů k článku SOLID – (S)ingle Responsibility Principle:

  1. dzejkob

    Co na to říct? Principiálně hezký učebnicový příklad a bylo by fajn, kdyby se to tak dělalo. V realitě se ovšem počká, až Mařenka přijde – opraví se bugy a potom se to překlopí do režimu „to funguje – na to se nesahá“.

    1. Tomáš DusíkAutor příspěvku

      Re:
      Ahoj, díky za komentář.
      Já se snažím vyvíjet podle TDD, aby bugů bylo co nejméně a design byl co nejvíce jednoduchý a flexibilní.
      Jednoduchý a flexibilní design = dodržování SOLIDu. Aby se dobře testovalo tak jsou třídy malé a každá má jasnou responsibilitu (SRP). Jelikož jsou třídy malé tak jsou i solidně pokryté testy. Jelikož jsou solidně pokryté testy tak se do nich nebojím šáhnout :)

      V realitě (teda aspoň v té mojí) se věci mění rychle, to je prostě vývoj. Bát se šáhnout do nějakého kódu je cesta do pekel a proto se snažím udělat vše proto abych se nebál = testy testy a zase testy.

  2. lenoch

    Já mám šablonu mailu, kde je text mailu, subject a další parametry zprávy a pak třídu Mailer, která tu zprávu pošle.

  3. Tomáš Votruba

    Diky za srozumitelný a názorný příklad
    Ahoj, moc se mi líbí jak jsi to pojal.
    Když vidím někoho tento pojem vysvětlovat, tak vezme nejsložitější příklad, který v poslední době potkal.

    Email sender a mail factory je krásné, krátké a k věci.

    Jsem z PHP komunitu, koukal jsem na příklad a napadlo mě, máte tam nějaký Dependency Injection Container? Bez něj ten kód spíš spoustu lidí odradí svou náročnou udržitelností.

    1. Tomáš DusíkAutor příspěvku

      Re: Diky za srozumitelný a názorný příklad
      Ahoj, díky moc, to jsem rád.
      Co se týče DI containeru tak jsem injectováni dependencies snažil řešit spíše jiným způsobem, např přes Factories a Abstract Factories. Záleží na velikosti projektu a na tom co od toho DI containeru vlastně očekáváš.

      Přijde mi, že k tomu abych si injectnul třídu tak s použitím DI containeru musím pořádně zaplevelit kód, viz jsfiddle pro typescript example s DI container. Ale je to jen můj názor, možná to je v PHP vyřešené jiným způsobem.

      1. Tomáš Votruba

        Re: Diky za srozumitelný a názorný příklad

        Přijde mi, že k tomu abych si injectnul třídu tak s použitím DI containeru musím pořádně zaplevelit kód, viz jsfiddle pro typescript example s DI container. Ale je to jen můj názor, možná to je v PHP vyřešené jiným způsobem.

        To je pravda. Psát vlastní kontejner vše zkomplikuje a sám to dělám jen na školení, když vysvětluji co DI kontejner je (díky za tip Davide Grudle). V PHP si ho sám nepíšu, ale používám hotové řešení (Symfony\DependencyInjection nebo Nette\DI).

        Co DI kontejeru očekávám?

        1. Nahážu tam třídy, které chci jako služby
        2. Když jednu vytáhnu, tak má v sobě všechny potřebné závislosti (nejlíp přes constructor)

        A díky moc za ten příklad v jsfiddle. Takový kontejner vypadá složitě, znečišťuje a znepřehledňuje kód, takže chápu proč preferuješ factories.

  4. Jaroslav Týc

    Takhle by to šlo
    Podle titulku a úvodu jsem si říkal „a jéje, někdo byl včera na přednášce a dneska nám píše, co jim pan profesor vtloukal do hlavy“, ale hned jak přišla věta „já jsem si vybral…“, tak jsem věděl, že to bude napsané z osobní zkušenosti a má cenu čít dál.
    Díky za kvalitní popis z osobním pohledem na věc a za příklad, který dává smysl od začátku do konce.

  5. Vít Heřman

    SRP z jiného pohledu
    Zdravím,

    nedávno jsem o SRP psal takové vnitrofiremní pojednání o převažujícím podivném chápání pojmu SRP. Zjistil jsem, že programátoři usilující o dodržení SRP mají snahu dekomponovat daleko více, než je únosné. Výsledkem bývá hrozivý moloch malých interfaců a tříd, které reprezentují často velmi umělé abstrakce. Často pod chybně chápanou záminkou testovatelnosti.

    Výsledkem je dramaticky větší množství entit v systému a také daleko větší množství infrastrukturního kódu (třídy nebo rozhranní, které v podstatě jen uměle lepí jiná rozhraní a třídy, apod.). To vše přináší neúnosnou komplexitu snižující pochopitelnost systému na základě studia kódu. A to považuji za nesrovnatelně větší zlo, než-li prohřešky vůči SOLID principům.

    Módní koncepty jako interface všude, DI a IoC tomu nasazují korunu. Tyto koncepty mají skutečně jen velmi málo exklusivních přínosů. Třeba v případě šířených veřejných knihoven nebo frameworků, od kterých je požadována vysoká extensibilita ty přínosy vidět jsou. Pochopitelnost sice trpí jak ďas, ale rozšiřitelnost je vynikající. Jde sice o trade-off, ale přínos je zřejmý. Ale třeba v zákaznických aplikacích je to čirá zbytečnost, protože potřeba znovupoužitelnosti na úrovni binárního kódu je skoro nulová. Není problém provést změnu ve zdrojovém kódu aplikace a během pár minut nasadit (zjednodušeně řečeno).

    V tomto příkladu jistou nadbytečností zavánějí třídy (rozhranní) jako (I)EmailTransporter, (I)EmailBuilder. Obyčejné dvě metody (a třeba fluent API) poslouží lépe:

     mailing
        .createEmail(sender, recipient, subject, body)
        .send(configuration.smtpOptions)
    

    Proto doporučuji být k SOLID principům skeptický. Nedoporučuji slepě následovat jejich tisíckrát prezentované výhody. Hlavní je zamyslet se do hloubky, zda jde o skutečnou výhodu pro mou aplikaci a uvědomit si zamlčované náklady, o kterých žádná kniha nebo prezentéři moc nemluví…

    1. Radek

      Re: SRP z jiného pohledu
      Chápu, že můžete mít problém se zneužitím DI, SRP a dalších. Aby to lidem něco řeklo, o jak velkých projektech se bavíme? Vytváří je tým se sdílenými znalostmi nebo se vývojáři střídají? Řeší váš software problémy se známým řešením nebo prochází kontinuálními proměnami?

      1. Vít Heřman

        Re: SRP z jiného pohledu
        Bavíme se o projektech velikosti řádově desetitisíce LOC, tým usiluje o sdílené znalosti, ale přesto dochází ke střídání. Jedná se o víceméně standardní zákaznické projekty s SQL databází na pozadí, formuláři nebo webovkama na popředí a business logikou uprostřed.

        Zásadní je ale u těchto typů aplikací to, že skoro vždy se jedná o dost specifická zákaznická řešení na míru, kde je snadná změna zdrojového kódu a není tedy v zásadě problém měnit kontrakty tříd.

        Chtělo by to hlouběji rozebrat, ale obecně mi dávají univerzální smysl pouze „L“ a „I“ ze SOLIDu. „S“ je těžko uchopitelné (snažil jsem se naznačit), „O“ je výhodné pouze pro frameworky. A nakonec výhody „D“ jakožto důsledné závislosti výhradně na abstrakcích jsou sporadické, protože nutí abstrahovat i to, co v systému abstraktní být nemusí. Raději opakuji, že mluvím o zákaznických aplikacích se snadnou realizací změn na úrovni zdrojového kódu. A díky tomu nejen, že lze, ale i je výhodné abstrahovat méně. Na čitelnost kódu a udržitelnost to má vliv spíše pozitivní, protože v systému potom existuje daleko méně „entit“.

        Zjednodušeně řečeno podle mne platí, že systém se snáze spravuje, pokud minimalizujeme počet entit (např. tříd a rozhraní) a ty mají pochopitelné a dobře zvolené kontrakty. Interní implementace metod je důležitá také, ale druhořadá.

        A díky tomu se nemůžu zbavit pocitu hraničícím s jistotou, že SOLID přímo navádí k nadměrnému množství entit ve zdrojovém kódu a právě tím znesnadňuje jeho údržbu. To je jeho náklad, který musí být vyvážen nějakou podstatnou výhodou. A tou výhodou je znovupoužitelnost a rozšiřitelnost nejrůznějších částí formou rozšiřování a nikoli změn interních implementací. Ale nějak racionálně obhájit to lze podle mého jen u knihoven a frameworků.

  6. Vasek

    Je dobry napad ukazovat principy OOP sveta na spise funkcionalnim jazyku? Jako chapu ze Typescriptu je vyrazny krok k OOP v JS, ale presto si myslim, ze ukazkove implementace by byly lepsi v jinem nez jazyce.

    Nechci tim nijak zlehcovat praci, kterou jsi udelal, a UMLka ktera jsi vytvoril. To je super a pochopi to z toho mnoho novych lidi, to je uzasne.. Ale ten zvoleny jazyk mi prijde spis ku neprospechu veci.

  7. Radek

    Jsem rád za tenhle seriál. Podle mě je SOLID zásadní při OO vývoji.

    Navržená dekompozice by však podle mě měla pokračovat. Zpráva nemá zodpovědnost za odesílání a ani nemá vědět, jak bude odeslána. Metodu send a atribut transport bych z ní smazal. Šel bych i dál a zrušil vazbu na message builder, naopak bych přidal metodu ve smyslu public string serialize (SerializerInterface serializer). Pak
    už s minimální prací můžeme zprávu poslat jak e-mailem, tak třeba jako notifikaci na mobil.

    1. lenoch

      Re:
      To send() ve zprávě mi taky zavání. Osobně si zatím myslím, že by měla stačit třída MailSender a Message, eventuálně s odpovídajícími interface. Možná, že je potřeba někdy dekomponovat ještě na další třídy, ale zatím na to nevidím valný důvod.

      1. mirek

        Re:
        Naprostou souhlasim. Dokonce bych si troufl rict, ze uvedena „dekompozice“ je pro me az trochu silena. Uz kdyz jsem cetl prvni odstavec s odkazem na knihu Cisty kod, cekal jsem neco podobneho. Uz z navrhu autora musi preci kazdeho trknout zavislost zpravy na dalsich sluzbach. Sama zprava se dokaze odeslat? V serialu o SOLID? EmailWelcomeMessage bude asi abstraktni (nejaka spolecna logika pro vsechny zpravy), protoze zprav bude vic „druhu“ … vlastne to je jen EmailMessage … nepotrebuje mit odpovedost send() atd, ne?

  8. d@rkWolf

    Hmm, to je krásná ukázka toho, jak vyrobit luxusní, nepřehledný systém, v kterém se vyzná tak akorát autor, kdokoliv další to bude louskat týden a pak doufat.

Napsat komentář

Tato diskuse je již příliš stará, pravděpodobně již vám nikdo neodpoví. Pokud se chcete na něco zeptat, použijte diskusní server Devel.cz

Zdroj: https://www.zdrojak.cz/?p=21077