
Jak QA inženýr kupuje dětské kolo aneb řízení kvality jako součástí každodenního života
Popis výběru a nákupu dětského kola za použití QA principů shift-left a obecně řízení kvality.
Přejít na obsah|Přejít k hlavnímu menu|Přejít k vyhledávání
S imutabilními kolekcemi se v C# setkáváme poměrně často, ale často si neuvědomujeme všechny možnosti, které máme, v čem přesně se liší, a jak vybrat tu správnou v daný moment.
Imutabilní – neboli neměnné – kolekce a kolekce pouze pro čtení působí na první pohled jako jednoduchý koncept. Stačí si představit např. seznam nebo slovník, jehož prvky nelze přidávat ani odebírat, pouze číst.
K čemu je to ale dobré?
Při zodpovídání této otázky zjistíme, že C# nabízí několik typů imutabilních či read-only kolekcí a odpověď záleží na širším kontextu. Pokud chceme psát kvalitní kód, je dobré se v dostupných možnostech vyznat a umět zvolit tu správnou. Pojďme se na ně podívat.
IReadOnly: pouze pro čtení na okoS touto skupinou se vývojáři většinou setkají jako první. Jde o rozhraní jako IReadOnlyList<T>, IReadOnlyCollection<T> nebo IReadOnlyDictionary<TKey, TValue>.
Tato rozhraní obsahují podmnožinu metod klasických kolekcí - chybí právě ty metody, kterými lze kolekce měnit.
List<string> names = ["Ada", "Grace"];
IReadOnlyList<string> roNames = names;Kód pracující s proměnnou roNames nemůže volat metody jako Add, Remove a Clear. To je pro vývojáře užitečný signál a zároveň vynucená kontrola.
Garance imutability je však pouze kosmetická. Kód pracující s původní referencí names může změny provádět libovolně. Obě reference ukazují na tentýž objekt, změna se tedy projeví i v roNames.
Referenci roNames je dokonce možné přetypovat zpět na List<string> a provést změnu. Tímto explicitním porušením kontraktu si však vývojář již v podstatě říká o problémy.
Přestože jsou rozhraní ze skupiny IReadOnly pouze pro čtení spíše na oko, jde o velmi užitečný mechanismus. Jeho využívání téměř nic nestojí a hlavními benefity jsou zpřehlednění kódu a zamezení mutaci kolekce omylem. Ve většině základních případů je to přesně to, co potřebujeme.
ReadOnly: opět jen na okoPro úplnost uveďme, že stejný princip platí i pro podobnou skupinu tříd zahrnující např. ReadOnlyCollection<T>, ReadOnlyDictionary<TKey,TValue> a ReadOnlySet<T>.
ReadOnlyCollection<string> rocNames = names.AsReadOnly();Podobně jako rozhraní skupiny IReadOnly jsou i třídy skupiny ReadOnly jen jakýmsi obalem nad původní referencí. Skrz tento obal nelze kolekci upravovat, protože chybí mutační metody. Ale pod obalem se skrývá klasický mutovatelný objekt.
Immutable: opravdová imutabilitaCo kdybychom místo pouhé reference pouze pro čtení chtěli skutečně imutabilní kolekci?
Intuitivně bychom mohli sáhnout po třídách jako ImmutableList<T>, ImmutableDictionary<TKey, TValue>, ImmutableHashSet<T> a dalších. Instance těchto tříd jsou skutečně imutabilní.
IImmutableList<string> fruits = ImmutableList.Create("kiwi", "mango");Takto vzniklý objekt bude vždy obsahovat právě řetězce kiwi a mango, nehledě na to, kolik referencí na něj vytvoříme a co s nimi budeme dělat.
Jaké benefity tato garance přináší? Tady je potřeba dát pozor na to, k čemu třídy skupiny Immutable ve skutečnosti slouží.
Při práci s imutabilními kolekcemi nejde o to, že se data vůbec nemění. Nesmí se měnit v rámci konkrétního objektu. Pokud chceme kolekci, která například obsahuje jeden prvek navíc, je nutné vytvořit kolekci novou jako kopii původní s naší změnou:
IImmutableList<string> fruitsAndVegetables = fruits.Add("carrot");Podstata Immutable tříd spočívá v tom, že v tomto okamžiku nedochází ke kopírování celé původní kolekce. Vtip je v tom, že na pozadí se využívá mechanismus sdílené paměti, který dovoluje novému objektu efektivně využít neměnná data původní kolekce.
To přináší klíčovou úsporu paměti v situaci, kdy je původní kolekce velká. Změny lze navíc transparentně řetězit.
IImmutableList<string> fruitsAndVegetablesAndMeat = fruitsAndVegetables.Add("beef");Kvůli tomuto mechanismu může být čtení z těchto imutabilních kolekcí pomalejší. Tento kompromis má své opodstatnění. Efektivní vytvoření kopie se změnou při zachování imutability původního objektu je klíčové pro některé styly programování – zejména funkcionální programování – a může účinně zmenšit komplexitu paralelních programů.
Frozen: vytvořit jednou, číst mnohokrátV případě, že chceme imutabilní kolekci skutečně optimalizovanou pro čtení, můžeme od verze .NET 8 sáhnout po FrozenDictionary<TKey,TValue> a FrozenSet<T>.
FrozenSet<string> colors = new HashSet<string> { "yellow", "green" }.ToFrozenSet();Takto vzniklá "zamrzlá" kolekce nabízí rychlé operace pro čtení. To se hodí v případě velké kolekce a častého přístupu k datům v ní. Cenou za tuto optimalizaci je pomalejší vytvoření takové kolekce. Při vytváření jsou totiž data kolekce analyzována a je pro ně vypočítána struktura umožňující právě ono rychlé čtení.
Imutabilní kolekce mají ještě jeden háček: jejich garance se vztahuje pouze na strukturu kolekce. Pokud kolekce obsahuje mutovatelné objekty, jejich data se mohou nadále měnit. Řešení je zřejmé - pokud na tom záleží, je nutné použít imutabilní objekty.
Na závěr si zopakujme možnosti, které nám C# nabízí:
IReadOnly využijeme běžně v kódu, když chceme vyjádřit, že se daná kolekce nemá měnit.Immutable jsou užitečné, pokud potřebujeme vytvářet změny bez modifikace původní instance kolekce.Frozen se hodí, pokud chceme optimalizovat čtení z kolekce za cenu jejího pomalejšího vytvoření a ztráty možnosti ji upravovat.Já osobně v kódu často používám rozhraní IReadOnly. Naproti tomu třídy Immutable a Frozen se hodí spíše ve specifických situacích. Je však užitečné znát jejich vlastnosti nejen pro případy, kdy je jejich použití na místě, ale i proto, abychom se vyhnuli jejich nesprávnému použití.

Popis výběru a nákupu dětského kola za použití QA principů shift-left a obecně řízení kvality.
Děkujeme za váš zájem o odběr našeho newsletteru! Pro dokončení registrace je potřeba potvrdit vaše přihlášení. Na zadaný e-mail jsme vám právě zaslali potvrzovací odkaz. Klikněte prosím na tento odkaz, aby bylo vaše přihlášení dokončeno. Pokud e-mail nenajdete, zkontrolujte prosím složku nevyžádané pošty (spam) nebo složku hromadné pošty.
