Sunday, 21 August 2005
Bázová třída pro business objekty - návrhový vzor Layer Supertype
Na konci spotu, v němž byla vytvořena třída DataCacheHelper, jsem slíbil, že ukážu, jak si vynutit použití objektu DataCacheHelper všemi třídami v business vrstvě. K tomu nám poslouží vzor Layer SuperType, jehož definice se dá parafrázovat takto: zaveďme společného předka pro všechny třídy jedné vrstvy aplikace, v němž zapoudříme společný kód a sdílené chování.
Nyní si popíšeme rozhraní a implementaci vzorového předka pro business objekty. Zobrazit kód. (C#)
Abstraktní třída BusinessObjectBase obsahuje dva konstruktory. Bezparameterický konstruktor je potomky vyvoláván při zakládání nové instance bez obrazu v databázi ("bez platného - perzistentního id). V tomto konstruktoru nastavíme, že objekt není změněn vůči datům v databázi (m_isDirty = false), přidělíme mu dočasné id uložené v konstantě NO_ID a voláním privátních metod setNew a setLoaded označíme objekt jako "nový - bez obrazu v databázi" a současně "není třeba nahrávat data z databáze". U každého nového objektu se také předpokládá, že jde o aktivní objekt - tedy o objekt, který nemá příznak smazán (Discarded) ani neaktivní (InActive) - viz enumerace ObjectState na konci výpisu.
Druhý konstruktor, který přijímá argument id, používají odvozené objekty, jestliže již byly dříve uloženy do databáze. Opět nastavíme příznak, že objekt není změněn vůči datům v databázi (m_isDirty), dále nastavíme proměnnou m_isLoaded na false, což je příznak, který signalizuje, že data objektu ještě nebyl nahrána z databáze, a uložíme si id objektu.
Veřejná vlastnost IsDirty vrátí true, jestliže byl objekt změněn vůči datům v databázi, vlastnost IsNew vrátí true, jestliže se jedná o nový objekt bez perzistence - čeká na "Insert".
Vlastnost IsDeleted má hodnotu true, když již byla data objektu v databázi smazána příkazem Delete (objekt jen "dožívá" v business vrstvě) nebo když u objektů, jejichž data se například kvůli zachování referenční integrity fyzicky nemažou, byl do databáze zapsán stav Discarded.
Vlastnost Id vrací unikátní identifikátor objektu, jestliže byl objekt uložen do databáze, jinak vrací konstantu NO_VALUE.
Vlastnost ObjectState vrací stav objektu s využitím hodnot enumerace ObjectState (aktivní objekt, dočasně neaktivní objekt, smazaný objekt).
Metoda Load je pro nás zajímavá hlavně tím, že si vynutíme použití třídy DataCacheHelper. Jedná se metodu se šablonou (vzor Template method), která nejprve zkontroluje, jestli jde o objekt, který již byl nahrán a/nebo který byl již smazán - pokud je jedna z těchto podmínek pravdivá, metoda Load ihned ukončí svoji činnost. Když jsou všechny předběžné podmínky pro vyvolání metody Load splněny, metoda se pokusí vyzvednout dříve uložený řádek s daty pro svou instanci z třídy DataCacheHelper. Jestliže řádek existuje, pak je vyvolána varianta metody DoInternaLoad přijímající odkaz na řádek, jinak je vyvolána metoda DoInternalLoad, která musí řádek z databáze teprve získat. Metody DoInternalLoad jsou chráněné a virtuální a za jejich implementaci odpovídají odvozené třídy - třída BusinessObjectBase dbá na dodržení základní kostry algoritmu, ale implementaci jednotlivých kroků aloritmu ponechává (musí ponechat) na podtřídách, což je hlavní idea vzoru Template Method. Po úspěšném nahrání objektu je volána metoda setLoaded, která označí objekt jako nahraný (IsLoaded bude nyní vracet true).
Poznámka: V metodě Load se zatím předpokládá, že data objektu potřebujeme nahrát pouze jednou a metoda tedy neumožňuje aktualizaci dat objektu z databáze po prvním nahrání. Jak aktualizaci dat z databáze odvozeným třídám umožníme, si ukážeme v dalším pokračování.
Metoda Save neumožní uložení objektu, jestliže jde o nenahraný objekt ("není co ukládat, data nemohla být změněna"), jestliže jde o vymazaný objekt, nebo pokud objekt nebyl změněn a současně nejde o nový objekt. Metoda tedy již na úrovni předka ošetří, že nebudou zbytečně ukládány objekty, jejichž data byla nahrána, ale uživatel je nijak nezměnil. Metoda pouze volá chráněnou virtuální metodu DoInternalSave a jak asi ti chytřejší z vás tuší, jedná se o další příklad vzoru Template Method. Voláním privátní metody setClear po úspěšném uložení objektu nastavíme na false příznak "změněn" (IsDirty) a "nový objekt" (IsNew). Jestliže byl ukládán objekt, u nějž bylo vyžádáno smazání (ObjectState=ObjectState.Discarded), je nastaven příznak IsDeleted voláním chráněné metody SetDeleted na true.
Metoda Discard slouží ke zrušení objektu, přesněji řečeno k převedení objektu do stavu ObjectState.Discarded - pokud je objekt v tomto stavu a dojde k uložení objektu, metoda DoInternalSave buď záznam v databázi fyzicky vymaže (DELETE) nebo do databáze uloží stav ObjectState.Discarded (UPDATE). Metoda Discard pouze zkontroluje, zda nepracujeme nad smazaným objektem (IsDeleted=true), u nějž opakované rušení nemá smysl, a jestliže tomu tak není, nastaví objektu stav ObjectState.Discarded a označí objekt voláním metody SetDirty jako změněný.
Chráněnou statickou metodu SaveCollection používají odvozené třídy pro ukládání objektů ve svých kolekcích. (vztah agregace nebo kompozice). Výhodou je, že v odvozených třídách nemusí být stále stejný a otravný cyklus foreach, který se liší jen typem iterovaného objektu.
Metody DoInternalLoad a DoInternalSave jsme již zmiňovaly - jsou to "sloty" používané odvozenými třídami k zavedení vlastní aplikační logiky do schématu vysokoúrovňového scénáře. Bázovou implementaci metody DoInternalLoad přijímající řádek s daty objektu mohou zavolat odvozené třídy, jestliže chtějí nahrát stav objektu (ObjectState) bez zbytečné duplikace kódu - obnovení a ukládání hodnot vlastních specifických vlastností je samozřejmě plně v režii odvozených tříd. Metoda DoInternalLoad bez argumentů ani metoda DoInternalSave nejsou abstraktní, i když by abstraktní být mohly - v business vrstvě ale občas máme třídy, u nichž nemusíme (nechceme) psát perzistenci a proto mají metody v bázové třídě prázdné tělo, abychom nebyli nuceni zcela zbytečně ve více odvozených třídách poskytovat symbolické "prázdné implementace".
Metodu Init mohou odvozené třídy použít pro vlastní inicializační kód (vytváření kolekcí a přihlašování jejich událostí atd.) - příklad uvidíte v pokračování spotu.
Metoda SetDirty nastavuje příznak "změněn oproti datům v databázi" - příznak nemá význam pro objekty pro objekty bez perzistence a pro smazané objekty.
Metoda CheckEquals porovná předané objekty - jestliže se objekty nerovnají, je objekt označen jako změněný. Jak asi tušíte, metodu volají odvozené třídy v set sekci svých vlastností (CheckEquals(oldValue, newValue)) a jsou tak zbaveni nutnosti reagovat na výsledek porovnání a ukládat si vždy každá sama za sebe příznak "jsem změněn". Když uživatel zmáčkne tlačítko uložit na formuláři a my data z formuláře přeneseme do objektu, metoda CheckEquals zajistí, že objekt bude označen jako změněný jen tehdy, pokud uživatel opravdu nějaké změny na formuláři provedl (třeba vybral jinou hodnotu v listboxu). Výhody jsou zřejmé, kód na formuláři je stále týž - pouze "tupě" přenáší data ze vstupních prvků formuláře do vlastností business objektu a ten si již potutelně a sám na úrovni předka ošetří, zda nově předané hodnoty vyžadují uložení, nebo ne, což může nastat, když uživatel z pouhého rozmaru klikne na tlačítko uložit a přitom si detail objektu celou dobu jen prohlíží.
Metoda TriggerLoad iniciuje nahrání objektu, jestliže objekt ještě nebyl nahrán, nejde o nový objekt a také nesmí jít o smazaný objekt. Metodu volají odvozené třídy při přístupu k jakékoli vlastnosti nebo metodě objektu (vzory Lazy Load, Ghost).
Význam dalších chráněných a privátních metod byl již myslím dostatečně osvětlen v předchozím textu při výkladu veřejného rozhrani, takže se nebudu opakovat.
Rozhraní IPersistable vyjadřuje minimální nárok, který musejí splňovat všechny objekty ukládající a obnovující svá data z/do perzistentního úložiště - výhodnou výchozí a závaznou osnovu realizace rozhraní poskytuje třída BusinessObjectBase.
Z enumarace ObjectState pro vyjádření základních stavů objektu prozatím nepoužívame stav InActive - význam ostatních stavů by již vám měl být po přečtení spotu dostatečně zřejmý.
Příště si ukážeme vzorovou implementaci třídy, která dědí z BusinessObjectBase.
Sunday, 21 August 2005 21:29:28 (Central Europe Standard Time, UTC+01:00)
.NET Framework | Návrhové vzory
Thursday, 18 August 2005
Výpadky blogu
Včera mi Vilém Málek nareportoval zákeřnou chybu v DasBlogu, která některým z vás mohla způsobit problémy při psaní komentářů a posléze i zcela znemožnit přístup na blog.
Nejdříve jsem zkusil nasadit novou verzi DasBlogu, ale tím jsem paradoxně problém jen zhoršil - v release dokumentu byla popsána asi je polovina kroků potřebných pro úspěšný upgrade, takže jsem vše ladil za pochodu a nakonec jsem musel najít chyby v stávající verzi a zkompilovat svoji vlastní verzi. Snad funkční, ale zdaleka ne dokonalou. :( Asi si nějaký blogovací engine opravdu vytvořím sám.
Podle mého testování je teď už vše v pořádku, pokud ale na nějaký problém narazíte, prosím napište mi přímo na mail reneATrenestein.net.
Viléme, ještě jednou díky!
BTW: DotNetHosting, na kterém momentálně běží moje doména, mohu zatím jen chválit. Reakce administrátora jsou okamžité, takže včera výpadek trval naštěstí jen velmi krátkou dobu. Stejně rychlé reakce na ohlášený problém, jak jsem si už stačil vyzkoušet, má DotNetHosting dokonce i o víkendu.
Thursday, 18 August 2005 09:59:55 (Central Europe Standard Time, UTC+01:00)
Ostatní
Tuesday, 16 August 2005
Řešení literární hádanky z 13.8
Nikdo z vás se nepokusil o odpověď, možná proto, že jsem nenabídl šampaňský jako u přechozí hádanky. Takže vás nebudu dál napínat, autorkou je Marina Cvetajevová, o níž a o sobě napsal kníže básníků R.M.Rilke v elegii pro Marinu tyto neskromné verše:
Vlnám jsme, Marino, mořem, hloubce jsme
Marino nebem!
Zemi jsme zemí a tisíckrát jarem, jsme skřivan,
Marino,
jenž píseň vyvřelou dál vrhá v neprůzračnost.
Tuesday, 16 August 2005 22:15:50 (Central Europe Standard Time, UTC+01:00)
Literární a jiné humanitní úlety
Interval - Návrh aplikací v jazyce UML - Diagram tříd I
"Po delší prodlevě vychází další článek o návrhu aplikací s využitím jazyka UML. Místo zbytečných omluv za dlouhou a neplánovanou odmlku snad čtenáře potěší informace, že se napříště budu věnovat i konstrukcím jazyka UML nově přidaným ve verzi 2.0. Tématem tohoto článku je vysvětlení elementárních pojmů, jejichž znalost je nezbytná při návrhu diagramu tříd. " Pokračování na Interval.cz.
Tuesday, 16 August 2005 07:39:59 (Central Europe Standard Time, UTC+01:00)
UML
Monday, 15 August 2005
Lehkovážné povzdychnutí nad ovládáním spotřební elektroniky
Stáří se může projevovat inkontinencí, což okolí díky nějakým super hygienickým vložkám, co vám dají křídla, ani nezpozoruje, ale hlavně, jak jsem dlohodobým výzkumem ve svém okolí na reprezentativním vzorku zjistil, sníženou nebo nulovou schopností ovládat běžnou spotřební elektroniku, což je diagnóza, se kterou si ani spammeři nevědí rady a na můj dotaz jich pár poslalo obratem jen nabidku na tradiční moderní všelék "Buy cialis, viagra, You will be able to penetrate deeper ". Fakt díky za osvětu, ale občas i senioři nechtějí být jen hlubinnými průzkumníky dávno propátraných a opuštěných šachet a potřebují krev napumpovat jinam. Potřeboval bych pro ně spíš syntetizovat nějaký derivát s erektivní složkou pro mozkovou kůru a s dlouhodobým účinkem. S vašimi protekčními kontakty na farmaceuticko-alchymistické koncerny to určitě bude hračka.
Dneska jsem si několikrát kontroloval vlhkost svého spodního prádla, jakožto další symptom mého předčasného stáří, protože jsem zjistil, že mám potíže s ovládáním spotřební elektroniky i já. Jen nevím, jestli je chyba na mé straně. Představuji si to nějak takhle. Senior Marketing Specialist v jedné nejmenované firmě na spotřební elektroniku, říkejme ji třeba Jessica, která se na své místo vypropracovala tvrdou prací per vaginam, se rozhodla, že konečně všem ukáže, jak její ložnicová kreativita častým pobytem na zásadních poradách sublimovala do nového koncepčního přístupu k modelovému spotřebiteli dlouhodobě probíraném pod kódovým a neredukovatelným popisem "idiot, co se bojí přemíry našich tlačítek na dálkových ovladačích a vytěžuje naše nadějné zárodečné Venuše v prodejnách spotřební elektroniky zbytečnými dotazy ("hele, jaky tlacitko mi nahraje estrádu na Nově a jaký horor na Primě, tuhle jsem se splet, chtel jsm vidět nějakou novou další originální píseň Vondráčkový o jejím novym věčně panenskym extempore na Copa Cabaně, ale místo toho mi video nahrálo nějaký horor s příšernejma vyžilejma monstrama, co vypadala jen o málo líp než moje stará, když si dá obrannej trojitej vojenskej maskovací make-up, takže jsem se dost bál, a asi až kurva po hodině mi došlo, že to Vondráčková bejt nemůže, protože pořád nevidim žádný silikonový prsa, na což jsem expert, páč už jsem prozkoumal dost natürlich přírodních dívek Blesku, a že ani ten neartikulovanej řev nevystihuje úplně přesně intonaci a frázování naší slavice, mám sluch a vkus přeci ne. Ale ještě předtím, než mi došlo, že nekoukám na estrádu, jsem se nejdřiv lek, že mojí slavici honí v nějaký nový ostřejší reality show, jako jsou ti Vyvolení a nějakej jejich velkej Bratr, ten hodně vostrej namyšlenej intelektuální hajzl Rejžek, co si pořád asi myslí, že naše všemi milovaná umělkyně je novou geneticky vylepšenou a sadističtější inkarnací otce Grebeníčka, nebo možná taky že je jenom žijícím kmotrem Mafie s vražedným pseudonymem Helena, to si asi nejni ještě v tyhle věci uplně jistej."). Dotazy kvůli své složitosti musejí být eskalovány od našich vyškolených asistenek obchodu přímo na First level support, a pak do hi-tech development centra, které se celé dny snaží řešit problém, jak může prostý člověk postmoderní éry bezchybně odlišit při volbě nahrávaného programu žádaná a skutečná normalizační monstra od monster neskutešných a falešných. Proto Jessica navrhla pro začátek experimentálně vylepšit ovládání spotřebičů a to tak, že se zredukuje počet tlačítek a většina z nich se bude chovat jinak, když je podržíme 1s, unikátně jinak, když je podržíme 2s a úplně jinak, když se jich jen tak drobounce a jemňoučce heboučce dotkneme. Jessica sice chtěla, aby tlačítka úplně jinak reagovala na slintání nad silikonovými implantáty, ale to již vývojový team nedokázal spolehlivě realizovat. Nikdo sice nepochopil, v čem je nové ovládání lepší, ale Jessica všechny uzemnila argumentem, že vymyslela včera v noci, navíc v nové a myšlenkami osvícené poloze z Kamasútry a při oduševnělém orálním spojení s VicePrezidentem, zcela originální cool slogan doprovodné kampaně podpořené nabídkou výhodné půjčky od renomované finanční společnosti Provident Financial a zabírající stoprocentně na prosťáčky. "Méně tlačítek je vždy jen s námi za stejné prachy více tlačítek"! Její kolegové slogan doprovodili frenetickým potleskem a nadšeným hýkáním, což je, jak vědí jen zasvěcenci, někteří výše postavení členové zednářské lóže a celý investigativní tým připravující Občanské Judo, nejvyšší akustická forma korporátního souhlasu při strategickém rozhodování. A challenge je challenge, co se dá dělat, z něj má jeden ze svých posledních orgasmů i stařičký předseda představenstva.
Konec vsuvky a podívejme se na výsledek extravaginální tvůrčí práce Jessiky. Dneska jsem nevěřil, když jsem si četl manuál k autoradiu Clarion. Spousta tlačítek se opravdu chová jinak, když je podržíte 1s, jinak, když je jen zmáčknete a občas pro spuštění nějaké méně použivané funkce musíte ťapat na tlačítko 2s. Kdo si tohle zapamatuje, je velmistr pro školení inovací ve spotřební elektronice a vydělá v nové době solidní peníze nezbytnými konzultacemi v domácnostech.
Kromě rádia mám špatnou zkušenost i s neergonomickým ovladačem k DVD přehrávačí Sencor nebo k videu Sony. Přijde mi jako kdyby výrobce tlačítka rozmístil podle toho, jak je náhodně vylosovalo jeho imageové oddělení z balíku všech funkcí, který dodalo technické oddělení.
Poučení na dobrou noc: Prokletím našeho věku je, že inovace musí být, i když třeba vagina Jessicy, jakožto seriový výrobek, se bez jakékoli evoluce už docela dlouhou dobu obešla.
Sunday, 14 August 2005 23:30:33 (Central Europe Standard Time, UTC+01:00)
Ostatní
Saturday, 13 August 2005
Literární hádanky - poznáte autorku veršů?
Tak zase jedna exkurze k literárním láskám. Prozradím jen, že autorka veršů je žena - cizinka s pohnutým osudem, žijící nějakou dobu v Čechách. To, že když si vzpomenu na tyto verše, je podle mé ženy spolehlivě barevný lakmusový indikátor počínající opilosti, vám asi nepomůže, alespoň ale znáte důvod, proč jsem vybral právě je. Do všech koutů rozlezlý stesk, touha po ztraceném a přitom nikdy nehledaném, jen tušené ozvěny Kazatelovy marnosti, uhrančivé zaříkání života, hravá rozmarnost ... že se člověku ani nechce z tohoto rozpoložení střízlivět.;)
Pořád se někdo ztrácí: byl tu zatím -
dál je svět bez něho
Jednoho dne se i já takhle ztratím
z povrchu zemského
Co rve se, ve víru se točí,
zapadne v nepaměť.
I něžný hlas, i mé zelené očí,
i vlasy mé jak měď.
A svět potrvá dál, s vezdejším chlebem
a ve své jistotě.
Jako bych nikdy, pod nižádným nebem
nebyla v životě.
Já, rozmarná jak dítě - hned se hněvá,
hned radost má, i strach,
já, milující čas, kdy v krbu z dřeva
se stává žhavý prach,
violoncello, keře jako hříva,
a zvony nad hlavou...
Já, která patřím, skutečná a živá,
na zemi laskavou.
Od vás všech (proč, když v ničem neznám míru,
si mám klást otázku,
kdo cizí je, kdo můj) chci vaši víru.
A prosím o lásku.
Za moji pravdu ano-ne; ať říct vám
ji smím. Dny, nocemi
mě za to milujte, že smutná bývám
a dvacet let je mi.
za činy jak voda bez břehů -,
bláznivý ptačí vzlet,
za pravdu, za hru, za bezuzdnou něhu
a příliš hrdý vzhled.
za to, že urážky (s čím chcete přijďte)
pohřbívám do země ...
Poslyšte! - I za to, že umřu, viďte,
už milujete mě.
Friday, 12 August 2005 23:40:09 (Central Europe Standard Time, UTC+01:00)
Literární a jiné humanitní úlety
Wednesday, 10 August 2005
Několik informací nejen k blogu
Sešlo se mi pár různorodých informací, které nevydají na celý spot, ale připadají mi důležité nebo zajímavé, takže je všechny spojím alespoň do tohoto "pel mel spotu".
Nejprve k blogu.
- Komu chybí měsíční archiv spotů podobný tomu, co byl v .TEXTu, už nemusí truchlit. V pravém navigačním sloupci naleznete měsíční archiv.
- Jak jste si asi již všimli, kvůli novodobému moru jménem komentářový spam jsem zapnul u komentářů povinné zadání číselného kódu z obrázku.
- Pár z vás si stěžuje na malé okno pro psaní komentářů. Vězte že na odstranění problému se usilovně pracuje ;). Přesněji řečeno, postupně změním celý layout blogu, ten současný mi ani po úpravách nevyhovuje.
- Pokud mi chcete sdělit něco důležitého nebo zajímavého, tak kontakty na mě naleznete nově v pravém navigačním sloupci.
Jestliže mi někdo z vás v poslední době napsal a nedostal odpověď, není to proto, že bych na odpovědi kašlal, ale někdy v té záplavě spamů i běžné korespondence mohu na nějaký důležitý mail zapomenout. Nestyďte se a napište mi znovu.
Chci ale zdůraznit, že v žádném případě už ode mě neobdržíte odpovědi na maily s technickými dotazy zaslané na moje soukromé emailové adresy. Hlavně poté, co jsem zredukoval počet svých příspěvků v odborných konferencích, začaly na moje adresy chodit maily, jejichž pisatelé ode mě chtěli rady z různých oblastí - od psaní severových ovládacích prvků přes webové služby k flashování MDA. Snažil jsem se na dotazy odpovědět a vždy jsem na konec mailu doplnil upozornění, že žádnou další radu takto přímo neposkytnu a žádal jsem každého, aby psal dále jen do konferencí, kde si jeho příspěvku může všimnout více lidí, kteří znají odpověď. Počet mailů ale stále rostl, a proto jsem se je rozhodl ignororovat, protože neznám žádný jiný účinný způsob, jak tazatele odradit. Snad moje rozhodnutí pochopíte, nejsem žádná soukromá poradna, ani nemíním suplovat support jiných firem.
Pobavilo mě, že pár nespokojených individuí mi napsalo, jak si dovoluji neodpovídat na jejich dotazy, když jsem za to placen Microsoftem. Zamyslel jsem se nad sebou, zastyděl za svou roztržitost, kvůli níž jsem zapomněl, že jsem na čestném místě výplatní listiny Microsoftu, a jal jsem se kontrolovat své konto, abych zjistil, kolik jsem si za posledni dobu nahrabal bez práce. Začal jsem také radostně uvažovat nad tím, do jakých nových akcií ten z modrého nebe spadlý balík nacpu. Avšak ani po podrobné prohlídce všech pohybů na účtu jsem nenašel žádnou příchozí platbu od Microsoftu, takže mi ruměnec z tváře zmizel a stud vystřídala nasranost, že si mi někdy dovoluje diktovat na základě svých stupidních a nepodložených domněnek, co pro něj musím udělat. Někteří lidé jsou opravdu zvláštní tvorové a podle mé skromné a ještě neverifikované hypotézy je Bůh stvořil proto, aby zkoušel naši laskavost k bližnímu, kultivovanost v chování a sebeovládání, a tedy nám pomohl dotahovat k dokonalosti vlastnosti, jež nám zabraňují řešit konflikty nadávkami či inzultací dotyčného a činí tak náš svět alespoň občas "nejlepším ze všech možných světů".
A pro nepřispívám už tak často do konferencí, jake se mnozí ptali?
- Hlavním důvodem je čas, respektive jeho nedostatek. Více k tomuhle bodu asi nemá cenu dodávat.
- Jak jsem už psal asi před rokem a půl v jednom příspěvku, myslím si, že EMWAC, jakožto konference, která pravděpdobně sdružuje nejvíce .Net vývojářů v Čechách, přestává plnit svůj účel. Proč? Když jsem se do ní přihlásil, bylo v ní tak 200 lidí a konferencí prošlo za den jen pár příspěvků. V současné době je přihlášeno přibližně 800 lidí, počet příspěvků za den silně kolísá, ale často je jich určitě několik desitek, což už je počet, při němž se více projevují chronické problémy konference.
- Nedostatečné technické a personální zázemí - viz třeba věčné, otravné a nikdy neřešené stížnosti kvůli Reply-To hlavičce.
- Absence FAQ dokumentu - začátečnící jsou v každé konferenci vítáni, ale vždy je lepší, když jsou dotazy, které se už objevily x-krát, zodpovězeny v samostatném a na konferenci nezávislém dokumentu, než když se odpověď napíše nově příchozím pokaždé znova a znova přímo do konference.
- Neexistence moderátorů - každá veřejná konference by měla mít moderátory, kteří dbají na dodržování zakladní netiquette, kontrolují formát příspěvků, a upozorňují (nejen) nováčky na prohřešky. Kořením každé konference jsou OT příspěvky, jenže na Emwacu bylo dny, kdy OT příspěvků byla většina. I to je práce pro moderátory. Já jsem ten poslední, kdo by nad sebou chtěl nějaké dráby, ale taktní a trpělivý moderátor může úroveň konference jen pozvednout.
- Konference by měla být rozdělena minimálně na dvě další - jedna konference by byla pro začátečnické dotazy a druhá pro pokročilé dotazy. Není příjemné se prohrabovat nediferencovanými maily, kdy v jednom mailu pisatel řeší záludnosti webových služeb a WSDL specifikace, a hned v následujícím mailu se někdo jiný potýká se základní syntaxí jazyka C#. Řešení obou dotazů je bezesporu pro oba tazatele stejně důležité, ale myslím, že jejich příspěvky nepatří do jedné konference.
- Bod, který vyplývá z předchozích bodů. Konference je nepřehledná a je v ní spousta duplicitních dotazů i odpovědí.
Update: Reakce Romana Pichlíka
Tuesday, 09 August 2005 23:22:23 (Central Europe Standard Time, UTC+01:00)
Ostatní
Sunday, 07 August 2005
Cachování řádků z databáze pro business objekty - třída DataCacheHelper
Při psaní business vrstvy libovolné aplikace jste jistě narazili na následující problém, který můžeme demonstrovat na profláknutém příkladu s objednávkami a jejich položkami. Pod položkou rozumíme instanci třídy, ve které jsou uloženy informace o vybraném produktu, počtu objednaných kusů produktu a celkové ceně. Objednávka a položka objednávky jsou třídy, které jste už určitě psali tolikrát, že nemáte rádi ani jejich názvy ;)
Každá objednávka má 0..n položek a vyžádáme-li si konkrétní položku z kolekce všech položek (Items) u objednávky, která již byla uložena do databáze, musí dojít nejprve k nahrání kolekce. Je jedno, zda položky nahráváte ihned privátní metodou nazvanou třeba loadItems volanou z konstruktoru třídy Objednávka, nebo zda (a lépe) používáte zpožděné nahrávání, kdy kolekce Items je naplněna stejnou metodou teprve po prvním přístupu a konstruktory všech business objektů pouze uloží předané unikátní identifikátory (Id) a naplní své vlastnosti uloženými daty (kromě kolekcí) až po prvním přístupu k nějaké vlastnosti (kombinace vzorů Lazy Load a Ghost). Na přístupu k plnění dat objektů nezáleží, jen vždy musíte garantovat, že uživatel objektu musí přistupovat k datům objektu, aniž by si byl vědom provedených výkonnostních optimalizací - interní impementace je i zde nedotknutelné privatissimum objektu.
Jak zjistíte v metodě loadItems, jaké položky objednávka (třída Order obsahuje? Přes datovou vrstvu spustíte dotaz, která vrátí všechny záznamy s daty pro všechny položky objednávky - parametrem dotazu je samozřejmě Id objednávky. Kruciálním problémem je ale vytvoření položek objednávky (třída OrderItem) z vrácených záznamů. Jaké máme možnosti?
- Vytvoříme novou instanci OrderItem a předáme jí do konstruktoru její Id. Výhodou je, že třída Order není s třídou OrderItem nijak svázána a pouze jí předává její identifikátor. Velkou nevýhodou ale je to, že object OrderItem při obnovování svých dat z databáze bude znovu posílat dotaz do databáze "dej mi data pro mé Id", což nebude nijak efektivní přístup zvláště, když v objednávce budou desítky nebo stovky položek a každá z nich s opulentní rozhazovačností pošle svůj dotaz do databáze. Navíc je to zcela zbytečné, protože data již byla vyzvednuta v metodě loadItems, ale "jen" nebyly objektu OrderItem předána.
- V metodě loadItems přečteme záznamy položek objednávky, vyzvedneme data ze všech sloupců a pro každou položku vyvoláme konstruktor, který akceptuje všechny vlastnosti položky. Tedy kromě Id předáme i celkovou cenu, počet kusů atd. Sice jsme se již zbavili opakovaného dotazování do databáze položkami objednávky, ale objevily se další zásadní nevýhody. Třída objednávka je zatížena zbytečnou znalostí rozhraní (konstruktoru) třídy OrderItem a při změně třídy OrderItem, jakými jsou přidání nebo odebrání vlastnosti, budeme muset provést i změny ve třídě Order. Při tomto řešení jsme se právě vydali na strastiplnou a rozháranou životní cestu, nazývanou moderními mudrci ze softwarových pousteven ve svých písemných testamentech "Maintenance Nightmare". Stejný problém budeme mít při plnění vlastností OrderItem, navíc bychom u každé vlastnosti museli mít i set přístupovou metodu, z čehož by se měl všem autokritickým vývojářům obracet žaludek.
- Třídě OrderItem přidáme konstruktor, který přijímá záznam z databáze - v případě .Net Frameworku tedy objekt DataRow. Tohle řešení sejme povinnost nést břemeno znalosti rozhraní třídy OrderItem z třídy Order, ale zanechá nás s třídami, jejichž veřejné (nebo minimálně "internal") rozhraní je zapráskáno objekty z nižších vrstev. Proč by třída měla ukazovat, že je závislá na objektech DataRow, jejichž hlavní doménou je databázová vrstva? Perzistence je u business objektů nutné zlo, ne alfou a omegou a hlavním důvodem jejich existence. Bohužel, i v mnoha složitých projektech jsou stále k vidění jen truchlivé krabičky s daty z databáze a metodami Load a Save doplněné o honosnou etiketu "business vrstva" od nějakého rekvalifikovaného outsidera s kriplovsky laděným elánem Horsta Fuchse, co se v pomatení smyslů rozhodl pomoci saturovat deficit pracovních sil na trhu s vývojáři.
Než přejdu ke cachování dat, jen drobná poznámka, abych předešel dotazům. Metoda loadItems může poslat dotaz, který vrátí jen id položek objednávky, takže se data na klienta netahají dvakrát a můj problém pak působí jen jako vykonstruovaná obsese. I v tomte případě se ale místo jednoho dotazu budete potýkat s desítkami dotazů, které vyzvedávají - většinou zcela zbytečně - data jen pro jednu instanci OrderItem. Jestliže mám k tomu příležitost, je lepší vyzvednou všechna data pro všechny objekty najednou jedním "úsporným" dotazem a přitom dovolit v případě potřeby objektu přímé obnovení dat z databáze svým separátním dotazem.
Když tedy není pro nás přijatelný konstruktor s objektem DataRow, musíme při vytváření objektu "OrderItem" sdělit, odkud může načíst svá data. Jinými slovy, objekt OrderItem musí vědět, kam mu třída Order "schovala" objekt DataRow. Proč bychom ale neefektivně každému objektu extra sdělovali, odkud může načíst svá data? Zavedeme raději jeden centrální objekt - cache na příchozí data z databáze. Pak stačí objektu OrderItem předávat jen Id jako v první variantě a přitom využívat všech výhod cachování dat.
Co od takové datové cache požadovat?
- Třída musí být globálně viditelná pro všechny objekty. Půjde tedy o Singleton, respektive pro webové aplikace bude vhodné použít PseudoSingleton (Thread Specific Storage).
- Rozhraní, které se nemění s přidáváním dalších business tříd a které mohou používat jednotným způsobem všechny objekty. Takže chceme univerzální metody pro ukládání i vyzvedávání dat jakéhokoli objektu, ne nějaké stále bobtnající rozhraní s metodami StoreOrdeItem, StoreOrder, StoreXX, StoreXY, ... .
Zde je jednoduchá implementace třídy, která zatím splňuje naše nároky. Zobrazit kód
Myslím, že kód je sám o sobě dostatečně vypovídající, takže jen stručný komentář. Statický atribut Instance vrátí pro každý thread specifickou instanci třídy, která se pro jeden thread chová jako běžný Singleton. Metoda CloseInstance odstraní instanci třídy pro daný thread a tuto metodu je vhodné volat ve webové aplikaci na konci každého požadavku v obsluze události EndRequest v souboru global.asax. Metoda StoreData uschová předaný datový řádek (argument row) pro objekt daného typu (argument type) - metoda předpokládá, že řádek obsahuje sloupec Id, který je jednoznačným identifikátorem každého business objektu. Metoda GetData vrátí dříve uložený řádek pro typ v argumentu type a pro objekt, jehož id bylo předáno v argumentu businessObjectId. Po vrácení dat je uložený řádek odstraněn, aby nebyly vlastnosti business objektu permanentně obnovovány z dříve uložených a již neaktuálních dat.
Přístě si ukážeme, jak si u business objektů vynutit používání třídy DataCacheHelper bez duplikace kódu a rizika, že zapomenete v nově přidané třídě řádky z instance DataCacheHelper vyzvedávat, a také postupně z DataCacheHelperu vydělíme různé aspekty jeho chování, abychom umožnili rekonfiguraci DataCacheHelperu za běhu aplikace a adekvátně vyladili jeho činnost pro různé typy aplikací.
Sunday, 07 August 2005 19:26:34 (Central Europe Standard Time, UTC+01:00)
.NET Framework | Návrhové vzory
Monday, 01 August 2005
Drobné postřehy k navigačním programům Pocket Kim, SmartMaps a Dynavix
Jednou ze silných motivací, proč si vůbec udělat řidičák, byla i moje nezřízená chuť "geeka" otestovat už konečně a hlavně pořádně GPS navigaci.
Chvíli jsem pokukoval po nějakém vychytaném přístroji od firmy Garmin, ale cena mě odradila. Nejsem obchodní zástupce ani jiný podobný týpek, který projíždí republiku křížem a krážem, a ani sofistikované argumenty, pocházející z líhně falešných racionalizací mého horšího já, mě nepřesvědčily, abych investoval skoro 30 000 do jednoúčelového přístroje.1 Místo Garmina jsem zakoupil bluetooth GPS Holux 230 a program Pocket Kim v navigačním balíčku 'NaviPack' od firmy Sunnysoft. Součástí 'NaviPacku' je i výborný držák Dicota Keeper pro PDA, který jsem uchytil na přední sklo auta a zatím na něm drží jako přibitý. K PDA dostanete také USB kabel, kterým můžete dobíjet PDA přímo z notebooku nebo USB konektor zasunete do nabíječky na 220V či do cigaretové nabíječky v autě. Chytré a univerzální řešení. Stolní nabíječka i cigaretová nabíječka k PDA i GPS jsou také součástí NaviPacku.
Pocket Kima jsem vzal, protože v lednu aplikace SmartMaps i Dynavix na své entré do světa navigace teprve čekaly.
K samotné navigaci:
Pocket Kim
Testoval jsem hlavně verzi 2.9, protože ve verzi 3.0 uvedené v květnu se na MDAII drasticky zpomalí odezvy aplikace po spuštění GPS. Proto je (nejen) pro mě verze 3.0 zcela nepoužitelná.
V lednu se jednalo o aplikaci, která měla ze všech dostupných programů asi nejlepší mapové pokrytí Čech. Ve srovnání s programy cizí provenience (Navigon, TomTom Navigator) byl po stránce vzhledu i ovládání už tenkrát Pocket Kim špinavým káčátkem, z něhož se ve verzi 3.0 vyklubala neskutečně odpudivá a demencí postižená labuť. Nepřeháním. S žádnou verzí není radno manipulovat v autě, když jste na místě řidiče, ale ve verzi 3.0 je utrpením i volba trasy v pohodlném křesle doma, protože se neustále musíte přes stále stejně nepříjemné a neintuitivní "dotykové prstové" menu proklikávat k navigačním bodům.
Aby Pocket Kim ve verzi 2.9 komunikoval s BT GPSkou, musel jsem nainstalovat Pocket Bluetooth Tools.
Problémem Pocket Kima je poměrně malá databáze míst, do kterých vás dokáže přímo navigovat. Jinak řečeno, třeba v Praze nemůžete navigovat z ulice do ulice, ale musíte vždy najít nejbližší navigační bod, který ale také může být za sedmero horami o tři bloky dále. Částečně se to dá obejít přes zadání vlastního bodu do mapy, ale k němu jste navigováni podobně jako při jízdě ve hrách GTA nebo Mafie = řídíte se jen hrubě podle směru šipky v mapě;). K tomu nepotřebuji satelitní navigaci.
Největším nedostatkem Pocket Kima je ale úplná absence hlasové navigace. Místo toho na vás před každou křižovatkou, kde máte odbočovat, začne Pocket Kim nesměle pípat. To znamená, že se musíte kouknout na displej PDA a zabočit podle toho, co vidíte na displeji. V Praze si neustálé koukání na displej nedovedu představit, takže podle mě se podle pípání opravdu jezdit nedá. A když na displej PDA dopadá sluneční světlo, tak toho také moc neuvidíte.
Testovací jízda s Pocket Kimem
Vybrali jsme cestu z Benešova do Průhonic u Prahy přes Týnec nad Sázavou (tedy ne po dálnici). Jestliže Pocket Kima sleduje spolujezdec, dá se podle něj jet. Pocket Kim selhal pouze jednou, když jsem na jednom odlehlejším místě trval na tom, aby Petra odbočila doleva, aniž bych vzhlédl od displeje:). Když se mě zeptala už potřetí, jestli to myslím vážně, že má zatočit doleva a dodala "do toho zákazu vjezdu" došlo mi, že Pocket Kim se nás snaží navést na nějakou užitkovou cestu, která evidentně nikam nepokračuje, protože na jejím konci je stodola. Takže poučení: kromě displeje je dobré stále sledovat reálné okolí a dopravní značky.
Ve dvou se tedy sice s Pocket Kimem jakžtakž jezdit dá, ale stejně musíte neustále kontrolovat, jestli vás náhodou mapové podklady nevedou někam do pole nebo do zdi. Bez hlasové navigace je Pocket Kim nepoužitelný ve větších městech, kde je hustá doprava, protože při koukání na displej nestíháte sledovat okolí. Abych ale Pocket Kima jen nehaněl - jeho vektorové mapové podklady zabírají pouhých 8 MB (ve verzi 3.0 o něco více) a Pocket Kim také nabízí 140 (ve verzi 3.0 220) měst do úrovně ulic.
SmartMaps
Společnost Aponia uvolnila nedávno čtrnáctidenní demo verzi svých map ve verzi Navigator. SmartMaps jsou bitmapové mapy, takže demo zabírá na paměťové kartě, bez které se neobejdete, úctyhodných 212 MB. Velikost je ale dána podrobností map a jejich podobností s tištěnými mapami. Doporučuji si demo stáhnout, i když nechcete použivat navigaci, a pokochat se mapami, abyste věděli, o čem mluvím. Na ovládání verze Navigator jsem si rychle zvykl, komunikace s BT GPS byla bezproblémová. Předností SmartMaps je také rozsáhlá a stále se rozšiřující databáze zájmových bodů - stačí si jen vybrat, k jakému zámku nebo hradu vás mají dnes SmartMaps dovést, a na cestě si třeba nechat vyhledat nejbližší benzínovou pumpu po rozsvícení "hladového oka" nádrže. SmartMaps mají jen 13 krajských měst do úrovně ulic.
SmartMaps mají hlasovou navigaci a můžete si vybrat, zda chcete být instruováni mužským nebo ženským hlasem. My jsme měli většinu času zapnutý mužský hlas, protože Petra po chvíli navigování ženským hlasem, který jsem původně preferoval já, rezolutně prohlásila, že už tu hysterku poslouchat nebude. Hlasy, a to ani ten mužský, opravdu nepůsobí příliš profesionálně, ale na navigaci stačí. Máte také možnost volit mezi plnou a zjednodušenou navigací - myslím, že jinou než zjednodušenou nevydrží nikdo používat, protože když se v rozšířené navigaci během pěti minut desetkrát dozvíte, že máte pokračovat rovně a po jaké silnici jedete, tak začnete být asi stejně jako já mírně podráždění. Zjednodušená navigace hlásí jen důležité odbočky. Instrukce jsou typu "Za 250 metrů odbočte doprava".
SmartMaps jsme otestovali na stejné trase jako Pocket Kima. Do Průhonic jsme dorazili bez sebemenších problémů, jen při zpáteční cestě SmartMaps v Čestlicích nenahlásily, abychom pokračovali po vedlejší silnici a nechaly nás jet po hlavní (buď šlo o nepříliš dávno provedenou změnu značení hlavní a vedlejší silnice, nebo o chybu v navigačních podkladech). Během chvíle a po našem ignorování povelu k otočení SmartMaps přepočítaly trasu a dovedly nás zpět do Benešova.
SmartMaps nejsou špatné, ale stále se neobejdete bez koukání do mapy. Projeli jsme i jiné trasy a hlavně na více křižovatkách umístěných blízko za sebou je hlasová navigace poněkud chaotická. SmartMaps jsou ale výborným kompromisem mezi užitnou hodnotou a cenou.
Dynavix
A dostáváme se k nekorunovanému králi navigace po Čechách, i když jsem měl možnost vyzkoušet Dynavix jen pouhé 2 hodiny, protože Telematix (ke své vlastní škodě) demo verzi nenabízí, ale naštěstí mi Dynavixe zapůjčil můj kolega z práce Michal. Ovládání Dynavixu není špatné, i když zahraniční programy, o kterých jsem psal výše, mají stále ovládání lepší a "vychytanější". To ale nevadí - (budoucí) úspěch Dynavixu stojí na nejkvalitnějších mapových podkladech pro ČR a na úžasné hlasové navigací. Přesnost mapových podkladů je opravdu špičková, což se projevuje i tím, že v některých městech se můžete nechat navigovat až do úrovně čísel popisných! Mimochodem, Dynavix bude brzy dodávat i podrobné mapové podklady pro Evropu.
Už jsem psal, že hlasová navigace je úžasná a mohu dodat další superlativa. Je profesionální, vůběc neobtěžuje a je neuvěřitelně přesná. Jak taková typická navigace probíhá? Jedete a Dynavix vás upozorní nevtíravou hláškou "připravte se na odbočení vlevo". Před křižovatkou se ozve přesnější instrukce "za 250 metrů odbočte vlevo". To by mi stačilo, ale hochům z Telematixu ne, a tak když vjedete do křižovatky, ozve se ještě povel "nyní doleva". Petra zhodnotila navigaci slovy: "Podle toho dokáže jet kamkoli i blbec".
Zkušební cesta vedla z Benešova do Bystřice, pak do Divišova a Ostředka a zpět. Několikrát jsem odbočili do nějakých malých vesniček, abychom Dynavix zmátli, ale ten vždy jen přepočítal trasu a dále nás navigoval ke zvolenému cíli. V jedné vesničce měl Dynavix v mapě dokonce nějakou zpevněnou polní cestu, na kterou se nás snažil navést, protože tvrdil, že vede nejrychleji do cíle. Jen zde jsem raději jako nevěřící Tomáš uhnul jinam, abych neskončil někde v bahně nebo v houfu divočáků, což jsou okolnosti, s nimiž ani Mistr Dynavix zatím nepočítá .
Dynavix obsahuje samozřejmě i nejaké nedodělky - verze 1.0 má na některých PDA problémy s BT ovladačem, často se ozývala zbytečná hláška o ztrátě satelitního signálu, i když jen poklesl počet satelitů na tři atd. Na to, že je Dynavix ve verzi 1.0, jde ale podle mě opravdu o slušně vyzrálý produkt.
Cena sice není lidová, skoro 8000 Kč, ale já jsem na 99% rozhodnutý, že si Dynavix pořídím - nic lepšího pro Čechy opravdu není. Neměl jsem ho dostat do ruky ;)
Další odkazy k Dynavixu:
Tohle bylo zatím opravdu jen pár mých zkušeností s navigačními systémy, ale po zakoupení Dynavixu se zde určitě ještě pár podobně laděných spotů objeví.
1. Malá poznámka na okraj. Garmin nyní dodává i navigaci na zařízeních s OS Windows Mobile (iQueue)
Monday, 01 August 2005 20:10:56 (Central Europe Standard Time, UTC+01:00)
Mobilitky | Navigace
Saturday, 30 July 2005
Řešení hádanky "Znáte dobře návrhové vzory"
Protože nikdo nedodal kompletní řešení k hádance z 26.7., zde je odpověď.
- Třída MessageReceiverBase - událost MessageReceived, návrhový vzor Observer.
- Třída MessageReceiverBase -metoda CreateMessage, návrhový vzor Factory Method. Metoda CreateMessage vrací přímo instancí třídy Message nebo její potomky. Potomci třídy MessageReceiverBase mohou metodu přepsat a vrátit z metody například instanci OrderMessage, aniž by byly dotčeny vysokoúrovňové scénaře pracující pouze s rozhraním Message a deklarované na úrovni MessageReceiverBase.
- Třídy MessageReceivePoint, MessageReceiverBase a její potomky můžeme považovat za participanty návrhového vzoru Bridge. Třída MessageReceivePoint je abstrakcí - logickým přístupovým bodem, který dokáže přijímat data na daném URI a který interně využívá konkrétní fyzický přístupový bod, jímž je potomek třídy MessageReceiverBase zapouzdřující detaily komunikace po zvoleném přenosovém protokolu. Metoda Listen třídy MessageReceivePoint deleguje volání na metodu Listen třídy MessageReceiverBase. Samozřejmě lze o potomcích třídy MessageReceiveBase uvaživat i jako o strategiích, jak zaznělo v diskuzi o spotu, i když si myslím, že vzor Bridge lépe vyjadřuje role tříd.
- Třída AddMesageAttributesProcessor - jak vyjadřuje její název, jedná se o realizátora vzoru Content Enricher - k přijaté zprávě dodává další informace, které nebyly přímo její součástí ale které jsou důležité pro další zpracování zprávy. Příklad - messagingový systém přijme objednávku a Content Enricher ke zprávě doplní údaje o platební morálce zákazníka.
- Třída FilterMessageAttributesProcessor - opět dle názvu můžete usuzovat, že jde o návrhový vzor Content Filter. Procesor z přijaté zprávy odstraní všechny informace, které nejsou důležité pro další zpracování a které by pouze zbytečně vytěžovaly zdroje serveru. Příklad - messagingový systém přijme obrázové přílohy, které není třeba posílat k dalšímu zpracování, ale pouze se archivují v DMS, takže nemá smysl hnát obrázky celým procesem vyřizování objednávky. Content Filter obrázky ze zprávy před jejím dalším zpracováním odstraní.
Jak někteří z vás (Petr :) ) správně vytušili, diagram také svádí k tomu, aby byl rozšířen o Intercepting filter nebo o vzor Pipes&Filters - tyto vzory v něm ale v současné podobě nalezneme poze jako latentní možnosti, které můžeme uskutečnit doplněním a úpravou vztahů mezi existujícími třídami.
Saturday, 30 July 2005 17:22:25 (Central Europe Standard Time, UTC+01:00)
Návrhové vzory | Programátorské hádanky