Převis poptávky po kvalifikovaných IT pracovnících tlačí mzdy v tomto oboru nahoru a dává uspět i specialistům, jejichž kvalifikace není zrovna optimální. Nikdy mě nebavilo dělat pořád dokola to samé, takže si udržuji poměrně široký záběr napříč více IT disciplínami. Je to vůbec možné? Mám na to, nebo umím řadu věcí špatně a pořádně nic?
Je to zhruba rok, co jsem svoje portfolio znalostí rozšířil o programování webových aplikací v ASP.NET. Když jsem se do toho pouštěl, měl jsem obavy, jestli svoji pozornost nerozptyluji příliš do šířky a zda se tak nepřipravím o schopnost být například dobrým analytikem. Zkušenosti získané při programování v ASP.NET mě upozornily na dvě moje skutečně základní neznalosti v SQL. Odnáším si z toho dva závěry - (1) skutečně mě překvapuje, že jsem mohl tak dlouho s tak základní mezerou ve svých znalostech fungovat, a že si (2) musím svůj široký záběr udržet, protože moje schopnost daný problém řešit komplexně s využitím širokých znalostí je právě to, na čem stavím svoji přidanou hodnotu.
Přiznávat svoje chyby mi nevadí, takže se o ně v textu níže podělím a vy se z nich můžete poučit.
Training is always expensive
Je to zhruba 15 let, kdy mi můj tehdejší zaměstnavatel dal za úkol zpracovat nějaká data o klientech. Nic jiného než MS Access jsem k tomu nedostal. Uměl jsem docela dobře programovat ve VBA pro MS Office, takže rozšířit jeho použití o datové manipulace založené na SQL pro mě bylo poměrně jednoduché. O něco později jsem se naučil připojit se z MS Accessu na databázi Oracle. Mohl jsem tak do svého stolního počítače kopírovat produkční data a dělat nad nimi dotazy tak, jak jsem potřeboval. Byl to úžasně jednoduchý a pružný způsob, jak o datech zjistit doslova cokoliv. Velmi jsem si to užíval a naučil jsem se kolem toho spoustu triků, jako třeba že je dobré jednotlivé sloupce v tabulkách indexovat. Nebo že je rychlejší data importovat do tabulky bez indexů a indexy nastavit až pak, a podobně. Také jsem postupně zjistil, že u pohovorů obvykle padají důmyslné otázky, kde odpovědí je použití LEFT JOIN, RIGHT JOIN, IS NULL, COUNT nebo GROUP BY a HAVING. A protože v tomto rozsahu jsem SQL bezpečně ovládal, měl jsem za to, že už to docela dobře umím.
Někdy v té době mému zaměstnavateli přivezl dodavatel demo verzi nového systému a naplnil ji testovacími daty. Systém s nimi běžel neskutečně pomalu a o příčinách se vedly zasvěcené diskuse. Jednou jsem se, plný sebevědomí z nově nabytých zkušeností, lidí od dodavatele zeptal, jak indexují data v tabulkách. Chvíli se na sebe dívali a pak se jeden z nich osmělil a nejistě se zeptal, co že to ty indexy vlastně jsou. Velmi mě to pobavilo a řadu let jsem to dával k lepšímu jako skvělou historku.
Když jsem se tenkrát snažil vysvětlit, k čemu jsou indexy dobré a proč že je vhodné je použít, dostalo se mně uzemnění, že jejich databáze není relační, ale objektová, že si ji sami vytvořili a že samozřejmě žádné indexy nepotřebuje. Vzápětí byl ale problém s rychlostí systému v zásadě vyřešen a do spuštění systému dodavatel svoji objektovou databázi vyměnil za Oracle.
Z té doby pochází nadpis mého článku, bonmotem "Training is always expensive" jsem totiž častoval svého šéfa pokaždé, když dodavatel přiznal některý ze specifických "design patternů", na jejichž základě svůj software vyvíjel. Chtěl jsem tím poukázat na to, že někdo cenu za získávání znalostí zaplatit musí - a v tomto případě to byl můj zaměstnavatel jako zákazník toho dodavatele.
Spolupráce s tímto konkrétním dodavatelem byla skutečně bolestná. Jejich analytici a programátoři totiž ctili zásadu, že nikdy nebudou řešit problém dříve, než nastane. Praktickým důsledkem tohoto přístupu pak bylo to, že funkčně promyšlené nebo výkonově optimalizované byly jen ty části softwaru, které v původní nepromyšlené a prvoplánové variantě byly zákazníkem odmítnuty a dodavatel je musel předělávat. S tím souvisela mimořádně nepříjemná vlastnost celého řešení: nikde, kde to nebylo výslovně požadováno, nepočítalo s vložením hodnot mimo správný rozsah nebo v jiném než správném formátu - v takovém případě systém nejčastěji zobrazil run-time error a odmítal dále jakkoliv pokračovat. Dodavatel tento postup obhajoval tím, že je podstatně lepší, když je problém zjevný a musí být odborně řešen, než když si aplikace s nesprávnými daty nějak poradí a na problém se přijde až s odstupem času.
Během dalších let jsem na řadě projektů SQL okrajově používal, několikrát jsem vytvořil jednorázový nástroj pro migraci a transformaci dat, který data ze zdrojového systému importoval do lokální databáze, tam je zpracoval a exportoval ve struktuře vhodné pro cílový systém, nebo jsem v rámci analýzy a designu IT řešení navrhoval datové modely. Prostě jsem normálně fungoval a přišlo mi, že co se SQL týče, základní znalosti potřebné pro svoji práci mám a mohu se na ně spolehnout.
Během posledního roku jsem při programování v ASP.NET úspěšně - obložen řadou článků a nápověd - vytvořil i dotazy umožňující stránkování výpisu dat pomocí klauzulí with a over a připadal jsem si, že projekty vykonávám s "odbornou péčí". Vážně jsem nečekal, že v průběhu jednoho měsíce budu dvakrát čelit problémům jak vystřiženým z výše popisovaného projektu.
A co znaky jiné než české znakové sady?
První problém mě zaskočil pozdě odpoledne, kdy mi web používaný již přes půl roku jedním z mých zákazníků poslal následující email.
Když dostanu podobný email, tak to znamená, že zákazník udělal něco skutečně tak nečekaného, že si s tím aplikace neporadila a napsala mu na obrazovku,
že došlo k chybě a že data nemohla být zpracována. Ani chvíli neváhám a zákazníkovi posílám email s omluvou a prosbou o popis toho, co se vlastně přihodilo. Vím přesně, na které obrazovce a při které operaci k chybě došlo, ale nevím, co se doopravdy stalo. Popis chyby "Multiple-step OLE DB operation generated errors. Check each OLE DB status value, if available. No work was done." je do té míry mlhavý, že vážně nevím, co s tím.
Záhy se ukazuje, že zákazník do jednoho z polí ve formuláři v části pro správu webu nakopíroval část textu z MS Wordu a pokusil se data uložit - neúspěšně. Pořád nechápu, co se mohlo stát, a nechávám si část textu poslat emailem. Nic zvláštního na ní nevidím, ale na testovacím systému chybu rychle reprodukuji.
Připadám si jako o více než deset let mladší a u tehdejšího dodavatele - ano, problém v tomto případě řeším až tehdy, kdy k němu dojde.
Před časem se mi jeden kolega - programátor svěřil s tím, co ho na jeho práci tolik stresuje: Totiž to, že nikdy neví, kde nechal jakou chybu. Já svoje duševní zdraví léta opírám o víru, že pokud je aplikace pořádně otestovaná a dělá to, co je popsáno v dokumentaci, tak je z definice naprogramovaná správně.
Ale zpátky k té chybě při ukládání dat. Problém byl způsoben tím, že v kopírovaném textu byl neviditelný znak, kterým MS Word označuje konce řádek v "seznamu s odrážkami" (bulleted list). Pole, do kterého byla na MS SQL serveru data ukládána, bylo typu VARCHAR s českou kódovou stránkou, ale onen neviditelný znak z české znakové sady nebyl. Co mi paměť sahá, nikdy jsem pole typu NVARCHAR, které je sto unicode znaky jako tento pojmout, nepoužil, a nikdy jsem nezaznamenal, že by to čemukoliv vadilo. Pozoruhodné, že?
Okamžitě se mi vybavilo, jak jsem před lety u nějakého pohovoru dostal otázku na datové typy Oraclu pro ukládání znakových řetězců a jak jsem neuspěl, když jsem uvedl pouze CHAR a VARCHAR a úplně jsem pominul typy jako VARCHAR2 a NVARCHAR2.
Složené indexy
Druhý případ se stal s odstupem cca 3 týdnů. Z důvodů souvisejících s produktovou nabídkou mého oblíbeného hostingového poskytovatele (a potažmo zřejmě kvůli licenčním podmínkám Microsoftu) jsem se rozhodl, že nová část databáze pod serverem www.mentio.cz bude uložená nikoliv na MS SQL serveru, ale na MySQL serveru. Navrhl jsem datový model a do administračního rozhraní MySQL jsem začal sázet tabulku za tabulkou. MySQL jsem zatím použil pouze v několika velmi malých projektech s velmi dočasným rozsahem nasazení (například v rámci diplomky), takže jsem měl oči na stopkách, abych něco nepřehlédl (vida, žádný NVARCHAR, ale VARCHAR i pro znaky unicode / UFT-8). Když jsem došel k indexům, uživatelské rozhraní se mě u každého dalšího indexu ptalo, jestli má být definován jako samostatný index nebo jako součást již existujícího indexu jako složený index. Odpovědí jsem si nebyl úplně jistý a tak jsem začal Googlovat o složených indexech.
Nebudu to protahovat, rovnou přiznám svoje omyly. Vždycky jsem si myslel, že použití několika jednoduchých nebo jednoho složeného indexu se liší hlavně tím, že u složeného indexu je možné vynutit zajištění unikátnosti kombinací obsahu v indexovaných sloupcích. Také jsem si myslel, že moje oblíbené první prostředí,
kde jsem SQL používal, totiž MS Access, umožňuje použití složených indexů pouze pro primární klíče, nikoliv pro ostatní sloupce v tabulce. Jak je vidět na obrázku níže, není tomu tak, dokonce i MS Access použití složených indexů umožňuje.
Čtu si články, které mně Google našel, a říkám si: "Jak jsem, proboha, takto zásadní věc mohl nevědět? Kolik času jsem mohl svým zákazníkům a sobě ušetřit? Poskytoval jsem jim služby s odbornou péčí?"
Tak schválně, otevírám zdrojovým kód webu www.mentio,cz, procházím každou z aktuálních 42 databázových tabulek. Ke svému překvapení zjišťuji, že s novými znalostmi toho moc nevylepším. U 39 tabulek nic neměním, protože jednotlivé indexy jsou vždy dostatečně selektivní a v několika případech jsem dokonce složené indexy - s cílem zajistit jedinečnost kombinací hodnot - správně nastavil. Myslím, že to souvisí s tím, že tabulky navrhuji cíleně předem tak, aby byly ve vhodné normální formě, a aby jednoduché indexy, které jsem zatím jako jediné doopravdy uměl používat, byly pro prohledávání tabulek dostatečně účinné. U dvou tabulek potřebné složené indexy chyběly - což jsem rychle napravil. Z hlediska uživatele se změna ale vůbec neprojevila, protože výsledná stránka pro uživatele byla generována v okamžiku vložení nových dat administrátorem - tedy mnou - a cachována ve formě textového souborů na disku webového serveru. V případě jedné tabulky jsem (kvůli úspoře klikání) skutečně složený index pro kombinaci celkem 12ti sloupců použil, ale sloupce jsem měl ve špatném pořadí - tady by časem po naplnění tabulky více záznamy došlo k výkonovým potížím, které bych - až by nastaly - muset řešit. A v uších mi opět zní "problémy neřešíme dříve, než nastanou". Ono to má nakonec něco do sebe.
Závěrečná poznámka pro hloubavého čtenáře? Víte, k čemu je "clustered index" a proč nemůže být v tabulce více než jeden?