
Jak posouváme hranice výzkumu
Přiblížit si něco tak moc, že uvidíte atomy? To v dnešní době není problém.
Přejít na obsah | Přejít k hlavnímu menu | Přejít k vyhledávání
Píše se rok 2001, sedím v budově č. 9 na hlavním kampusu Microsoftu v Redmondu a můj tým usilovně pracuje na verzi .NET Framework 1.1.
Můj vedoucí mi mírně podrážděný telefonuje, stěžuje si na nedostatečnou osvětu u programátorů a domlouvá nám schůzku u týmu, který řeší statickou analýzu kódu. Chceme tam přidat několik pravidel, abychom pomohli vývojářům zachytit běžné chyby, které se většinou projeví až potom, co si uživatel přepne jazykové nastavení ve Windows.
V hlavě mi mimovolně naskočí jedna z našich vlastních tříd: System.Globalization.RegionInfo. Máme tam konstruktor, který má na vstupu parametr typu string. Jeho hodnota může být buď jeden z předdefinovaných kódů v ISO 3166, nebo název kultury/jazyka. Instance daného typu pak slouží jako jakýsi poskytovatel informací o regionu, který je asociovaný s daným kódem nebo kulturou.
Naskakuje mi pot na čele. Tohle není dobré. Přemýšlím, jak se bude můj vedoucí tvářit až mu budu oznamovat, že ani naši vlastní programátoři nebyli zatím dostatečně zasaženi osvětou, kterou tak vášnivě pumpujeme do zbytku organizace. A že jako tester jsem to neobjevil dřív. A jak se s tím pak asi poperou ty miliony vývojářů, kteří budou na .NET stavět své aplikace?
Problém je v normalizaci vstupu pomocí metody ToUpper. Tahle metoda, stejně jako několik dalších ve třídě String, má dvě přetížení:
Je velká šance, že si jako vývojář v téhle chvíli řeknu, že operace normalizace kódu ISO 3166 nemá být závislá na konkrétním jazykovém nastavení a sáhnu po první verzi bez parametru CultureInfo. Co si ale nevšimnu: Ve skutečnosti tahle metoda používá jako výchozí kulturu pro převedení písmen CultureInfo.CurrentCulture. Ta většinou koresponduje s aktuálně vybraným jazykovým nastavením uživatele ve Windows.
Kde se pak tohle vysype, je v jazycích, které mají zvláštní formy jinak běžných písmen. Třeba turečtina má 4 varianty písmena „i“: i, İ, ı, I. Podle pravidel pro tenhle jazyk je pro malé „i“ forma velkého písmena „İ“ – velké I s tečkou.
V téhle chvíli už je asi jasné, co se stalo – “it” ToUpper() = “İT” – a to není validní kód regionu.
Rychlá odpověď: neúplný rozklad na třídy ekvivalence. Základní rozklad pro konstruktor RegionInfo(string name) by mohl vypadat třeba takhle:
Případ |
Parametr name |
Očekávaný výsledek |
Nevalidní – null | null | ArgumentNullExpection |
Nevalidní – prázdný | “” | ArgumentException |
Nevalidní kód/kultura | “ABCD” | ArgumentException |
Nevalidní – neutrální kultura bez asociovaného regionu | “en” | ArgumentException |
Validní – specifická kultura | “en-US” | Ok |
Validní kód ISO 3166 | “IT” | Ok |
Validní kód ISO 3166, normalizace | “it” | Ok |
Bohužel tento rozklad nepokrývá, že pod pokličkou probíhá normalizace s využitím metody ToUpper a že se používá přetížení které závisí na aktuálním jazyku ve Windows. Opravený rozklad:
Případ |
Parametr name |
Očekávaný výsledek |
Current Culture |
Nevalidní – null | null | ArgumentNullExpection | Nezáleží |
Nevalidní – prázdný | “” | ArgumentException | |
Nevalidní kód/kultura | “ABCD” | ArgumentException | |
Nevalidní – neutrální kultura bez asociovaného regionu | “en” | ArgumentException | |
Validní – specifická kultura | “en-US” | Ok | |
Validní – specifická kultura | “it-it” | Ok | en-US |
Validní – specifická kultura | “it-it” | Ok | tr-TR |
Validní kód ISO 3166 | “IT” | Ok | |
Validní kód ISO 3166, normalizace | “it” | Ok | en-US |
Validní kód ISO 3166, normalizace | “it” | Ok | tr-TR |
Konstruktor třídy RegionInfo nebyl zdaleka jediným problémovým místem, bylo jich mnohem víc. Musely se přepsat všechny operace na řetězcích, kde se vysloveně nevyžadovalo uplatnit pravidla pro specifický jazyk tak, aby používaly tzv. invariantní kulturu. Tím se získá objekt, který je nezávislý na jazykové mutaci a zpracování hodnot typu String bude nezávislé na aktuálním jazykovém nastavení ve Windows. V případě konstruktoru RegionInfo to znamenalo použít metodu ToUpper(CultureInfo.InvariantCulture).
Ten problém byl ale ve skutečnosti ještě hlubší. Skutečným zdrojem byl nevhodný návrh operací ve třídě String, které jako výchozí nastavení pro většinu operací používají CurrentCulture. Tohle nebylo možné jednoduše opravit, protože třída Systém.String už byla venku mezi zákazníky a z důvodu kompatibility nebylo možné najednou změnit výchozí chování jejich metod.
V průběhu delšího období se tak postupně zavedlo několik nápravných opatření, aby se zamezilo nesprávnému použití:
Nic z toho už bohužel nemohlo zvrátit nešťastný původní návrh, jenom omezit negativní důsledky.
Jako kdybych slyšel mé dospívající syny, když píšu tyhle řádky. .NET 1.1, to existovalo? Každé pozvání ke společnému zhlédnutí mého oblíbeného filmu začíná otázkou „A je to barevné nebo černobílé?“.
Současnost je rozhodně barevná. Ale jsou věci, které zůstávají černobílé: buď je ten rozklad úplný nebo není. A když není, máš problém.
Přiblížit si něco tak moc, že uvidíte atomy? To v dnešní době není problém.
Když před dvěma lety OpenAI představila ChatGPT, začaly se objevovat názory, že vývojáři a testeři přijdou o práci. Po dvou letech ale můžeme konstatovat, že tomu tak není. Kde se stala chyba a jaké nové výzvy nám AI představila?
Robot Framework je rozšířený testovací tool založený na pythonu, udržovaný komunitou a zdarma. Poměr cena/výkon tedy vychází velmi výhodně. Syntaxe Robot Frameworku je založená na klíčových slovech (keywords). Poradí si Robot Framework s BDD a s Gherkinem? Pojďme se na to podívat.
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.