V souvislosti se zpracováním OSM dat, jsem s kolegy opětovně provětral můj názor na univerzální řešení. Tento názor není čerstvý. Neustále se vyvíjí a konkretizuje, nicméně spíš se jen piluje do hlubších detailů na základě nových zkušeností, než aby se měnila jeho podstata. Rád bych se o tento, možná kontroverzní názor podělil. Třeba Vás povede k zamyšlení.
Jedna ze zásadních otázek, kterou poslední dobou při takové filozofické diskuzi pokládám, je na robustnost. Sleduji tím dvě věci. V první řadě si „sjednotím“ pojmy s diskutujícím. Přeci jen, každý si pod i běžnými pojmem představuje malinko něco jiného. A pojem robustní software nebo robustní knihovna je dost nekonkrétní sám o sobě. Sekundárně se pak pokouším naladit partnera v diskuzi. I on se pak zamyslí nad tím, že pojmy mohou být jinak chápány. Jednak to tvoří přátelštější diskuzi a pak je diskutující ochoten více naslouchat.
Já si pod pojmem „robustní“ představuji neprůstřelné, silné a funkční. Jiní si pod tímto pojmem představují spíše univerzální, nebo komplexní řešení pohlcující všechny situace. To je ale dost zásadní rozdíl. Ten první, můj pohled, je typický zejména pro unixové nástroje. Ty jsou malé, rychlé a řeší jen malou specifickou část problému. Zato ji řeší tak nejlépe, jak umí. Díky tomu obsahují daleko menší množství chyb, které by obsahovala komplexní alternativa. Druhý přístup je znám především z různých knihoven, nebo frameworků. Často tyto knihovny, nebo tedy frameworky, složené z většího množství knihoven, řeší velmi širokou a komplexní škálu situací, které může programátor, coby uživatel takového frameworku potřebovat.
Proto pro ujasnění termínů budu používat slovo „univerzální“ a „konkrétní“.
Pod pojmem „univerzální“ si představuji řešení generické, pokrývající širokou škálu problémů, tedy komplexní. Příkladem může být například mj. výborná knihovna Boost, jenž je častým zdrojem pro samotný C++ standard.
Naproti tomu pojem „konkrétní“ vnímám jako jednoúčelové, omezené, úzké řešení jednoho problému. Z knihoven lze vybrat například libxml. Knihovna v podstatě umí pracovat jen s xml dokumentem. Umí ho číst a zapisovat několika způsoby, ale nic dalšího neumí.
Pokud se bavíme o vlastním, autorském kódu, nebo také takovém kódu, jenž je částí nějakého konkrétního řešení, situace se značně komplikuje. Dejme tomu, že tvoříme nějakou webovou aplikaci, například jednoduché CMS. Prostě takový ten primitivní blogovací systém s přihlášením a on-line editací textů. Samotné řešení vlastně nic moc extra neumí. Než programátor začne takový kód psát, musí se rozhodnout pro jeden z předchozích přístupů. Samozřejmě bereme v potaz situaci, že kód píše od začátku na zelené louce, ať už k tomu má důvody, jaké chce.
Může napsat řešení, které bude mít pravděpodobně rychle, asi na něj nebude moc hrdý, ale bude to funkční a bude to vlastně dělat jen to, co bylo na počátku požadováno. Díky tomu to bude velmi rychlé, ale také velmi obtížně rozšiřitelné a každá další funkcionalita bude velmi pracná. V kódu toho bude pramálo co bude možné v budoucnu použít, což může, ale také vůbec nemusí být problém.
Také může napsat řešení rozvážně, pomaleji a z hlediska moderního přístupu více akademicky. Kód pořád bude dělat to, co bylo původně v plánu, nicméně bude snadno rozšiřitelný a další funkcionalita bude doplněná daleko snadněji a tedy i levněji. Na druhou stranu k takové situaci vůbec nemusí dojít a kód je tak zbytečně složitý, protože počítá se situacemi, které nikdy nenastanou.
Podle mého skromného názoru, není ani jeden tento extrémní přístup správný. Je hezké dělat věci akademicky, čistě, správně, čitelně a komplexně. Snadno upravitelné, rozšiřitelné a obecně dobře spravovatelné. Ale tento extrémní přístup sebou nese často zbytečnou časovou náročnost, i náročnost na systémové prostředky, prostě neefektivitu. Před samotnou prací, by se tedy měl programátor zamyslet o budoucnosti projektu. Byť pravda, ve světě IT víc než kde jinde platí, že co platí dnes, zítra platit nemusí. Lze ale odhadnout směr, kterým se bude projekt ubírat.
Osobně jsem si vyzkoušel oba přístupy a cítím, že pravda je někde uprostřed. Skoro by se dalo říci, že známé pravidlo 80 na 20 se dá uplatit i zde.
Podle statistických dat, odhadů a pouček je za 20% času na projektu hotovo 80%. Zbývajících 80% času se pak ladí těch chybějících 20%. Z vlastní zkušenosti musím těmto poučkám dát za pravdu. Nevím zda je to přesně těch 80 na 20, ale na těch číslech na konec nesejde. S tvorbou takového univerzální kódu je to ale podobné. Základních 20% kódu pojme 80% všech případů a i případů které, jsou nejběžnější. Zbývajících 80% je pak dopsáno jen pro těch dalších 20% méně běžných, často velmi ojedinělých případů.
Někdy mám dokonce pocit, že tu občas panuje přímá exponenciální úměra. Mějme nějaký univerzální kód, knihovnu, která například umí vizualizovat tabulky. Nad těmito tabulky umí pracovat s filtry, stránkováním a dalšími databázově statickými maličkostmi. Čím univerzálnější ale knihovna je, tím více se musí obcházet a hackovat, pokud ji chceme použít na nějakou nestandardní situaci, pokud možno univerzálním způsobem. Jako příklad mohu uvést nějakou komplikovanou SQL podmínku závislou na subselectu a dalších podmínkách. Tuto specialitu lze vyřešit tak, že se prostě napíše extra, odděleně od této knihovny, nebo lze použít knihovnu jak jen to jde, a kvůli specialitám se obchází všechny standardní cesty v knihovně.
Samozřejmě lze namítnout, že takováto knihovna lze napsat tak, aby k něčemu takovému nedocházelo. Z praxe je ale zřejmé, že čím složitější je problém, tím hůře se pak píše komplexní, rozumějte univerzální řešení. V extrémních situacích, jako je třeba porozumění OSM dat, jenž jsou definovány neuvěřitelně širokou škálou značek a téměř neomezeným množstvím lidských chyb v použití těchto značek, dochází také k téměř nekonečnému pokrytí všech možných situací.
Taková práce nad těmito OSM daty by se dala přirovnat k fulltextovému hledání, jenž nachází řešení v umělé inteligenci. OSM data jsou uzavřená v deterministickém prostředí a je dobře zřejmé, jak mají být interpretována. Ovšem jejich nekonečně chybný způsob zápisu, může vést k nekonečnému množství automatických oprav, pokud chceme správně interpretovat i chybně, nebo neúplně zapsaná data.
Dříve zmiňovaná zlatá střední cesta se mi celkem osvědčila. A používám jí již docela dlouho a zatím mě nezklamala. Kód který píši, píši s rozmyslem tak, aby v případě potřeby šel rozšířit. Někdy to neklapne a je třeba ho přepsat víc, než bych chtěl. Jindy to klapne perfektně a jen si libuji, jak jsem na to dřív myslel. V konečném důsledku je kód celkem specifický, a zvláštnosti jsou prostě řešeny zvlášť. Snažím se dodržovat rozhraní, ale pokud by to znamenalo investovat dalších 400% původního času jen kvůli něčemu, co použiji velmi omezeně, dost možná jen jednou, prostě to udělám specificky – nestandardně. Konec konců, nestandardní situace si vyžadují nestandardní řešení.
Získám tím nejen čas, na momentální práci, ale i čas na rozmyšlenou, pokud bych přeci jen chtěl udělat nějaké univerzálnější řešení. To můžu nakonec udělat až bude takových případů víc, než jen jeden. Navíc je kód méně složitější a tedy rychlejší a přehlednější. Ano, krásný akademický přístup řeší opravu několik chyb na jednom místě. Ale na tom samém jednom místě se dá vytvořit hned několik chyb. Extrémismus škodí vždy, ať už je na jakékoli straně.
© 2024 Ondřej Tůma McBig. Ondřej Tůma | Based on: Morias | Twitter: mcbig_cz | RSS: články, twitter