Atributy jsou zlo

Atributy v C# (v ostatních jazycích známé např. jako anotace) považuju ve většině případů za zlo, protože porušují SRP – třída pak dělá více než musí – navíc si s sebou nese metadata. Na první pohled vypadají atributy jako super věc, ale snadno můžete narazit na situaci, kdy se vám vymstí mít všechno na jedné hromadě – a pak budete litovat, že používáte atributy.

Představte si, že např. děláte systém, který máte nasazený u více zákazníků. Defaultně máte na třídě Person omezení pomocí atributu na maximální délku příjmení na 50 znaků. Teď si ale jeden zákazník vzpomene, že potřebuje maximální délku zvýšit na 100 znaků. Pokud nechceme provést tuto úpravu i u ostatních zákazníků, jsme s atributy v problémech.

Mnohem více se mi líbí uložení metadat někde úplně mimo a vytažení metadat pro danou třídu dynamicky z nějakého metadata-provideru za běhu aplikace. Odkud si metadata onen provider vytáhne je jeho problém – může si je vytáhnout z databáze, konfiguračních souborů nebo klidně z atributů.

ASP.NET MVC

Pokud sledujete vývoj ASP.NET MVC, došlo zde přesně k tomuto posunu od atributů k obecnému metadata-provideru. V prvních verzích ASP.NET MVC se ViewModely odekorovaly pomocí atributů z namespace DataAnnotations a podle toho se vyrenderovaly UI prvky (omezení na max. délku stringu v JavaScriptu apod.).
V posledních verzích došlo k zobecnění a byla zavedena abstraktní třída ModelMetadataProvider, z které můžete podědit a tahat si metadata odkukoliv je libo. Samozřejmě je standardně dodáván DataAnnotationsModelMetadataProvider (to je jméno! :-)), který čte metadata z DataAnnotations atributů, čímž je zajištěna zpětná kompatibilita.

Díky tomuto obecnému konceptu můžete např. validační pravidla definovat pěkně silně typově pomocí FluentValidation a do ASP.NET MVC je přenést pomocí FluentValidationModelMetadataProvider.

Jak se tedy postavit k použití atributů?

Když už máte nějaké třídy, které jsou odekorovány atributy a nemůžete to změnit, napište alespoň kód pracující s těmito třídami tak, aby se atributy nepoužívaly napřímo, ale zprostředkovaně přes nějakého metadata-providera.

Pokud bych dělal na malé neperspektivní aplikaci, asi bych použití atributů překousl. Ale vždy (vždy!) nějak abstrahujte čtení atributů, tj. nevolejte napřímo GetCustomAttributes. A právě tato abstrakce je de facto onen metadata-provider.

12 thoughts on “Atributy jsou zlo

  1. Proč ten bulvarizující nadpis? Z názvu „atributy jsou zlo“ nakonec vypadlo, že na atributech v podstatě nic špatného není, akorát se nesmí cpát bezhlavě všude a nemá se s nimi (stejně jako s milionem jiných věcí) pracovat napřímo, ale přes nějaké rozhraní.
    Ale jinak ne že bych s článkem nesouhlasil…

    To se mi líbí

  2. Horší než vymýšlení nadpisů článků je už jen invalidace cache 😉
    Za zlo atributy považuji právě proto, že člověk (aspoň já jsem takový byl) má díky jejich podbízivé kráse a snadnému použití tendenci je cpát všude. Tak jsem chtěl upozornit na obezřetnost, s níž by se k nim mělo přistupovat…

    To se mi líbí

  3. Atributy jsou dobro – používáš extension metody? Používáš P/Invoke? Používáš XML serializaci? WCF? Nějak si nedokážu představit příklad, kdy pro jednu instanci aplikace chceš mít metodu jako extension a pro druhou ne. To je jako se vším – když potřebuješ něco obecnějšího (jako v tvém konkrétním případě), tak to použiješ, když by to přineslo zbytečný overhead, (víš, že prostě WinAPI funkce GetNěcoEx2 se bude jmenovat stejně vždycky), tak proč je nepoužít?

    To se mi líbí

  4. Jo, to jsi vyjmenoval případy, kdy se atributy musí použít, protože to tak v Microsoftu udělali. To ale neznamená, že by to nešlo nadesignovat lépe 🙂

    To se mi líbí

  5. No já myslím, že nadesignovat lépe by prostě byl zbytečný overhead. Jsou věci, který se měnit nebudou, např. tyhle systémový, obecně něco, co je úzce spojené s vnitřní logikou, stejně jako počet prstů si nadeklaruješ jako int a ne jako něco. co je schopné ukládat libovolně velká čísla s libovolnou přesností :). Nejsou metadata jako metadata. Někde ta hranice, za kterou se nevyplatí abstrahovat být musí, asi člověk nepíše skladový systém tak, aby šel konfiguračně přiohnout na ovládání letů do vesmíru 🙂

    To se mi líbí

  6. Já zase považuju za zlo ten způsob myšlení, že „co kdyby to náhodou někdo někdy chtěl změnit“. To porušuje podle mého mnohem zásadnější princip, než je SRP – totiž KISS.

    Nevedu si přesnou statistiku, ale pocitově mi přijde, že s „under-engineered“ řešením se setkávám mnohem méně často, než s „over-engineered“, kde je všechno řešeno nějakým „enterprise“ způsobem. A úplně nejčastější mi přijdou ty případy, kdy je to sice impresivně složité, ale zato napsané tak, že je to fakticky nerozšiřitelné.

    To se mi líbí

  7. Souhlasím s Altairem, a taky bych upřednostnil KIS –
    proč hned dělat „enterprise“ řešení, atributy jsou fajn a na většinu případů stačí.
    Když se ukáže, jako v tvém příkladu, že to nestačí, tak atribut smázneš a budeš maximální délku nastavovat jinak, ostatně stejně jako to udělali u Microsoftu…

    To se mi líbí

  8. někdy mi příjde, že větou začínající na „Teď si ale jeden zákazník vzpomene, že …“ bych dokázal zpochybnit prakticky cokoliv z oboru softwarového inženýrství :]

    jinak s atributama zacházím velice opatrně, ale objektivně mi spoustu práce ušetří

    inb4 „Třídy jsou zlo“

    :]

    To se mi líbí

  9. A co tedy, Augi, říkáš na MEF? Tedy na jeho výchozí podobu, vím, že jádro MEFu je na atributech nezávislé.
    Mně na atributech vadí jen to, ž je snadné s nimi vytapetovat prostor nad názvem třídy.BTW: Vidím, že je antipattern se teď píše je zlo. 🙂

    To se mi líbí

  10. Tak určitě! Můžeš mít atributy, a může to bejt dobrý. Ale pak si zákazník vzpomene, a pak to není dobrý. Ale když si zákazník nevzpomene a ty máš supersystém na metadata, tak to taky není dobrý.

    Chci říct, atributy jsou statický metadata, což je zlo když potřebuješ dynamický metadata, ale dobro když stačí statický metadata;)

    To se mi líbí

  11. Petr Snobelt: To jedno rozhraní navíc z celého systému IMHO nedělá enterprise řešení 🙂

    Isac: Ale zrovna ta moje věta popisuje tak elementární požadavek, že IMHO stojí za to se nad tím zamyslet, jestli by to nešlo udělat lépe.

    René: Protože jádro MEFu není na atributech závislé, tak u mě dobrý 🙂 Je to vlastně stejná situace jako v případě zmiňovaného ModelMetadataProvideru z ASP.NET MVC.

    dkl: Právě proto jsem psal, že u malé neperspektivní aplikace jsou atributy ok 🙂
    Vytvoření metadata-systému pomocí atributů a pomocí providerů je IMHO stejně náročné (ani jedno není o řád složitější/jednodušší).

    To se mi líbí

  12. jo, v tom případě co se zmiňuje v článku je použití toho atributu na pováženou

    podle mě nejsou ani tak problém ty atributy, jako spíš jejich úžasná schopnost nalákat vývojáře na „jednoduché a elegantní řešení“, které se nakonec ukáže jako jednoduché, ale ne až tak elegantní :]

    To se mi líbí

Napsat komentář

Tento web používá Akismet na redukci spamu. Zjistěte více o tom, jak jsou data z komentářů zpracovávána.