<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Augiho web</title>
	<atom:link href="http://www.augi.cz/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.augi.cz</link>
	<description>Osobní stránky jednoho podivného programátora...</description>
	<lastBuildDate>Wed, 28 Dec 2011 14:01:55 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Co dělat v roce 2012</title>
		<link>http://www.augi.cz/programovani/co-delat-v-roce-2012/</link>
		<comments>http://www.augi.cz/programovani/co-delat-v-roce-2012/#comments</comments>
		<pubDate>Wed, 28 Dec 2011 14:01:55 +0000</pubDate>
		<dc:creator>Augi</dc:creator>
				<category><![CDATA[Programování]]></category>

		<guid isPermaLink="false">http://www.augi.cz/?p=443</guid>
		<description><![CDATA[Díky Vyvojari.sk jsem narazil na zajímavý článek o jedenácti věcech, které by mě dělat každý vývojář v roce 2012. S tím seznamem se dá celkem souhlasit, ale dovolím si komentář a přidám dalších 5 bodů, které by měl bezpodmínečně každý vývojář dělat (na úkor původních jedenácti věcí). Založit si Twitter účet a třeba jen pasivně [...]]]></description>
			<content:encoded><![CDATA[<p>Díky <a href="http://www.vyvojari.sk//News-11-veci-ktore-by-mal-robit-vyvojar-v-roku-2012-102132.aspx">Vyvojari.sk</a> jsem narazil na zajímavý <a href="http://michaelcrump.net/11-things-every-software-developer-should-be-doing-in-2012">článek o jedenácti věcech, které by mě dělat každý vývojář v roce 2012</a>. S tím seznamem se dá celkem souhlasit, ale dovolím si komentář a přidám dalších 5 bodů, které by měl bezpodmínečně každý vývojář dělat (na úkor původních jedenácti věcí).<br />
<span id="more-443"></span></p>
<p>Založit si Twitter účet a třeba jen pasivně ho sledovat je vhodný doplněk k RSS. Velkou výhodu vidím v tom, že se k člověku (pokud sleduje ty správné lidi) dostanou i věci z blogů, které by si do RSS sám nedal. Přečíst si o tom, jak řešit třeba nějaký specifický problém v Javě může člověka někam posunout&#8230;třeba k tomu, aby si uvědomil, jak je C# super <img src='http://www.augi.cz/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Je to trošku podobný případ jako když člověk začal používat jako zdroj informací internet (tedy nějaký uzavřený okruh serverů) místo čtení novin. U novin se člověk dostane i k věcem a názorům, které mu v případě &#8222;soukromého vesmíru&#8220; unikají&#8230;</p>
<p>Dalším zajímavým bodem je &#8222;<em>Carry around a modern phone</em>&#8222;. Z mého pohledu ne kvůli tomu, abyste byli free-cool-in, ale protože denodenním používám člověk lépe pochopí, co běžného uživatele trápí a jaká by naše mobilní aplikace opravdu neměla být.</p>
<p>Jak píše jeden komentující, přidal by dvanáctý bod &#8211; &#8222;<em>Get a hobby.</em>&#8222;. Já bych bodů přidal rovnou pět, aby se člověk z toho všeho programování a spol. nezbláznil a třeba nevyhořel:</p>
<ol>
<li>Najděte si ženskou. Pokud už ženskou/rodinu máte, věnujte se jí/jim. Pokud jste rádi Singleton, tak choďte mezi lidi &#8211; a teď myslím lidi, ne programátory <img src='http://www.augi.cz/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  A když už chodíte jen mezi programátory, tak aspoň řešte něco jiného než programování. Vystupte ze své komfortní zóny!</li>
<li>Začněte dělat nějaký sport (ne šachy). Aspoň jednou týdně. Jestli máte odpor ke sportu, pusťte si oblíbenou hudbu do uší a běžte se svižným krokem na hodinku projít. Vaše tělo vám bude vděčné.</li>
<li>Najděte si nějaký (ideálně nepočítačový) koníček, který zaměstná jinou než &#8222;analytickou část mozku&#8220;. Začněte se učit nový cizí jazyk, vytáhněte zaprášený hudební nástroj, začněte kreslit, chodit na keramiku, &#8230;</li>
<li>Přečtěte alespoň dvě beletristické knihy. Ač se české školství vehementně snaží vybudovat v nás odpor k literatuře (aspoň já to tak vnímal), nedejte se.</li>
<li>Dbejte na svou životosprávu. Teď nemyslím, abyste se krmili jen salátama a podobnýma nesmyslama, ale snažte se jíst pravidelně a nenechávejte tělo zbytečně dlouho hladovět. Opět, vaše tělo vám bude vděčné.</li>
</ol>
<p>A na závěr bych si dovolil jedno heslo, které mě oslovilo a možná se v něm někteří také najdete:<br />
&#8222;<em>Dřív jsem obdivoval lidi, kteří pracují 16 hodin denně. Teď obdivuji lidi, kteří nemusí pracovat vůbec.</em>&#8220;</p>
<p>A protože se blíží konec roku, tak bych vám rád poděkoval za přízeň a popřál vše dobré do nového roku &#038; happy coding <img src='http://www.augi.cz/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.augi.cz/programovani/co-delat-v-roce-2012/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Architektura škálovatelných aplikací</title>
		<link>http://www.augi.cz/programovani/architektura-skalovatelnych-aplikaci/</link>
		<comments>http://www.augi.cz/programovani/architektura-skalovatelnych-aplikaci/#comments</comments>
		<pubDate>Sat, 17 Dec 2011 22:44:02 +0000</pubDate>
		<dc:creator>Augi</dc:creator>
				<category><![CDATA[Programování]]></category>

		<guid isPermaLink="false">http://www.augi.cz/?p=442</guid>
		<description><![CDATA[Je to už nějaký pátek, co se zajímám o vzor CQRS (Command Query Responsibility Segragation), který nachází uplatnění především u dvou typů aplikací, které ale nejsou tak časté &#8211; velmi komplexní aplikace (díky CQRS se lze lépe vypořádat s komplexitou) a velmi velké a/nebo vytížené aplikace (které potřebují škálovat). Ačkoliv se takto může zdát znalost [...]]]></description>
			<content:encoded><![CDATA[<p>Je to už nějaký pátek, co se zajímám o vzor CQRS (Command Query Responsibility Segragation), který nachází uplatnění především u dvou typů aplikací, které ale nejsou tak časté &#8211; velmi komplexní aplikace (díky CQRS se lze lépe vypořádat s komplexitou) a velmi velké a/nebo vytížené aplikace (které potřebují škálovat). Ačkoliv se takto může zdát znalost CQRS pro běžného programátora zbytečná (<em>ne každý je Google</em>), je s CQRS spjato mnoho velmi zajímavých konceptů, které mohou nalézt uplatnění i u běžných aplikací. Proto jsem se rozhodl sepsat z mého hlediska to nejzajímavější, co mě CQRS naučilo.<br />
<span id="more-442"></span><br />
Klasická představa vrstvení aplikace je takováto:</p>
<p><center><img src="http://www.augi.cz/wp-content/uploads/CQRS-01.png" alt="" /></center></p>
<p>V krabičce &#8222;Application&#8220; je skryta doménová logika i přístup k datům &#8211; odprostím se tedy prozatím od toho, jak je jádro aplikace implementované (DDD s ORM, Transaction Scripts, Active Record, &#8230;). Místo toho se zaměřme na to, jak je realizována komunikace mezi Aplikací a GUI &#8211; je to nějaká fasáda &#8211; vrstva rozhraní, které utváří API naší Aplikace, a nedělá tedy nic jiného, než že <em>tupě</em> volá Aplikaci.</p>
<p>Ve webovém GUI se striktně rozlišuje (a kdo to nedělá, je prasátko) mezi requesty, které provádí jen čtení (GET), a requesty jen měnícími stav (POST). Jak ví každý slušný webový vývojář, POST požadavek by neměl nic prezentovat (renderovat html) &#8211; měl by jen &#8222;nějak&#8220; zpracovat požadovaný příkaz a říci prohlížeči, kdo mu poskytne vizuální reprezentaci výsledku (tj. na jakou stránku má udělat redirect). Tento koncept je znám jako vzor <a href="http://zdrojak.root.cz/clanky/post-redirect-get-nejen-v-asp-net-mvc/">Post-Redirect-Get</a> a vzásadě to není nic jiného než krásná implementace <a href="http://martinfowler.com/bliki/CommandQuerySeparation.html">CQS</a> &#8211; <strong>Command Query Separation</strong>, což je koncept, který říká, že &#8222;objekt&#8220; by měl mít jen dva druhy metod:
<ul>
<li>provádí výhradně změnu a nic nevrací (tj. vrací <em>void</em> a nemají výstupní parametry)</li>
<li>nemění stav, jen čtou</li>
</ul>
<p>Převedeno do řeči CQRS, GUI (obecně zbytek světa) komunikuje s Aplikací srkzeva Commands (první typ metody) &#038; Queries (druhý typ metody):</p>
<p><center><img src="http://www.augi.cz/wp-content/uploads/CQRS-02.png" alt="" /></center><br />
Šipky ukazují směr <em>toku informace</em>.</p>
<h2>Commands</h2>
<p>Když chceme po Aplikaci něco vykonat (provést nějakou akci, která změní stav), pošleme směrem k Aplikaci tzv. Command. To je obyčejná třída bez metod, jen krabička na data (DTO), jejíž properties představují parametry příkazu, který chceme provést.</p>
<p>Commandové API Aplikace je triviální &#8211; je to jediný interface, který má jednu metodu: <em>void HandleCommand(ICommand command)</em><br />
V zájmu minimalizace requestů se často přidává druhá metoda <em>HandleCommands</em>, jejíž účel si laskavý čtenář jistě domyslí <img src='http://www.augi.cz/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /><br />
Toto univerzální rozhraní má jediný úkol (často delegovaný na kontejner) &#8211; předat Command do odpovídajícího Command Handleru, který provede jeho zpracování (ten už komunikuje přímo s Aplikací).</p>
<pre class="brush: csharp">public interface ICommandHandler&lt;TCommand&gt; where TCommand: ICommand
{
  void Handle(TCommand command);
}</pre>
<p>V čem je síla takového řešení? Protože pořád nikde nic nevracíme, nemusíme čekat na &#8222;fyzické&#8220; zpracování příkazu, tzn. GUI zobrazí obligátní hlášku &#8222;Váš požadavek <strong>bude</strong> zpracován.&#8220; a může vesele pokračovat dál.</p>
<h3>Informace o zpracování</h3>
<p>Zde vyvstává otázka, jak informovat uživatele/externí systém, že byl příkaz (ne)úspěšně zpracován (pokud ho to zajímá). Protože Command Handlery nic nevrací, musíme použít jinou komunikační cestu &#8211; v případě uživatele na e-shopu nás nepřekvapí klasické poslání mailu. Jiný způsob (pokud chceme informovat uživatele interaktivněji) je ten, že <em>ICommand</em> obsahuje property <em>Id</em> typu <em>Guid</em>, kterou může GUI nastavit a na základě tohoto identifikátoru požadavek trackovat. Konkrétní způsoby realizace jsou mimo rozsah toho článku, ale pěkným řešením je notifikace webového serveru o zpracování Commandu skrze Message Bus a následně nějaká forma (pseudo)persistentního spojení mezi webovým serverem a prohlížečem (pollování, <a href="http://en.wikipedia.org/wiki/WebSocket">WebSockets</a>, &#8230;).</p>
<h3>Benefity</h3>
<p>Přijde vám posílání Commandů zbytečně složité a nestojí podle vás za to, že máme díky němu možnost zadávat příkazy z GUI asynchronně? Souhlasím! Síla tohoto řešení je totiž v tom, že nám <strong>umožní rozložit zátěž v čase</strong> (tj. rozmělnit špičky v zátěži) a <strong>řešit výpadky aplikace</strong>. Těchto neocenitelných benefitů docílíme tím, že GUI nebude Commandy posílat přímo naší aplikaci, ale bude je jen předávat prostředníkovi (Message Bus, Command Bus, Message Queue), který je bude dále přeposílat naší aplikaci.<br />
Pokud zrovna nebude naše aplikace dostupná, tak uživatel v GUI nedostane chybovou hlášku, ale požadavek (Command) se uloží do fronty, a jakmile aplikace naskočí, prostředník to zmerčí, přepošle Command aplikaci a ta ho zpracuje. Uživatel tak dostane mail s potvrzenou objednávkou maximálně o chvilku později a není obtěžován momentálních chvilkovým výpadkem aplikace.</p>
<p>Onen prostředník (MessageBus) by pro nás měla být (podobně jako databáze) jen infrastrukturní záležitost (100% dostupná) a typicky ji nebudeme implementovat sami, ale použijeme nějaké existují řešení &#8211; v případě vlastní infrastruktury např. <a href="http://en.wikipedia.org/wiki/Microsoft_Message_Queuing">MSMQ</a> nebo <a href="http://en.wikipedia.org/wiki/RabbitMQ">RabbitMQ</a>, v případě cloudu např. Azuří <a href="http://www.windowsazure.com/en-us/home/tour/service-bus/">Service Bus</a> nebo Amazoní <a href="http://aws.amazon.com/sqs/">Simple Queue Service</a>.</p>
<h3>Kompatibilita</h3>
<p>Když se na tento způsob interakce GUI a Aplikace podíváme s odstupem, zjistíme, že to není o tolik složitější než klasický přístup. Místo každé hlavičky metody budeme mít třídu reprezentující Command a tělo metody přesuneme do metody <em>Handle</em> odpovídající Command Handleru (nic nebrání, aby jedna třída implementovala více <em>podobných</em> Command Handlerů).</p>
<pre class="brush: csharp">public OldFashionedFacade: IOldFashionedFacade
{
  public void OrderProduct(Product product, Customer customer)
  {
    // handle using Application
  }
}

public class OrderProductCommand : ICommand
{
  public Product Product { get; set; }
  public Customer Customer { get; set; }
}

public class OrderProductCommandHandler: ICommandHandler&lt;OrderProductCommand&gt;
{
  public void Handle(OrderProductCommand command)
  {
     // handle using Application
  }
}
</pre>
<p>Za povšimnutí stojí to, že parametry staré metody přejdou v properties třídy reprezentující Command. Pokud chceme mít nadále dostupné old-fashioned API (např. si nemůžeme dovolit měnit takto zásadně API), můžeme jednoduše nagenerovat toto API z Commandů. Jednoduše pro každý Command vygenerujeme jednu metodu fasádního interface, properties Commandu překlopíme na parametry této metody a metoda bude vevnitř jen volat univerzální <em>Handle</em>. Ale ani tady se nemusíme zastavit &#8211; můžeme např. nagenerovat i metody se sufixem <em>Sync</em>, které zajistí, že Command bude okamžitě zpracován místo zařazení do fronty v MessageBusu (někdy se to může hodit).</p>
<p>Jak vidno, zadávání požadavků do Aplikace přes Commandy nám přináší neuvěřitelné možnosti a v tomto řešení vidím jediný problém &#8211; je těžké rozhodnout, který kód je součástí Aplikace (a měl by tedy být uvnitř Aplikace) a který kód je jen infrastrukturní (a měl by tedy být v Command Handleru). Rozhodně do Command Handleru patří konverze typů, základní validace a autorizace. Zbytek je na vašem rozhodnutí&#8230;</p>
<h2>Queries</h2>
<p>Dotazovací část fasády Aplikace zůstane zvenku prakticky stejná &#8211; pořád se bude jednat o synchronní volání metod, protože uživatel chce vidět produkty v gridu okamžitě. Navenek to tedy mohou zůstat klidně fasádní služby, které budou volat NĚCO vespod. Pokud jste čekali, že to NĚCO bude Aplikace, musím vás zklamat. Prezentovat uživateli data, která prošla skrze Doménovou vrstvu, to bývá jeden z největších problémů nejen z hlediska výkonu (načtete celou entitu a pak zobrazíte jen příjmení) tak z hlediska čistoty kódu &#8211; pokud jste např. přidali entitě <em>Person</em> readonly property <em>DisplayName</em> jen proto, že ji potřebujete v GUI, tak si rovnou dejte facku <img src='http://www.augi.cz/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>Takže co bude to, co budou volat metody fasádních služeb (Queries) ? Nejefektivnější je sahat přímo do databáze &#8211; v případě .NET přes ADO.NET, příp. nějaký jednoduchý mapper (např. <a href="http://code.google.com/p/dapper-dot-net/">Dapper</a>). Ať se vám to může při prvním pohledu zdát jakkoliv zvrhlé, po několika měsících musím uznat, že je to dobrá cesta a nevede k masivní duplikaci kódu, jak by to mohlo na první pohled vypadat.</p>
<p><center><img src="http://www.augi.cz/wp-content/uploads/CQRS-03.png" alt="" /></center></p>
<p>Jak vidíme, de facto teď máme nad jednou persistentní vrstvou dvě aplikace &#8211; jedna se stará o zpracování Commandů a druhá o co nejrychlejší prezentaci dat uživateli (via Queries). Queries teď dělají to, že spouští (vysoce optimalizované) dotazy nad databází, které tahají jen ta data, která jsou opravdu potřeba.</p>
<p>Když budeme mít ale jen jednu databázi a aplikace zrovna bude pod velkým write-loadem (hodně Commandů), odnesou to Queries vyšší latencí &#8211; proto může být dobrý nápad rozdělit databázi na dvě:</p>
<p><center><img src="http://www.augi.cz/wp-content/uploads/CQRS-04.png" alt="" /></center></p>
<p>OpDB (<em>Operational Database</em>) je běžná databáze v 3NF+, ke které Aplikace přistupuje běžným způsobem &#8211; např. pomocí full-featured ORM &#8211; v .NET se dá za něj považovat asi jen <a href="http://nhforge.org/Default.aspx">NHibernate</a>, Entity Framework teprve bloumá okolo nádraží <img src='http://www.augi.cz/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>K <a href="http://martinfowler.com/bliki/ReportingDatabase.html">ReadDB</a> přistupují Queries co nejpříměji, např. přes nějaký zmiňovaný lightweight-ORM. Účelem této databáze je umožnit servírovat data uživateli co nejrychleji. Nejrychlejší by bylo mít pro uživatele předrenderovanou celou stránku (HTML), jen ji přečíst na jeden request z databáze (přes Query, resp. ReadApp) a přes webový server poslat do prohlížeče. To je poněkud extrémní řešení, proto se spokojme s tím, že budeme schopni na jeden request (a řekněme do desítek ms) získat všechna data potřebná pro zobrazení celé stránky, tedy &#8222;ViewModel&#8220; <em>stránky</em>. ViewModel můžeme v databázi mít uložen jako Json, XML, DTO serializované do BLOBu, jak je libo. Jediná podmínka by měla být, že jsme schopni získat všechna <strong>data na jeden jednoduchý dotaz</strong> (žádný join!).</p>
<p>Správně, ReadDB není nic jiného než <strong>předem napopulovaná cache</strong>, po které nechceme nic jiného než vytáhnout surová data na základě nějakého ID. Proto ReadDB nemusí být vůbec klasická relační databáze &#8211; může to být klidně NoSQL databáze! A naše aplikace pak bude cool! <img src='http://www.augi.cz/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<h3>Synchronizace</h3>
<p>Je nabíledni, že musíme ReadDB průběžně upravovat podle toho, jak se mění OpDB (~synchronizovat). To se typicky děje (opět) pomocí Message Busu, kdy při úpravě Doménového modelu vyvoláme událost, že došlo k nějaké změně (<em>ProductChanged</em>). Kdokoliv (tedy včetně ReadApp) má pak šanci tuto událost odchytit a poupdatovat podle ní odpovídající předpřipravené ViewModely apod.</p>
<p>Pokud ale nechceme udělat takový velký skok v používaných technologiích, není nic ztraceno. Můžeme uvažovat o dvou databázích jen z konceptuálního hlediska, fyzicky budeme mít jen jednu klasickou relační databázi. Jak už jsem psal, na úplném začátku jsme v situaci, kdy v Queries píšeme dotazy nad OpDB. Abychom dosáhli rozumného výkonu, musíme i v tomto řešení začít duplikovat data &#8211; k tomu slouží v klasických relačních databázích indexy. Takže máme databázi s indexy, klasika.</p>
<p>Prvním krokem k možnému budoucímu přesunu na více fyzických databází je to, že vytvoříme pohledy (Views). Prakticky sice budeme dělat pořád to samé, ale dotazy už budou ve své finální podobě (&#8222;<em>SELECT * FROM ViewModel1 WHERE Id = @Id</em>&#8222;) a nebudeme na ně tak muset v dalších krocích sahat.</p>
<p>Další iterací je to, že pohledy budou materializované. Pokud to náš DB stroj neumí, můžeme si je implementovat sami &#8211; jednoduše vytvoříme místo pohledů tabulky se stejnou strukturou. Pak si vytvoříme triggery nad původními tabulkami a podle zápisů do nich budeme upravovat naše <em>materializované pohledy</em>.<br />
Je zřejmé, že se nám tím zpomalí zápis, ale čtení bude bleskurychlé &#8211; takže konkrétní řešení závisí i na tom, jaký je ve vaší aplikace poměr čtení/zápis (nejčastěji to prý bývá 80 % vs. 20 %).</p>
<p>Pokud budeme chtít ReadDB a OpDB skutečně fyzicky rozdělit (a pokud neumíme zajistit spouštění triggerů přes více DB strojů), musíme synchronizaci přenést o úroveň výše. A tím se dostáváme zpět k výše zmiňované synchronizaci přes události (Events), které můžeme vyvolávat tam, kde to bude pro naši aplikaci nejvhodnější &#8211; v DALu, v Doméně nebo třeba po úspěšném zpracování Commandu&#8230;</p>
<h2>UI</h2>
<p>Jak je vidět z posledního obrázku, naše GUI teď prakticky pracuje nad dvěma aplikacemi &#8211; jedna zajišťuje načítání dat a druhá zpracování dat. Načítání dat zůstává prakticky stejné jako v případě klasické (non-CQRS) aplikace, ale rozdíly ve zpracování dat jsou markantní. Už nejsme schopni garantovat to, že po odeslání objednávky ji zákazník hned uvidí v nějakém seznamu, protože třeba příkaz ještě není zpracován nebo ještě nestačila proběhnout synchronizace ReadDB. A tomu je třeba přizpůsobit koncepci uživatelského rozhraní, příp. si více pohrát s aplikací. V části o Commandech jsem se např. zmiňoval o možnosti trackování stavu Commandu&#8230;</p>
<p>V souvislosti s CQRS se často mluví o tzv. <strong>Task-Based UI</strong>, což je alternativa k běžnému CRUD UI. Není to něco, co je v CQRS povinné, ale považuji to za zajímavý koncept, proto ho chci letmo zmínit.<br />
Klasické CRUD UI se vyznačuje tím, že umožňuje vytvořit <em>entititu</em>, upravit ji a příp. ji smazat. Problém je, že když voláme metodu <em>Change</em>, tak tím vůbec nevyjadřujeme <strong>záměr</strong>, proč tak činíme.<br />
Bylo by mnohem lepší, kdychom měli připravené Commandy, které by vyjadřovaly, že např. měníme adresu zákazníka, protože se stěhuje (a podle nové adresy mu doporučit novou výchozí prodejnu), že měníme příjmení zákazníka, protože se oženil/vdala/registroval(a), že mažeme zákazníka, protože zemřel atd.<br />
A pro tyto specifické tasky pak budeme mít specifické UI &#8211; Task-Based UI.<br />
S problematikou ukládání takových informací do databáze souvisí <a href="http://codebetter.com/gregyoung/2010/02/20/why-use-event-sourcing/">Event-Sourcing</a>, ale o tom třeba někdy jindy&#8230;</p>
<h2>Co z toho?</h2>
<p>CQRS je velmi zajímavý vzor, díky kterému jsem se dozvěděl o spoustě zajímavých konceptů, z nichž některé úspěšně používám v praxi. Ty nejzajímavější koncepty (MessageBus, ReportingDatabase) jsem se pokusil nastínit v tomto článku a věřím, že vás mohou inspirovat k dalšímu studiu CQRS a příp. i vylepšení vašich aplikací.</p>
<p>O CQRS není problém vygooglit spoustu materiálů (a možná se vás už ani Google nebude ptát &#8222;Did you mean CARS?&#8220; <img src='http://www.augi.cz/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> ) &#8211; doporučuji především materiály od <a href="http://codebetter.com/gregyoung/">Grega Younga</a>, <a href="http://www.udidahan.com/?blog=true">Udiho Dahana</a> a <a href="http://abdullin.com/journal/2010/3/23/dddd-cqrs-and-other-enterprise-development-buzz-words.html">Rinata Abdullina</a>.</p>
<p><script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js"></script><br />
	<script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js"></script></p>
<link type="text/css" rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css"/>
<link type="text/css" rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css"/>
<p>	<script type="text/javascript">
		if (SyntaxHighlighter) {
			SyntaxHighlighter.all();
		}
	</script></p>
]]></content:encoded>
			<wfw:commentRss>http://www.augi.cz/programovani/architektura-skalovatelnych-aplikaci/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>Jak jinak na widgety v ASP.NET MVC</title>
		<link>http://www.augi.cz/programovani/jak-jinak-na-widgety-v-asp-net-mvc/</link>
		<comments>http://www.augi.cz/programovani/jak-jinak-na-widgety-v-asp-net-mvc/#comments</comments>
		<pubDate>Sat, 10 Dec 2011 14:41:12 +0000</pubDate>
		<dc:creator>Augi</dc:creator>
				<category><![CDATA[Programování]]></category>

		<guid isPermaLink="false">http://www.augi.cz/?p=440</guid>
		<description><![CDATA[V předchozím článku jsem ukázal jednu možnost, jak implementovat v ASP.NET MVC (libovolné verze!) &#8222;sidebar widgety&#8220;. V tomto článku bych rád ukázal další možnosti realizace widgetů, na které nebyl v předchozím článku prostor. Ale ani tento článek není kompletním výčtem všech možností&#8230; SuperModel V předchozím řešení jsme od ViewModelu, který reprezentuje stránku s widgety, požadovali, [...]]]></description>
			<content:encoded><![CDATA[<p>V <a href="http://www.augi.cz/programovani/jak-na-widgety-v-asp-net-mvc/">předchozím článku</a> jsem ukázal jednu možnost, jak implementovat v ASP.NET MVC (libovolné verze!) &#8222;sidebar widgety&#8220;. V tomto článku bych rád ukázal další možnosti realizace widgetů, na které nebyl v předchozím článku prostor. Ale ani tento článek není kompletním výčtem všech možností&#8230;<br />
<span id="more-440"></span></p>
<h2>SuperModel</h2>
<p>V předchozím řešení jsme od ViewModelu, který reprezentuje stránku s widgety, požadovali, aby implementoval rozhraní <em>IViewModelWithWidgets</em>. Pokud ale v našem projektu widgety podporuje drtivá většina stránek, nemusí být toto řešení nejvhodnější. Nechceme totiž v zájmu <a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself">DRY</a> opakovat definici property <em>Widgets</em> v každém ViewModelu, takže nakonec stejně skončíme u nějakého bázového ViewModelu (který jako jediný tuto property implementuje) a to se nám už nemusí líbit a můžeme začít šilhat po jiném řešení. Přitom ale nemusíme nutně slevovat z našeho požadavku, aby byla celá stránka reprezentována jedním &#8222;ViewModelem&#8220;.</p>
<p>Data pro celou stránku jsou totiž ve skutečnosti reprezentována třídou <a href="http://msdn.microsoft.com/en-us/library/dd505255(v=VS.98).aspx">ViewDataDictionary</a>, která je v <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.controllerbase.viewdata(v=VS.98).aspx">Controlleru</a> i v <a href="http://msdn.microsoft.com/en-us/library/dd493045(v=VS.98).aspx">šabloně</a> dostupná jako property <em>ViewData</em>. Jak již název napovídá, <em>ViewDataDictionary</em> není (zjednodušeně řečeno) nic jiného než <em>Dictionary</em> ze <em>string</em>u na <em>object</em>, který má ale navíc další properties &#8211; a nejvíce na očích je právě property <a href="http://msdn.microsoft.com/en-us/library/dd460191(v=VS.98).aspx">Model</a>, ve které máme typicky instanci našeho ViewModelu.</p>
<p>Vhodnějším řešením, které nás už nebude nabádat k vytváření super-ViewModelu, je tak ukládání dat pro widgety pod <em>nějakým</em> klíčem přímo do <em>ViewData</em>. Kód v akčním filteru (metoda <em>OnActionExecuted</em>) se nám tak ztenčí na pouhé přímé přiřazení do <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.controllerbase.viewdata(v=VS.98).aspx">ViewData</a>. I kód v šabloně bude jednodušší &#8211; omezí se na zjištění, zda je ve <a href="http://msdn.microsoft.com/en-us/library/dd493045(v=VS.98).aspx">ViewData</a> obsažen požadovaný klíč.</p>
<p>Úplně nám tak odpadne potřeba zavádět nějaká infrastrukturní rozhraní jako v řešení z předchozího článku&#8230;</p>
<h2>Ajaxizace</h2>
<p>Uživatele našeho webu bude asi typicky zajímat především hlavní obsah stránky a nechce být zdržován tím, že bude muset čekat o chvilku déle než se načte nějaký zpropadený widget, který ho třeba v danou chvíli vůbec nezajímá. Jaké máme možnosti, když se vzdáme řešení s použitím Action Filterů?</p>
<p>Od <a href="http://www.augi.cz/programovani/asp-net-mvc-2/">ASP.NET MVC 2</a> máme k dispozici helper metody <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.html.childactionextensions.action(v=VS.98).aspx">Html.Action</a> a <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.html.childactionextensions.renderaction(v=VS.98).aspx">Html.RenderAction</a>, pomocí kterých můžeme provést jakýsi Sub-Request. Dojde tedy k zavolání dané akční metody a spuštění vráceného <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.actionresult(v=VS.98).aspx">ActionResult</a>u (jako v případě běžného requestu). Výsledek můžeme získat buď ve formě stringu (<em>Html.RenderAction</em>) nebo je výsledek vyrenderován přímo na místo, kde voláme <em>Html.Action</em>. Toto je velmi silná zbraň a díky ní můžeme prezentační logiku koncipovat zcela jinak.</p>
<p>Ideální mi přijde situace, kdy máme pro každý widget jednu akční metodu a k ní odpovídající šablonu (~<em>ascx</em>~<em>Partial View</em>). Mohli bychom mít jeden &#8222;velký&#8220; Controller jen pro akční metody widgetů, ale bude lepší mít pro každý widget samostatný Controller &#8211; widgety totiž mohou být interaktivní (tj. potřebovat další akční metody pro dodatečnou funkcionalitu) a pravděpodobně budou mít zcela rozdílné závislosti.</p>
<p>Pokud máme pro widget samostaný Controller a samostatnou šablonu, máme ho krásně separovaný. Úkolem hlavní stránky pak bude pouze zajistit volání <em>Html.[Render]Action</em> pro každý widget.</p>
<p>Separace nám přináší i další výhodu &#8211; volání akční metody je skvělý kandidát na kešování &#8211; můžeme využít standardní atribut <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.outputcacheattribute(v=VS.98).aspx">OutputCache</a>.</p>
<p>Nyní jsme ale stále v situaci, kdy se celá stránka načítá během jednoho requestu &#8211; ajaxizace je ale velmi jednoduchá! Pokud totiž akční metodu neoznačíme atributem <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.childactiononlyattribute(v=VS.98).aspx">ChildActionOnly</a>, můžeme ji volat i samostatně v rámci normálního requestu (samozřejmě musíme zajistit, aby se k ní dalo <em>doroutovat</em>).<br />
V hlavní stránce, která dosud volala <em>Html.[Render]Action</em>, se bude nyní generovat kód, který zajistí, že se widgety dotáhnou pomocí samostatných Ajax requestů (např. s využitím <a href="http://zdrojak.root.cz/clanky/html5-ukladame-si-data-k-elementum/">data atributů</a>).</p>
<p>Pokud chceme minimalizovat počet Ajax requestů, můžeme udělat jednu pomocnou akční metodu, která spustí akční metody požadovaných widgetů &#8211; tím se dostaneme na jeden request pro hlavní stránku a druhý request pro widgety.</p>
<h2>Závěr</h2>
<p>V <a href="http://www.augi.cz/programovani/jak-na-widgety-v-asp-net-mvc/">předchozím článku</a> jsem nastínil způsob implementace widgetů, který byl oblíbený v době první verze ASP.NET MVC. V první části toho článku jsem ukázal jeho vylepšení, které nás nenutí používat bázové třídy pro ViewModely a nejen díky tomu je flexibilnější a méně invazivní.</p>
<p>Za nejlepší řešení v současné době ale považuji variantu s <em>Html.[Render]Action</em>, která přináší mnohem větší míru modularity a jako (příjemný) důsledek snadné kešování a podporu pro asynchronní načítání widgetů v samostatném requestu.</p>
<p>Každý projekt si ale žádá svoje a tyto dva články rozhodně nepopisují všechny možnosti, jak je možné widgety v ASP.NET MVC implementovat. Věřím ale, že články mohou posloužit jako inspirace při implementaci widgetů ve vašem projektu&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.augi.cz/programovani/jak-jinak-na-widgety-v-asp-net-mvc/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Jak na widgety v ASP.NET MVC</title>
		<link>http://www.augi.cz/programovani/jak-na-widgety-v-asp-net-mvc/</link>
		<comments>http://www.augi.cz/programovani/jak-na-widgety-v-asp-net-mvc/#comments</comments>
		<pubDate>Tue, 29 Nov 2011 22:06:32 +0000</pubDate>
		<dc:creator>Augi</dc:creator>
				<category><![CDATA[Programování]]></category>

		<guid isPermaLink="false">http://www.augi.cz/?p=439</guid>
		<description><![CDATA[Už několikrát jsem dostal otázku, jak udělat v ASP.NET MVC &#8222;widgety&#8220;, tedy &#8222;komponenty&#8220;, které jsou někde na okraji každé stránky. Slyšel jsem názory, že ASP.NET WebForms jsou mnohem více nakloněny komponentovému vývoji (souhlasím) a tak je vývoj takových komponentových udělátek ve WebForms mnohem jednodušší než v MVC &#8211; s tím si ale dovolím nesouhlasit. Aby [...]]]></description>
			<content:encoded><![CDATA[<p>Už několikrát jsem dostal otázku, jak udělat v ASP.NET MVC &#8222;widgety&#8220;, tedy &#8222;komponenty&#8220;, které jsou někde na okraji každé stránky. Slyšel jsem názory, že ASP.NET WebForms jsou mnohem více nakloněny komponentovému vývoji (souhlasím) a tak je vývoj takových komponentových udělátek ve WebForms mnohem jednodušší než v MVC &#8211; s tím si ale dovolím nesouhlasit. Aby byl člověk schopen napsat kvalitní komponentu ve WebForms, tak je nutné tento framework znát velmi zevrubně. A v ASP.NET MVC je to úplně stejné &#8211; pokud znáte MVC dobře, tak dokážete i v MVC pohodlně napsat widgetový systém. Mé řešení vám ukáži v tomto článku.<br />
<span id="more-439"></span></p>
<h2>Data pro widgety</h2>
<p>Moje filozofie je taková, že ve ViewModelu (který se vrací v akční metodě pomocí <em>return View(viewModel);</em>) musí být <strong>všechna</strong> data potřebná pro rendering <strong>celé</strong> stránky &#8211; tedy &#8222;hlavní obsah&#8220; i data widgetů.</p>
<p>Na úrovni Controlleru tak musíme zajistit, že načteme data pro všechny widgety, které budeme zobrazovat. Ano, už v Controlleru musíme vědět, co přesně budeme chtít vykreslovat &#8211; tak to má být &#8211; rozhodně bychom neměli takové rozhodnutí nechávat až do View!</p>
<p>Widgety ale nejsou &#8222;tím hlavním&#8220; co chceme v akční metodě dělat &#8211; to je něco jiného &#8211; např. v případě blogového systému načtení informací o článku (text, autor, &#8230;). Přidávat ručně kód pro načítaní widgetů do každé akční metody samozřejmě nebudeme. Takový úkol lze elegantně řešit pomocí aspektů, které jsou v ASP.NET MVC dostupné formou <a href="http://www.asp.net/mvc/tutorials/understanding-action-filters-cs">Action Filterů</a>. Implementujeme tedy v Action Filteru metodu <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.iactionfilter.onactionexecuted(v=VS.98).aspx">OnActionExecuted</a>, která se volá po provedení akční metody.</p>
<p>Jak ale zařídit, abychom mohli v této metodě uložit data pro widgety do ViewModelu? Jednoduše si vytvoříme rozhraní <em>IViewModelWithWidgets</em>, které musí implementovat každý ViewModel, jenž odpovídá stránce, na níž chceme vykreslovat widgety. Zde záleží, jestli máme widgety pevné nebo např. uživatelsky konfigurované.<br />
V prvním případě můžeme mít dílčí ViewModely pro widgety přímo jako properties rozhraní <em>IViewModelWithWidgets</em>.<br />
V druhém případě (který budu uvažovat dále) bude lepší mít jen jednu property typu <em>IEnumerable&lt;IWidget&gt;</em> nesoucí data pro všechny widgety. Rozhraní <em>IWidget</em> by mělo obsahovat minimálně property <em>string PartialViewName</em> &#8211; můžeme ale přidat třeba informace o pořadí widgetů apod.</p>
<p>Kostra Action Filteru může vypadat takto:</p>
<pre class="brush: csharp">public void OnActionExecuted(ActionExecutedContext filterContext)
{
  if (!(filterContext.Result is ViewResultBase))
  {
     return; // we will not render a View
  }
  var vm = ((ViewResultBase)filterContext.Result).Model as IViewModelWithWidgets;
  if (vm == null)
  {
    return; // we don't want to render widgets
  }
  vm.Widgets = InjectedWidgetProvider.GetWidgetsForCurrentUser();
}</pre>
<p>Atributem můžeme odekorovat jednotlivé metody, celé Controllery, příp. zaregistrovat Action Filter jako <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.globalfilters.filters(v=VS.98).aspx">globální</a> nebo ho servírovat pomocí vlastního <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.ifilterprovider(v=VS.98).aspx">Filter Provideru</a> (pak ho nezapomeňte <a href="http://msdn.microsoft.com/en-us/library/system.web.mvc.filterproviders.providers(v=VS.98).aspx">zaregistrovat</a>). Poslední možnost doporučuji zejména tehdy, když potřebujete řídit životnost Action Filteru nebo do něj injectovat nějaké závislosti (např. připojení do databáze na přečtení nakonfigurovaných widgetů pro přihlášeného uživatele).</p>
<h2>Vykreslení</h2>
<p>Při použití ASPX enginu (ne-Razor) vyřešíme vykreslení widgetů elegantně pomocí <a href="http://msdn.microsoft.com/en-us/library/wtxbf3hh.aspx">Master Pages</a> (když si ve Visual Studiu vytvoříte nový <em>ASP.NET MVC 3 Web Application</em>, tak ten Master Pages používá).<br />
To znamená, že máme soubor <em>Site.Master</em>, který obsahuje &#8222;šablonu&#8220;, jak má vypadat celá stránka. V této &#8222;šabloně&#8220; máme díry, jejichž obsah se mění &#8211; takže nějaký <em>ContentPlaceHolder</em> pro hlavní obsah, pro menu, pro nadpis stránky apod.<br />
V konkrétním View (např. <em>Detail.aspx</em>) pak pomocí atributu <em>MasterPageFile</em> určíme, jaká Master Page se použije (často máme v projektu jen jednu &#8211; <em>Site.Master</em>) a naším úkolem je dodat obsah pro <em>ContentPlaceHolder</em>y.</p>
<p>Ale zpět k našim widgetům. Kód v <em>Site.Master</em> bude přímočarý &#8211; zjistíme, zda se mají widgety renderovat, a pokud ano, tak je na nějakém vhodném místě (třeba uvnitř nějakého <em>div</em>u) vykreslíme:</p>
<pre class="brush: csharp">if (Model is IViewModelWithWidgets)
{
  foreach(IWidget widgetViewModel in ((IViewModelWithWidgets)Model).Widgets)
  {
     Html.RenderPartial(widgetViewModel.PartialViewName, widgetViewModel);
  }
}</pre>
<p>Pro každý widget pak budeme mít Partial View (<em>ascx</em>), které bude mít Model odpovídajícího typu (implementující rozhraní <em>IWidget</em>).</p>
<h2>Závěr</h2>
<p>Co jsme tedy museli udělat:</p>
<ul>
<li>Připravit si datový model, tj. zavést si rozhraní <em>IWidget</em> a <em>IViewModelWithWidgets</em>.</li>
<li>ViewModely pro widgety musí implementovat rozhraní <em>IWidget</em>.</li>
<li>ViewModely pro stránky, které obsahují widgety, musí implementovat rozhraní <em>IViewModelWithWidgets</em>.</li>
<li>Zajistit naplnění kolekce <em>Widgets</em> na úrovni Controlleru &#8211; k tomu nám skvěle poslouží Action Filter.</li>
<li>Vytvořit Partial View (<em>ascx</em> soubor) pro každý widget a zajistit jeho vykreslení v <em>Site.Master</em>.</li>
</ul>
<p>Dle mého názoru tedy nic extrémně složitého &#8211; ViewModel a Partial View pro widgety jsou nutné minimum (proto to děláme) a infrastrukturního kódu není tolik &#8211; prakticky jen načtení dat v Action Filteru a vykreslení widgetů v <em>Site.Master</em>.</p>
<p>V praxi můžeme chtít toto řešení dále rozvinout &#8211; např. načítat widgety asynchronně pomocí AJAXu. Ani to ale není nic složitého&#8230;<br />
[<a href="http://www.augi.cz/programovani/jak-jinak-na-widgety-v-asp-net-mvc/">navazující článek</a>]</p>
<p><script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js"></script><br />
	<script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js"></script></p>
<link type="text/css" rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css"/>
<link type="text/css" rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css"/>
<p>	<script type="text/javascript">
		if (SyntaxHighlighter) {
			SyntaxHighlighter.all();
		}
	</script></p>
]]></content:encoded>
			<wfw:commentRss>http://www.augi.cz/programovani/jak-na-widgety-v-asp-net-mvc/feed/</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>Zamyšlení nad NoSQL</title>
		<link>http://www.augi.cz/programovani/zamysleni-nad-nosql/</link>
		<comments>http://www.augi.cz/programovani/zamysleni-nad-nosql/#comments</comments>
		<pubDate>Sat, 29 Oct 2011 17:25:48 +0000</pubDate>
		<dc:creator>Augi</dc:creator>
				<category><![CDATA[Programování]]></category>

		<guid isPermaLink="false">http://www.augi.cz/?p=438</guid>
		<description><![CDATA[NoSQL je buzzword, který je tu s námi téměř už tři roky, přesto je pro mnohé lidi velkou neznámou, případně symbolem vzpoury proti zlým ošklivým přežitým enterprise SQL databázím. Rád bych se s vámi podělil o můj pohled na NoSQL, který je ovlivněn hlavně více než rokem používání Cassandry. Co to je? Především je důležité [...]]]></description>
			<content:encoded><![CDATA[<p>NoSQL je buzzword, který je tu s námi <a href="http://en.wikipedia.org/wiki/NoSQL#History">téměř už tři roky</a>, přesto je pro mnohé lidi velkou neznámou, případně symbolem vzpoury proti <em>zlým ošklivým přežitým enterprise</em> SQL databázím. Rád bych se s vámi podělil o můj pohled na NoSQL, který je ovlivněn hlavně více než rokem používání <a href="http://cassandra.apache.org/">Cassandry</a>.<br />
<span id="more-438"></span></p>
<h2>Co to je?</h2>
<p>Především je důležité zdůraznit, co NoSQL není &#8211; rozhodně to není <em>NO SQL</em>, tedy <em>trendy</em> odmítání relačních databází. Zkratka NoSQL znamená <strong>Not Only SQL</strong>, tedy uvědomění si toho, že relační databáze není jediná možnost řešení persistence, že existují i alternativy, které mohou být v některých případech vhodnější.</p>
<p>U rozsáhlejších aplikací pak můžeme dojít k tomu, že na některá data je vhodná relační databáze, na jiná NoSQL databáze a na další data úplně jiná NoSQL databáze. Tento pragmatický přístup, kdy se mixuje použití více databází v jednom projektu, se často označuje jako <a href="http://codemonkeyism.com/nosql-polyglott-persistence/">polyglot persistence</a>.</p>
<p>NoSQL databáze vznikaly (a vznikají) jako řešení reálných problémů &#8211; není to tedy bláznivý výmysl akademiků odtržených od reality, ale vysoce praktická záležitost. Zrod mnoha NoSQL databází je spjat s projekty, které se musely vypořádat s obrovským množstvím dat &#8211; Facebook (<a href="http://cassandra.apache.org/">Cassandra</a>), Google (<a href="http://en.wikipedia.org/wiki/BigTable">BigTable</a>), Amazon (<a href="http://www.allthingsdistributed.com/2007/10/amazons_dynamo.html">Dynamo</a>), LinkedIN (<a href="http://project-voldemort.com/">Voldemort</a>) atd.</p>
<p>Použití NoSQL databáze může mít ale smysl i tehdy, pokud máme méně dat (které by v pohodě zvádla relační databáze) &#8211; třeba protože nějaká NoSQL databáze nabízí datový model, který je pro naši aplikaci přirozenější.</p>
<p>Ale zpět k úvodní otázce. <strong>NoSQL databáze je software pro perzistenci dat, který je alternativou ke klasickým relačním databázím</strong> (nic objevného). NoSQL databází existuje mnoho a dají se rozdělit z <a href="http://en.wikipedia.org/wiki/NoSQL#Taxonomy">mnoha hledisek</a>. Ve velmi specifických případech může dávat smysl vyvinout i vlastní NoSQL databázi (ale myslete na <a href="http://en.wikipedia.org/wiki/Not_Invented_Here">NIH</a>).</p>
<h2>Kdy použít NoSQL</h2>
<p>Rozhodnutí, zda použít místo ověřené relační databáze neznámou NoSQL databázi, není jednoduché, a hlavně to není rozhodnutí jen technické, ale i ekonomické.</p>
<p>NoSQL databáze např. často nemají takové možnosti dotazování jako relační databáze. Zkuste se třeba zamyslet nad tím, jak by ovlivnilo vaši aplikaci, kdyby jedinou podporovanou DB operací bylo uložení řádku a jeho načtení podle nějakého ID (nepřeháním!). To vede k tomu, že je na vaši aplikaci přenášena odpovědnost (např. generování sekundárních indexů), kterou jste dosud považovali za samozřejmou součást databázového enginu. Použití NoSQL databáze tak často znamená kompletní redesign celé aplikace, takže hodně učení a práce pro aplikační programátory (kteří nepracují zadarmo).</p>
<p>Většina dnešních programátorů vyrůstala ve světě, kde jedinou možností uložení dat byla relační databáze. Umí tak s ní dobře pracovat (v čemž jim pomáhají léty vyladěné tooly), jsou na ni schopni napasovat jakýkoliv model a už při úvodním seznamování s novým projektem jim v hlavě automaticky naskakují tabulky a vazby mezi nimi. Takže stojí za zvážení, zda se opravdu vyplatí investovat čas (~peníze) do učení diametrálně odlišných technologií a zda nemůže být ekonomičtější použít léty ověřené relační databáze namísto nové sexy NoSQL databáze.</p>
<p>Tím nechci říct, že se má absolutně kašlat na vzdělávání a inovaci, ale situace na trhu práce je tristní a ne každý má to štěstí (já ano <img src='http://www.augi.cz/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> ), že pracuje s bandou nadšených vývojářů, kteří čtou blogy, zajímají se o novinky v oboru a po večerech si zkouší nové technologie. Mnohdy člověk musí pracovat s lidmi, pro které je programování jen způsob obživy, odpracují si svých 8 hodin a tím to pro ně končí. A dělat s takovýmto týmem projekt, který používá NoSQL databázi, může být nákladné.</p>
<p>Náklady spojené s přechodem na NoSQL databázi se ale týkají celého týmu. Také vaši admini si budou muset umět poradit s novým SW v infrastruktuře, naučit se ho spravovat, zálohovat, tunit atp.</p>
<h2>Takže?</h2>
<p>Co jsem chtěl říct tímhle zamyšlením? NoSQL je zajímavá alternativa k zavedeným relačním databázím a rozhodně má své místo na trhu a proto doporučuji se o NoSQL databáze zajímat a nějaké si zkusit osahat. Pokud si proti nějaké NoSQL databázi zkusíte napsat jednoduchou aplikaci, neuvěřitelně vám to rozšíří obzory.</p>
<p>Nepoužívejte ale NoSQL databáze jen protože je to cool, protože by to <em>mohlo</em> být lepší nebo protože je používá konkurence. Řiďte se rozumem, ne emocemi. Dobře si spočítejte, co vám NoSQL přinese a jaké budou náklady. Pokud se už pro NoSQL rozhodnete, tak myslete na to, že se nemusíte úplně vzdávat <em>pohodlné</em> relační databáze &#8211; v projektu nemusíte používat jednu jedinou databázi&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.augi.cz/programovani/zamysleni-nad-nosql/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Pojďte pracovat do AVASTu!</title>
		<link>http://www.augi.cz/programovani/pojdte-pracovat-do-avastu/</link>
		<comments>http://www.augi.cz/programovani/pojdte-pracovat-do-avastu/#comments</comments>
		<pubDate>Mon, 20 Jun 2011 18:20:39 +0000</pubDate>
		<dc:creator>Augi</dc:creator>
				<category><![CDATA[Programování]]></category>

		<guid isPermaLink="false">http://www.augi.cz/?p=436</guid>
		<description><![CDATA[AVAST is hiring! Pokud chcete pracovat ve firmě, jejíž produkt má více než 130 miliónů uživatelů, ale máte strach, aby Vás nesešrotoval velký moloch, pak práce v AVASTu může být to pravé. Žádný dress-code, žádný open-space, žádný &#8222;manager&#8220;, který Vám bude stát s bičem za zády a diktovat nesmyslné požadavky nebo Vám vyčítat, že jste [...]]]></description>
			<content:encoded><![CDATA[<p>AVAST is hiring! Pokud chcete pracovat ve firmě, jejíž produkt má více než 130 miliónů uživatelů, ale máte strach, aby Vás nesešrotoval velký moloch, pak práce v AVASTu může být to pravé. Žádný dress-code, žádný open-space, žádný &#8222;manager&#8220;, který Vám bude stát s bičem za zády a diktovat nesmyslné požadavky nebo Vám vyčítat, že jste věnovali hodinu sebevzdělávání (třeba formou čtení Augiho blogu <img src='http://www.augi.cz/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> ).<br />
Každá mince má ale dvě strany, takže relativní svoboda v práci je vyvážena požadavkem na samostatnost, smysl pro pořádek a schopnost sebemotivace.<br />
<span id="more-436"></span></p>
<p><strong>Tato pozice již není volná, ale máme v AVASTu jiné neméně zajímavé pozice pro .NET programátory, takže se mi v případě zájmu <a href="mailto:augustyn@avast.com">neváhejte ozvat</a>.</strong></p>
<p>A o jakouže práci se to jedná? Spolu se mnou, <a href="https://twitter.com/#!/topascz">Tomášem</a> a částečně <a href="https://twitter.com/#!/alenkacz">AlenKou</a> byste spolupracoval(a) na systému pro podporu chodu naší <a href="https://blog.avast.com/category/viruslab/">virové laboratoře</a>, tzn. softwaru pro zpracování velkého množství <em>vzorků</em> z různých zdrojů, jejich automatické zpracování, přidělování analytikům, podporu pro vytváření nových virových definic (příp. samostatné tooly), reporting apod.</p>
<p>Vaším denním chlebem by tak byl C#, (T-)SQL, HTML+JS, vše podle aktuálních potřeb. Zastáváme totiž názor, že než mít specialistu <strong>jen</strong> na jednu věc (databáze, web), je lepší, aby se vývojář staral o <em>vertikální výsek</em> projektu, tj. aby šel se svou částí kódu od databáze, přes aplikační server až po nasazení a podporu. Přirozeně, každý jsme jiný, každého baví něco jiného (a tak se o to víc zajímá), takže zde funguje výměna zkušeností, společné <em>Utils</em> knihovny atd.</p>
<p>Pozornému čtenáři mého blogu asi netřeba zdůrazňovat, že máme rádi nové technologie (pokud má jejich použití smysl) a rádi děláme věci pořádně. Příkladem budiž použití NoSql databáze <a href="http://www.augi.cz/programovani/cassandra-ocima-net-programatora/">Cassandra</a>, <a href="http://www.augi.cz/programovani/unit-testy-a-globalni-stav/">testování</a> (to opravdu není pravidlem v každé firmě) nebo nově <a href="http://www.augi.cz/programovani/prubezna-integrace/">integrační server</a>.</p>
<p>Co očekáváme od uchazeče?</p>
<ul>
<li>perfektní znalost C# (minimálně verze 3)</li>
<li>perfektní znalost .NET Frameworku (minimálně verze 3.5) &#8211; kromě <em>core</em> především ADO.NET, ASP.NET a WCF</li>
<li>zkušenosti s ASP.NET MVC</li>
<li>dobrou znalost MS SQL (2008)</li>
<li><em>praktickou</em> znalost návrhových vzorů (tj. umět je správně aplikovat v praxi, ne je umět vyjmenovat)</li>
<li>znalost základních algoritmů a jejich složitostí (opět umět využít při rozhodování během řešení úkolu)</li>
<li>zkušenosti s psaním testů</li>
<li>obecný rozhled v SW technologiích, tj. nežít jen v MS bublině, vědět co je heap, stack, COM, serializace, tušit jak může fungovat Garbage Collector, jak funguje TCP, HTTP, vědět proč pařez nemůže býti stromem atd. (prostě základy, co musí každý programátor znát)</li>
<li>zájem o nové technologie, přístupy a postupy</li>
<li>&#8230;ale i základní znalost starého dobrého čistého C (schopnost napsat/upravit jednoduchý program v C)</li>
<li>vystudovaná slušná technická univerzita je dobrým předpokladem, nikoliv nutnou podmínkou (tou je znalost metodik UTFG a RTFM)</li>
</ul>
<p>Technický skill ale není vše, takže očekáváme i rozumné osobnostní rysy, především komunikativnost (je potřeba komunikovat se zbytkem virové laboratoře) a rozumnou míru asertivity (nebát se přijít s vlastním nápadem, vylepšením nebo kritikou). Výše zmiňovaná samostatnost, smysl pro pořádek a nadšení pro práci jsou nutnou podmínkou (co si budeme nalhávat, jsme tu tak trošku perfekcionisti a zlí jazykové by řekli, že i trošku workoholici <img src='http://www.augi.cz/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> ).</p>
<p>Práce není možná z domova, ani na částečný úvazek, ale pracovní doba je &#8222;flexibilní&#8220;, tj. když ráno potřebujete zajít na úřad, tak se svět nezboří. Sedíme v Praze přímo <a href="http://mapy.cz/#x=14.452372&#038;y=50.045165&#038;z=15&#038;d=addr_11540571_0_1&#038;t=s&#038;q=Bud%C4%9Bjovick%C3%A1%201518%2F13a%2C%20Praha&#038;qp=8.785824_47.373659_22.467885_51.854782_6">na Budějovické</a> (metro C), v krásné nové <a href="http://www.trianon.cz/">budově</a>. Kanceláře máme různě velké, ale rozhodně nebudete sedět v openspace.</p>
<p>A co Vám můžeme nabídnou my (pokud Vám výše uvedené nestačí <img src='http://www.augi.cz/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> ) ?</p>
<ul>
<li>solidní plat</li>
<li>5 týdnů dovolené</li>
<li>firemní angličtina</li>
<li>90Kč stravenky</li>
<li>nealko pití na pracovišti</li>
<li>příspěvek na důchodové připojištění</li>
<li>nekuřácké pracoviště</li>
</ul>
<p>Pokud Vás nabídka práce zaujala, <a href="mailto:augustyn@avast.com">neváhejte mi napsat</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.augi.cz/programovani/pojdte-pracovat-do-avastu/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Průběžná integrace</title>
		<link>http://www.augi.cz/programovani/prubezna-integrace/</link>
		<comments>http://www.augi.cz/programovani/prubezna-integrace/#comments</comments>
		<pubDate>Sun, 05 Jun 2011 13:06:44 +0000</pubDate>
		<dc:creator>Augi</dc:creator>
				<category><![CDATA[Programování]]></category>

		<guid isPermaLink="false">http://www.augi.cz/?p=435</guid>
		<description><![CDATA[Continuous integration je volně řečeno souhrn praktik a nástrojů, při kterých vývojáři integrují (commitují) své změny často (typicky alespoň jednou za den). Každá integrace je automaticky ověřena testy a případně může vést až k automatickému nasazení nové verze aplikace (continuous delivery), v případě neúspěchu k okamžitému reportování problému. Přínosy continuous integration jsou především zrychlení vývoje, [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://martinfowler.com/articles/continuousIntegration.html">Continuous integration</a> je volně řečeno souhrn praktik a nástrojů, při kterých vývojáři integrují (commitují) své změny často (typicky alespoň jednou za den). Každá integrace je automaticky ověřena testy a případně může vést až k automatickému nasazení nové verze aplikace (<em>continuous delivery</em>), v případě neúspěchu k okamžitému reportování problému.<br />
Přínosy continuous integration jsou především zrychlení vývoje, rychlejší dodávání nových verzí a snížení chybovosti &#8211; to vše <strong>díky automatizaci co nejvíce úkonů</strong>, které je třeba dělat při vývoji, testování a nasazovaní aplikace.</p>
<p>Všechno by to šlo implementovat pomocí vzájemně provázaných skriptů, ale za šťastnější řešení (i když zavádí <a href="http://en.wikipedia.org/wiki/Single_point_of_failure">SPOF</a>) považuji nasazení nějakého <a href="http://en.wikipedia.org/wiki/Comparison_of_Continuous_Integration_Software">integračního serveru</a> coby hlavního koordinátora všech operací. Integrační server toho pro nás může ale dělat ještě více &#8211; např. provázat buildy a verze aplikace s <a href="http://en.wikipedia.org/wiki/Bug_tracking_system">bug trackerem</a> nebo <a href="http://en.wikipedia.org/wiki/Issue_tracking_system">issue trackerem</a> (<a href="http://www.bugzilla.org/">Bugzillou</a>, <a href="http://www.mantisbt.org/">Mantisem</a>, <a href="http://www.atlassian.com/software/jira/">Jirou</a>, &#8230;). Integrační server se tak může stát místem, na kterém vidíte <em>vše o projektu</em> (a slovo <em>integrační</em> tak dostává další rozměr).</p>
<p>V tomto článku bych vám rád popsal, proč a jak jsem nasazoval integrační server já. Moc jsem toho o průběžné integraci předem nenastudoval, přistoupil jsem k věci celkem pragmaticky &#8211; cílem bylo vyřešit problémy, které mě trápili. A díky <a href="http://www.jetbrains.com/teamcity/">TeamCity</a> jsem byl schopen do týdne rozjet prakticky vše, co jsem plánoval &#8211; tedy build Solution s více než 100 projekty (C# a C), spuštění unit testů, integračních testů, nasazení a spuštění akceptačních testů. Všechno samozřejmě plně automaticky, odpálené commitem do SubVersion.<br />
<span id="more-435"></span></p>
<h2>Proč jsem do toho šel?</h2>
<p>Až donedávna byl projekt, na kterém dělám, prakticky one-man-show. To mj. znamenalo, že všechno jsem měl pod palcem já &#8211; od konzistence (zbuildovatelnosti) zdrojových kódů v repository, přes spuštění a úspěšné projití všech testů až po nasazení (přes <a href="http://weblogs.asp.net/scottgu/archive/2010/07/29/vs-2010-web-deployment.aspx">One-Click Publish</a>). A všechny tyto kroky jsem dělal tehdy, když se mi zachtělo.<br />
Tento stav s sebou nesl mnoho problémů &#8211; nejvíc mě pálilo občasné vypublikování neotestovaného kódu (protože touhle změnou jsem prostě nemohl nic rozbít), omylem vypublikovaná DLLka ve špatném formátu (x86 místo x64) a především zdržení spojené s ručním nasazením aplikace (před publikováním nové verze jsem ručně zálohoval aktuální verzi). O ruční synchronizaci aplikace a databázového schématu ani nemluvím. Poslední kapkou bylo to, že k projektu přišel další člověk a já si uvědomil, co všechno si musí nainstalovat, aby byl schopen projekt vůbec zkompilovat.<br />
Zavedení continuous integration tak bylo lékem na všechny výše uvedené problémy.</p>
<h2>Příprava</h2>
<p><em>Jedna věc předem &#8211; je důležité si uvědomit, že &#8222;csproj&#8220; soubory nejsou nic jiného než build scripty pro MSBuild a proto se nebojte do nich zasahovat ručně &#8211; ne vše jde totiž naklikat přes Visual Studio.</em><br />
Prvním krokem k tomu, abyste mohli projekt zařadit do CI, je to, že projekt musí být po čistém checkoutu z repository zkompilovatelný <em>jedním příkazem</em>. Mým cílem tak bylo, aby fungovalo něco jako &#8222;<em>MSBuild.exe MySolution.sln /T:Build /p:Configuration:Release</em>&#8222;. To nebyl problém na mém vývojářském stroji, kde jsem měl nainstalované Visual Studio a knihovny třetích stran nakopírované na správná místa nebo v <a href="http://en.wikipedia.org/wiki/Global_Assembly_Cache">GAC</a>u. Na <em>čistém</em> build serveru to už ale tak růžové nebylo. Takže na co byste si měli dát pozor?</p>
<h3>Pre a Post-build stepy</h3>
<p>Pokud kopírujete v Pre a Post-build stepech nějaké dependence, které nelze jinak vyjádřit, tak zajistěte, aby v době volání příslušného stepu už existovaly &#8211; tedy zajistěte správné pořadí kompilace.<br />
Já jsem řešil poměrně běžnou věc &#8211; mám nějakou nativní DLL knihovnu, kterou potřebuji zkopírovat do výstupního adresáře .NETího projektu. Takže jsem si pěkně naklikal ve Visual Studiu závislosti mezi projekty a kompilace krásně jela. Ale na build serveru byl problém. Závislost mezi .NETím a nativním projektem se totiž uloží jen do <em>sln</em> souboru (což není narozdíl od <em>csproj</em>e build script!). V MSBuildu 3.5 by to bylo ok, protože tam si MSBuild vše pořádně očuchal a správně určil pořadí. To ale údajně způsobovalo u velkých projektů výkonové problémy (?) a tak byla tato fičura v MSBuildu 4.0 odstraněna a MSBuild kouká jen na závislosti uvedené přímo v projektových souborech. Visual studio vám ale nedovolí přidat do .NETího projektu referenci na ne-.NETí projekt, takže nelze jednoduše naklikat závislost .NETího projektu na ne-.NETtím &#8211; musíme <a href="http://blogs.msdn.com/b/msbuild/archive/2010/12/21/incorrect-solution-build-ordering-when-using-msbuild-exe.aspx">referenci ručně dopsat</a> do <em>csproj</em>e. Jako bonus dostaneme ve Visual Studiu žlutý vykřičníček a warning, ale kompilace pomocí MSBuildu probíhá ve správném pořadí.</p>
<h3>Knihovny třetích stran</h3>
<p>Jak říká Martin Fowler &#8211; &#8222;<em>Everything should be in the repository.</em>&#8222;. Takže mějte ve verzovacím systému binárky knihoven třetích stran a z projektů na ně odkazujte pomocí relativních cest (nebojte se podívat přímo do <em>csproj</em>e). Pozor si dávejte hlavně tehdy, když máte na vývojářském stroji nějakou knihovnu nainstalovanou v GACu &#8211; ve spojení s automatickým přidáváním referencí (jako nabízí třeba ReSharper) vám to může připravit nemilé překvapení (nareferencovat assembly z GACu).</p>
<h3>Generované soubory</h3>
<p>Pokud generujete soubory pomocí T4, tak tyto soubory musí být v repository. Jen je potřeba zajistit jejich přegenerování na vývojářově stroji &#8211; to mám udělané tak, že v pre-build stepu spouštím <a href="http://msdn.microsoft.com/library/bb126245.aspx">TextTransform.exe</a>, ale jen pokud existuje soubor &#8222;<em>%CommonProgramFiles(x86)%\Microsoft shared\TextTemplating\10.0\TextTransform.exe</em>&#8220; (instaluje se až s Visual Studiem). To zajistí, že na vývojářském stroji (tj. s nainstalovaným Visual Studiem) dojde v pre-build stepu k přegenerování T4 souboru.<br />
Pokud se rozhodnete vyřešit T4 soubory tímto způsobem, tak reference na <em>custom</em> assembly nedávejte přímo do <em>tt</em> souboru, ale předávejte je přes parametry příkazové řádky.</p>
<h3>Testy</h3>
<p>Připravte se na to, že pokud máte testy napsané v MSTestu, budete muset na stroj, na kterém chcete testy spouštět, instalovat Visual Studio (pokud nechcete použít nějaký alternativní test runner).<br />
Pokud používáte v testech <a href="http://msdn.microsoft.com/en-us/library/microsoft.visualstudio.testtools.unittesting.deploymentitemattribute.aspx">DeploymentItem</a>, tak možná narazíte na jeho trošku podivné chování při zadávání relativní cesty. Osvědčilo se mi zadávat cestu relativně k umístění <em>sln</em> souboru a při spuštění přes <a href="http://msdn.microsoft.com/en-us/library/ms182486.aspx">MSTest.exe</a> pak nastavit jako <em>runconfig</em> soubor <em>LocalTestRun.testrunconfig</em> (který je ve stejném adresáři jako <em>sln</em> soubor).<br />
Dále myslete na to, že tam, kde budete pouštět integrační testy, budete muset mít pravděpodobně dostupné nějaké testovací verze databází apod.</p>
<h3>Transformace configů</h3>
<p>Před tím, než ze zkompilovaných binárek vytvoříte instalační balíčky, <em>můžete</em> mít potřebu upravit nějaké konfigurační soubory v aplikaci. S .NET 4 přišly <a href="http://msdn.microsoft.com/en-us/library/dd465326.aspx">web.config transformation</a>, které toto velmi zjednoduší. Ve webovém projektu máte klasicky soubor <em>web.config</em> &#8211; v něm byste měli mít nastavení, které odpovídá <em>Debug</em> konfiguraci (protože při debugu se nevím proč transformace neprovádějí). Dále budete mít soubor <em>web.Release.config</em> (Visual Studio 2010 má na jeho přidání podporu), ve kterém budou transformace připravující konfiguraci pro <em>Release</em> konfiguraci. Pokud máte v projektu kromě <em>Debug</em> a <em>Release</em> i další konfiguraci (např. <em>Stage</em>), můžete mít transformace i pro tyto další konfigurace (např. <em>web.Stage.config</em>).</p>
<p>Je možné, že budete chtít transformovat i jiný soubor než <em>web.config</em> (my transformujeme <em>log4net.config</em>). To <a href="http://stackoverflow.com/questions/5557866/how-to-transform-log4net-config-like-web-config/5998230#5998230">samozřejmě</a> <a href="http://stackoverflow.com/questions/4750153/transforming-files-with-msdeploy/5381408#5381408">není</a> <a href="http://geekswithblogs.net/EltonStoneman/archive/2010/08/20/using-msbuild-4.0-web.config-transformation-to-generate-any-config-file.aspx">problém</a>.<br />
Pokud nebudete mít na build serveru Visual Studio, tak si dejte pozor, abyste si vybrali to správné <a href="http://stackoverflow.com/questions/5557866/how-to-transform-log4net-config-like-web-config/5623673#5623673">řešení</a>.</p>
<p>Transformaci konfiguračních souborů můžete ale samozřejmě dělat jakkoliv, třeba pomocí vlastních skriptů &#8211; na tom nevidím nic špatného.</p>
<p>Nejen z hlediska bezpečnosti je velmi zajímavou variantou mít v některých konfiguračních položkách místo hodnot jen placeholdery, které se naplní správnými hodnotami až při nasazení. To je velice flexibilní řešení, protože umožní nasadit jeden distribuční balíček v různých prostředích (typicky různé <em>connection string</em>y).</p>
<h3>Vytvoření instalačních balíčků</h3>
<p>Instalační/Distribuční balíčky se zásadně liší podle typu aplikace &#8211; já se zde zaměřím jen na webové aplikace, konkrétně na vytváření balíčků, které se budou dále nasazovat pomocí nástroje <a href="http://technet.microsoft.com/en-us/library/dd569106(WS.10).aspx">MSDeploy</a> (<em>Web Deployment Tool</em>).<br />
Způsob vytvoření balíčku si můžete nastavit přímo ve Visual Studiu, v <em>Properties</em> dané webové aplikace. Já jsem si oblíbil možnost vytvořit balíček jako soubor <em>zip</em> a vytvořit ho v adresáři &#8222;Deploy/Packages&#8220; (relativně k solution).<br />
Důležité je, že balíčky mohou být parametrizované, což umožní výše zmiňované podstrčení správných hodnot do konfiguračních souborů až při nasazení (automaticky jsou takto parametrizovány právě zmiňované <em>connection string</em>y).</p>
<p>Pokud chcete do balíčku přidat nějaké vlastní soubory (u mě to jsou opět nativní DLL knihovny do adresáře <em>/bin</em>), tak to není problém &#8211; stačí je <a href="http://stackoverflow.com/questions/2747081/how-do-you-include-additional-files-using-vs2010-web-deployment-packages/2748752#2748752">dospecifikovat</a> v <em>csproj</em>i.</p>
<p>Jak ale vytvořit balíček z MSBuildu? Zde je opět více možností. Můžete zavolat MSBuild s targetem <em>Package</em> (&#8222;<em>MSBuild /T:Package</em>&#8222;) nebo můžete nechat vytvořit balíčky ihned během kompilace pomocí property <em>DeployOnBuild</em> (&#8222;/p:DeployOnBuild&#8220;).</p>
<h3>Nasazení</h3>
<p>Nasazení děláme pomocí nástroje <a href="http://technet.microsoft.com/en-us/library/dd569106(WS.10).aspx">MSDeploy</a>, který umožňuje plnohodnotné nasazení, tj. nejen zkopírování souborů, ale i vytvoření a ovládání AppPoolu, nastavení práv, migraci databáze atd. Je třeba <a href="http://www.iis.net/download/WebDeploy">ho</a> mít nainstalovaný jak na stroji, ze kterého nasazujeme, tak na stroji, na který nasazujeme. Typický příkaz pro jednoduché nasazení může vypadat nějak takto:</p>
<pre>"%ProgramFiles%\IIS\Microsoft Web Deploy V2\MSDeploy.exe" -verb:sync
 -source:package=Packages/MyApplication.zip
 -dest:auto,computerName="https://deployTargetComputer:8172/msdeploy.axd
?site=Default Web Site",userName=%username%,password=%pwd%,authtype=basic
 -allowUntrusted</pre>
<p>Parametry balíčku (např. výše zmiňované <em>connection string</em>y) se dají nastavit intuitivně pomocí přepínače <a href="http://technet.microsoft.com/en-us/library/dd569089(WS.10).aspx">-setParam</a>, příp. můžete podstrčit celý soubor s parametry.</p>
<h3>Migrace databáze</h3>
<p>Při nasazení aplikace je třeba ověřit, že okolní infrastruktura odpovídá tomu, na co byla aplikace stavěna. Pokud se zaměříme jen na databáze, tak bychom měli ověřit, že schéma v databázi odpovídá tomu, proti čemu chce aplikace pracovat.</p>
<p>To se typicky dělá tak, že aplikace ví verzi schématu (celé číslo), databáze má v nějaké metatabulce uloženu aktuální verzi schématu, a <em>instalační</em> skript je zodpovědný za to, že se zavolají migrační skripty, které zajistí upgrade (příp. downgrade) databáze podle potřeb aplikace, tj. sjednotí verzi schématu požadovanou aplikací a aktuální v databázi.</p>
<p>Celou tuto infrastrukturu si můžeme napsat sami (není to nic složitého), můžeme využít nějaké migrační knihovny, nebo může využít to, co nabízí <a href="http://msdn.microsoft.com/en-us/library/dd465343.aspx">Visual Studio a MSDeploy</a>.</p>
<h2>Můžeme začít!</h2>
<p>Pokud jsme schopni zkompilovat projekt jednoduše ihned po čistém checkoutu z repository, máme na build serveru nainstalovány všechny potřebné věci (.NET 4, VS2010, MSDeploy, &#8230;), umíme generovat distribuční balíčky a máme připraveny skripty pro jejich nasazení, tak nám nic nebrání nainstalovat nějaký integrační server a jednotlivé části této výrobní linky v něm provázat.</p>
<p>Já jsem se rozhodl použít <a href="http://www.jetbrains.com/teamcity/">TeamCity</a> a rozhodně své volby nelituji. O instalaci jsem se díky našemu <a href="http://twitter.com/#!/lukashasik">QA</a> starat nemusel, ale veškerou konfiguraci jsem pak dělal sám a poměrně rychle jsem se zorientoval. Předností je taktéž cena, která je pro menší a střední projekty nulová.</p>
<p>V každém projektu (já mám jen jeden projekt odpovídající celému solution) můžete mít (v Professional verzi, která je zadarmo, až 20) <em>Build Configurations</em>. Jednu <em>Build Configuration</em> bych označil za jednu výrobní linku, takže můžete mít třeba dvě BC z názvy &#8222;Stage&#8220; a &#8222;Production&#8220;. Když budou tyto dvě BC téměř identické, je možné vyextrahovat šablonu a tyto dvě BC na ní založit. Parametrizaci pak provedete přes <em>Build Parameters</em>.</p>
<p>Každá BC v sobě obsahuje posloupnost <em>Build Step</em>ů. Prvním (implictním) krokem je checkout z repository. Další kroky jsou již plně na nás, ale TeamCity nám zde velmi vychází vstříc &#8211; jsou zde připravené &#8222;<em>build step runnery</em>&#8220; pro spuštění MSBuildu, MSTestu, baťáku, PowerShellu, Antu, FxCopu&#8230;a dokonce přímo Solution (takže staší zadat cestu k solution, které chcete zkompilovat).</p>
<p>Dalším důležitým nastavením jsou triggery, které umožní nastavit, kdy se má BC spustit &#8211; kadý den v zadaný čas nebo po commitnutí do repository jsou samozřejmostí.</p>
<h2>Hotovo</h2>
<p>Týdnu, který jsem věnoval zavedení průběžné integrace, vůbec nelituji. Díky CI jsem zautomatizoval drtivou většinou věcí, které je třeba dělat při vývoji, testování a nasazování aplikace. Rozhodně ale nepovažuji současný stav za finální, protože je ještě spousta věcí, které by šly vylepšit nebo přidat &#8211; např. lepší správa konfiguračních souborů, automatický rollback po neúspěšném nasazení atd.</p>
<p>I současný stav je obrovským přínosem a proto vám doporučím začít s CI. Není potřeba začít hned dělat všechny věci, které zde popisuji &#8211; můžete je zavádět <em>průběžně</em>. Stačí začít třeba tím, že se vytvoří build server, který bude po každém commitu kontrolovat <em>zbuildovatelnost</em> solution &#8211; i to je velmi pěkný první krok.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.augi.cz/programovani/prubezna-integrace/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Unit testy a globální stav</title>
		<link>http://www.augi.cz/programovani/unit-testy-a-globalni-stav/</link>
		<comments>http://www.augi.cz/programovani/unit-testy-a-globalni-stav/#comments</comments>
		<pubDate>Sun, 03 Apr 2011 09:58:42 +0000</pubDate>
		<dc:creator>Augi</dc:creator>
				<category><![CDATA[Programování]]></category>

		<guid isPermaLink="false">http://www.augi.cz/?p=434</guid>
		<description><![CDATA[Unit testy a globální stav &#8211; jak to jde dohromady? Vůbec! Za žádných okolností! Takové bylo pro mě hlavní poselství přednášky Miška Heveryho z Googlu, kterou měl v březnu 2011 na ČVUT. Pokud chcete psát dobrý (dobře testovatelný) kód, tak se opravdu použití globálního stavu vyvarujte. Jak ale identifikovat přítomnost globálního stavu v kódu? Typickým [...]]]></description>
			<content:encoded><![CDATA[<p>Unit testy a globální stav &#8211; jak to jde dohromady? Vůbec! Za žádných okolností! Takové bylo pro mě hlavní poselství přednášky <a href="http://misko.hevery.com/">Miška Heveryho</a> z Googlu, kterou měl v březnu 2011 na ČVUT. Pokud chcete psát dobrý (dobře testovatelný) kód, tak se opravdu použití globálního stavu vyvarujte. Jak ale identifikovat přítomnost globálního stavu v kódu?<br />
<span id="more-434"></span><br />
Typickým a snadno odhalitelným globálním stavem je globální proměnná (<em>static</em> v C#), často jako součást implementace Singletonu. Globální proměnnou by v ideálním případě neměl náš kód používat. Nikdy.<br />
<em>Btw. &#8222;naším kódem&#8220; (zde i dále) myslím především jádro naší aplikace &#8211; business logiku, doménovou logiku, &#8230;</em></p>
<p>Jednoduchá a univerzální poučka zní, že pokud váš unit test vyžaduje úklid (teardown), pak testovaný kód s největší pravděpodobností pracuje s globálním stavem. Potřebujete např. po skončení testu smazat nějaké soubory z disku nebo vymazat nějaké hodnoty z databáze? Pak se může jednat o integrační test a pokud si to uvědomujete, tak to může být ok. Pokud se má ale jednat o skutečný unit test, tak je něco v nepořádku. Unit test by měl totiž testovat jen jednu jednotku a to v dokonalé izolaci &#8211; a pokud nejsme schopni používaný globální stav odizolovat, pak je náš testovaný kód shnilý a měli bychom s tím něco dělat.<br />
Máme tedy abstrahovat přístup k databázi nebo souborovému systému? V případě relační databáze jsme často díky ORM již odstíněni a slušné ORM pak není problém odizolovat a jako backend použít místo skutečné databáze jen kolekci v paměti. A u přístupu k souborovému systému není zas takový problém si vytvořit odstiňující vrstvu. Ale chápu, že to někdo může považovat za zbytečné vrstvení &#8211; pragmatickým přístupem pak může být pro takovou třídu nepsat unit test, ale jen integrační test.</p>
<p>Posledním, ne tak zřejmým, zdrojem globálního stavu, o kterém chci psát, je zjištění aktuálního času &#8211; vlastně to spadá do prvního zmiňované kategorie (použití globální proměnné, viz např. <em>DateTime.UtcNow</em> v C#), ale člověk si to tak neuvědomuje. Udělali tedy snad inženýři v Microsoftu chybu, že nám dali k dispozici aktuální čas přes globální proměnnou? Ne, jejich kód je z hlediska testovatelnosti ok. Pokud to dává smysl, klidně zavádějte globální proměnné &#8211; ale pokud chcete psát testovatelný kód, tak globální proměnné nepoužívejte napřímo. To znamená, že je vhodné z hlediska testovatelnosti odstínit údaj o aktuálním času za nějaké rozhraní <em>ICurrentDateTimeProvider</em>.</p>
<p>Jak jsem <a href="http://twitter.com/#!/AugiCZ/status/51207273602760705">nadhodil</a> na Twitteru, na první pohled se to může zdát jako over-engineered řešení &#8211; a dostalo se mi několika zajímavých reakcí.</p>
<p><a href="http://rarous.net/">Aleš Roubíček</a> <a href="http://twitter.com/#!/alesroubicek/status/51208755232251904">navrhuje</a> udělat pro každou metodu, která potřebuje aktuální čas, další overload, který má další parametr typu <em>DateTime</em>. To je zajímavé řešení, ale nelíbí se mi, že si zaprasíme veřejné API oné třídy. Ano, metoda s parametrem navíc by mohla být <em>internal</em> a mohli bychom použít <a href="http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx">InternalsVisibleTo</a>, ale&#8230;;-)<br />
Dobrý protiargument proti Alešově řešení <a href="http://twitter.com/#!/kolman/status/51224214560182272">nadnesl</a> <a href="http://kolman.cz/">Dan Kolman</a> &#8211; co když nějaká jiná metoda volaná během testu používá onu metodu bez parametru (a tedy používající <em>DateTime.UtcNow</em>) ? Pak jsme v koncích&#8230;</p>
<p>S další reakcí přišel <a href="http://filovo.net/">Filip Kinský</a>, který <a href="http://twitter.com/#!/Buthrakaur/status/51219047987159040">navrhuje</a> <a href="https://gist.github.com/886617">toto řešení</a>. To je docela fajn, protože nevoláme napřímo standardní <em>DateTime.Now</em>, jejíž hodnotu nemáme možnost změnit. Nyní můžeme změnit delegáta, který obstarává získání aktuálního času. Problém je ale v tom, že tato závislost není povinná (nikdo nás nenutí nastavit property <em>CurrentDateTime</em>) a třída tak v deklaraci konstruktoru <a href="http://twitter.com/#!/alesroubicek/status/51252967692701696">neinformuje o této závislosti</a>. A to je z mého hlediska problém, protože na <em>nepovinnou závislost</em> nevěřím &#8211; toto sousloví vnímám jako oxymóron <img src='http://www.augi.cz/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Vzásadě jsme se ale shodli, že odstínit přístup k aktuálnímu času (coby globálnímu stavu), <a href="http://twitter.com/kolman/status/51211466879156224">je</a> <a href="http://twitter.com/vladkax/status/51214052990521344">z hlediska</a> <a href="http://twitter.com/vlkodotnet/status/51213939077414912">testovatelnosti</a> <a href="http://twitter.com/hercegtomas/status/51321944599044096">dobré</a>.</p>
<p>Shrnutí na závěr je takové, že byste se měli ve svém kódu vyvarovat použití globálního stavu napřímo &#8211; z hlediska testovatelnosti (která jde ruku v ruce s <em>dobrým</em> návrhem obecně) je vhodné mít přístup ke globálnímu stavu odstíněn, abychom ho mohli kdykoliv nahradit.<br />
Ještě bych dodal, že každá třída by měla mít všechny své závislosti dostat přes parametry konstruktoru (volání konstruktoru se <em>nemůžeme</em> vyhnout). Zároveň ale pamatujte na <a href="http://en.wikipedia.org/wiki/Law_of_Demeter">Law of Demeter</a> a předávejte do třídy je ty závislosti, které třída <strong>přímo</strong> potřebuje.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.augi.cz/programovani/unit-testy-a-globalni-stav/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Architektura aplikace podle DDD</title>
		<link>http://www.augi.cz/programovani/architektura-aplikace-podle-ddd/</link>
		<comments>http://www.augi.cz/programovani/architektura-aplikace-podle-ddd/#comments</comments>
		<pubDate>Sun, 13 Mar 2011 21:22:09 +0000</pubDate>
		<dc:creator>Augi</dc:creator>
				<category><![CDATA[Programování]]></category>

		<guid isPermaLink="false">http://www.augi.cz/?p=433</guid>
		<description><![CDATA[I když se o návrh architektury aplikací zajímám už nějaký ten pátek, stále si připadám jako bych byl na začátku &#8211; inu je to téma, které není vůbec jednoduché a postupem času se navíc komplikuje, jak se dostávají do popředí zájmu nové technologie (NoSQL, HTML5) nebo náhledy na věc (CQRS, messaging, pub/sub). Proto jsem se [...]]]></description>
			<content:encoded><![CDATA[<p>I když se o návrh architektury aplikací zajímám už nějaký ten pátek, stále si připadám jako bych byl na začátku &#8211; inu je to téma, které není vůbec jednoduché a postupem času se navíc komplikuje, jak se dostávají do popředí zájmu <em>nové</em> technologie (<a href="http://en.wikipedia.org/wiki/NoSQL">NoSQL</a>, <a href="http://en.wikipedia.org/wiki/HTML5">HTML5</a>) nebo náhledy na věc (<a href="http://cqrsinfo.com/">CQRS</a>, messaging, pub/sub). Proto jsem se rozhodl sepsat tento článek, který neberte jako dogma, ale jen jako soupis mých aktuálních myšlenek a chápání architektury aplikace, který by měl rozpoutat diskuzi. Nemyslím si, že by existoval jediný správný přístup, ale o to by mohla být naše diskuze zajímavější <img src='http://www.augi.cz/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
<span id="more-433"></span></p>
<h2>Vymezení pojmů</h2>
<p>Většina pojmů, které používám, vychází z <a href="http://en.wikipedia.org/wiki/Domain-driven_design">DDD</a>. Pokud se podíváme na aplikace <a href="http://en.wikipedia.org/wiki/Multitier_architecture#Three-tier_architecture">třívrstvýma očima</a>, je v tomto článku řeč především o prostřední vrstvě (business, doménové, logické, &#8230;) a možná částečně o nejnižší (datové) vrstvě (pokud do ní chceme zahrnout <a href="http://en.wikipedia.org/wiki/Data_access_layer">DAL</a>). Není vůbec řeč o prezentační vrstvě (<a href="http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller">MVC</a>, <a href="http://en.wikipedia.org/wiki/Model_View_Presenter">MVP</a>, <a href="http://docs.djangoproject.com/en/dev/faq/general/#django-appears-to-be-a-mvc-framework-but-you-call-the-controller-the-view-and-the-view-the-template-how-come-you-don-t-use-the-standard-names">MTV</a>, <a href="http://en.wikipedia.org/wiki/Model_View_ViewModel">MVVM</a>).</p>
<h2>Application Service</h2>
<p>Prezentační vrstva by měla komunikovat s <em>prostřední</em> vrstvou (tj. vlastní aplikací) přes <em>Application Service</em> (tak o ní mluví Eric Evans), což je jedno nebo více rozhraní a související <a href="http://en.wikipedia.org/wiki/Data_Transfer_Object">DTO</a>s (tedy něco snadno vystavitelného třeba jako WebService). Každá metoda tohoto rozhraní představuje jeden use-case a tedy logickou transakci. Implementace této vrstvy vypadá tak, že se pouze volá <em>Domain Model</em> (o tom více níže).<br />
Martin Fowler o této vrstvě mluví jako o <a href="http://martinfowler.com/eaaCatalog/serviceLayer.html">Service Layer</a> (rozkliknout &#8211; obsahuje důležitý obrázek!) a myslím, že s ním nejsem v rozporu.<br />
<em>Na tohle téma je můj názor ustálený, ale rád si přečtu i jiné pohledy na věc.</em></p>
<h2>Domain Model</h2>
<p>Vlastní jádro aplikace je ukryto v <em>Domain Model</em>u, což je vrstva, která by měla obsahovat veškerou logiku naší aplikace. Jak by měla ale taková vrstva vypadat?<br />
Klasický DDD přístup je ten, že by to měl být přirozený OO obraz naší aplikace, tj. měly by to být třídy, které nesou nejen data, ale obsahují také chování (<em>doménové metody</em>). Zde vzniká problém, že u některých metod může být složité rozhodnout, ve které třídě by měly být (třeba protože pracují s více entitami). Proto se zavádí pojem <a href="http://stochastyk.blogspot.com/2008/05/domain-services-in-domain-driven-design.html">Domain Service</a>, což je interface/třída, která obsahuje právě tyto <em>těžko umistitelné</em> metody. Zde se nabízí otázka, proč bychom měli tyto doménové servisy abstrahovat pomocí interfejsů, když jsou ve stejném <em>modulu</em>, který obsahuje doménové objekty, které také neabstrahují své metody. Jediná rozumná odpověď, která mě napadá, je testování.</p>
<p>Na výše popsaném klasickém přístupu se mi nelíbí to, že některé metody jsou přímo v entitách a některé v doménových servisách. Zde máme vzásadě dvě (extrémní) řešení:<br />
1) Budeme se snažit namodelovat naší doménovou vrstvu takovým způsobem, abychom doménové servisy jednoduše nepotřebovali. To může vyústit v to, že budeme mít entity, které budou popisovat nějaký proces (což může být ok), v horším případě ve vytváření <em>umělých</em> entit (de facto tedy doménových servis).<br />
2) Veškerou doménovou logiku přesuneme do doménových servis a z entit nám tak vzniknou jen schránky na data a budeme tak mít <a href="http://martinfowler.com/bliki/AnemicDomainModel.html">anemický doménový model</a>. Jak moc tento název zní nezdravě a mluví se o něm jako o anti-patternu, tak i tento postup může být pro specifickou doménu to nejlepší řešení. Doménové servisy jsou pak vlastně kontejnery na <a href="http://martinfowler.com/eaaCatalog/transactionScript.html">transakční skripty</a>. Sice se tím zřekneme jedné z hlavní myšlenek OOP (že data a chování by měly být u sebe) a de facto se tím <em>vrátíme</em> k procedurálnímu programování, ale nemyslím si, že je to vyloženě špatně.</p>
<p><em>Co vy na to? Považujete anemický model za zhůvěřilost nehodnou života v 21. století? <img src='http://www.augi.cz/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </em></p>
<h2>Persistence</h2>
<p>Schopnost ukládat a načítat data z nějakého úložiště se abstrahuje do <a href="http://martinfowler.com/eaaCatalog/repository.html">Repository</a> a slouží tedy k abstrakci úložiště od domény. Co by měla taková repozitory obsahovat? Asi by tu měly být nějaké metody pro načtení a uložení objektu&#8230;ale jaké konkrétně? Základní <a href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</a> operace jsou asi samozřejmostí, ale co složitější dotazy? Upřednostňujete <a href="http://besnikgeek.blogspot.com/2010/08/specification-pattern-versus-query.html">Specification, Query Object</a> nebo <a href="http://systemfutures.spaces.live.com/Blog/cns!AD5058A4F6569231!242.entry?wa=wsignin1.0&#038;sa=330972865">explicitní metody</a> pro každý dotaz? <em>Co je váš favorit?</em></p>
<p>A co dotazy reportovacího charakteru? Já bych je dal do read-only <em>QueryRepository</em> &#8211; z hlediska <a href="http://cqrsinfo.com/">CQRS</a> to není nutné, ale IMHO je to velmi vhodné.</p>
<p>A jak by měly vypadat implementace běžných repositories? Pokud pracujeme proti relační databázi, tak je myslím nabíledni použít nějaký DAO, typicky objektově-relační mapper.<br />
Protože repositories vytváří doménové objekty, je třeba vyřešit ještě jednu důležitou věc &#8211; tyto objekty mohou mít nějaké závislosti a ty je třeba do těchto objektů nějak dostat. Měla by tedy repository injectovat závislosti do doménových objektů? Nebo by měla tento úkol delegovat na nějakou <em>Factory</em>? Pak ale potřebujeme od DAO, aby nám umožnila řídit vytváření instaní objektů, což nemusí být samozřejmostí&#8230;<br />
<em>Co myslíte, kdo by měl zajišťovat injektování závislostí do doménových objektů? A jaké závislosti vůbec mohou v doménových objektech být?</em></p>
<p>Kapitola sama pro sebe jsou transakce a <a href="http://martinfowler.com/eaaCatalog/unitOfWork.html">Unit Of Work</a>. Jak jsem psal v úvodu, tak do jedné transakce bych strčil celou metodu aplikační servisy &#8211; pak není problém si naijectovat <em>transakční objekt</em> nebo <em>UnitOfWork</em> do implementace repository.</p>
<h2>Shrnutí</h2>
<p>V článku jsem se snažil popsat svůj pohled na návrh architektury aplikace, přičemž jsem velmi ovlivněn DDD. Při uvádění těchto principů do praxe jsem přirozeně narazil na několik <em>záseků</em> &#8211; ať už kvůli mé neznalosti nebo nepochopení, tak kvůli nejednoznačnosti (existuje více správných cest, každá vhodná v jiné situaci). V textu jsem explicitně vypíchnul jen pár otázek, ale budu rád, když mě opravíte/poučíte i v něčem jiném <img src='http://www.augi.cz/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.augi.cz/programovani/architektura-aplikace-podle-ddd/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>Closures v C#</title>
		<link>http://www.augi.cz/programovani/closures-v-c/</link>
		<comments>http://www.augi.cz/programovani/closures-v-c/#comments</comments>
		<pubDate>Sat, 08 Jan 2011 18:52:20 +0000</pubDate>
		<dc:creator>Augi</dc:creator>
				<category><![CDATA[Programování]]></category>

		<guid isPermaLink="false">http://www.augi.cz/?p=432</guid>
		<description><![CDATA[Často opomíjenou, o to zajímavější a užitečnější, vlastností jazyka C# je podpora closures. A co že to vlastně closure (uzávěr) je? Wikipedie říká, že je to first-class function s volnými proměnnými, které jsou vázány k lexikálnímu prostředí. A co že to tedy je? Začněme tím, co je to first-class function (vhodný český překlad neznám). Mezi [...]]]></description>
			<content:encoded><![CDATA[<p>Často opomíjenou, o to zajímavější a užitečnější, vlastností jazyka C# je podpora closures. A co že to vlastně <a href="http://en.wikipedia.org/wiki/Closure_(computer_programming)">closure</a> (uzávěr) je? Wikipedie říká, že je to <strong><em>first-class function</em> s volnými proměnnými, které jsou vázány k lexikálnímu prostředí</strong>. A co že to tedy je? <img src='http://www.augi.cz/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
<span id="more-432"></span><br />
Začněme tím, co je to <em>first-class function</em> (vhodný český překlad neznám). Mezi námi programátory &#8211; není to nic jiného než obyčejný ukazatel na funkci. To znamená, že s funkcí můžeme pracovat jako s jakoukoliv jinou proměnnou &#8211; přiřazovat do ní, předávat si ji jako parametry&#8230;<br />
Možná vám přijde zbytečné, že se takový pojem vůbec zavádí, ale některé jazyky (třeba Java) ukazatel na funkci nemají. To ale nesnižuje vyjadřovací schopnost takového jazyka a stejné konstrukce jako s pomocí <em>first-class function</em> lze zapsat i jinak, jak je ukázáno např. <a href="http://csharpindepth.com/Articles/Chapter5/Closures.aspx">v tomto výborném článku</a> z knihy <em>C# in Depth</em>. V C# máme ale <em>first-class function</em> dostupné jako delegáty.</p>
<p><strong>Closure si tedy můžeme představit jako delegáty, které si sahají někam mimo své tělo, čímž do delegáta vnáší kontext prostředí, ve kterém byly vytvořeny.</strong></p>
<h2>Anonymní metody</h2>
<p>Do verze C# 2.0 jsme sice měli k dispozici delegáty, ale mohli jsme do nich přiřazovat jen celé metody. </p>
<pre class="brush: csharp">public class Test
{
  public delegate string TestDelegate(int i); // deklarace typu

  static string Test(int i)
  {
    return i.ToString();
  }

  public static void Main()
  {
    TestDelegate d = new TestDelegate(Test);
    // nebo TestDelegate d = Test;
    Console.WriteLine(d(1));
  }
}</pre>
<p>Od C# 2.0 byly ale zavedeny anonymní metody, což je konstrukt, který nám umožní vytvořit metodu uvnitř jiné metody.</p>
<pre class="brush: csharp">public class Test
{
  public delegate string TestDelegate(int i); // deklarace typu
  // to same jako Func&lt;int, string>

  public static void Main()
  {
    TestDelegate d = delegate(int i) { return i.ToString(); };
    Console.WriteLine(d(1));
  }
}</pre>
<p>No a konečně od C# 3.0 máme k dispozici lambda funkce:</p>
<pre class="brush: csharp">public class Test
{
  public static void Main()
  {
    Func&lt;int, string> d = i => { return i.ToString(); };
    Console.WriteLine(d(1));
  }
}</pre>
<p>Pokud máme v těle anonymní metody jen jeden příkaz, můžeme si odpustit i složené závorky:</p>
<pre class="brush: csharp">public class Test
{
  public static void Main()
  {
    Func&lt;int, string> d = i => i.ToString();
    Console.WriteLine(d(1));
  }
}</pre>
<p>A nyní se podívejme Reflectorem, co nám leze z kompilátoru:</p>
<pre class="brush: csharp">public class Test
{
  [CompilerGenerated]
  private static string &lt;Main>b__0(int i)
  {
    return i.ToString();
  }

  public static void Main()
  {
    Func&lt;int, string> d = new Func&lt;int, string>(Test.&lt;Main>b__0));
    Console.WriteLine(d(1));
  }
}</pre>
<p>Vidíme, že kompilátor udělal prakticky to samé, co jsme museli dělat ručně do příchodu C#2.0 &#8211; tedy vyextrahoval tělo do nové metody.<br />
Jen jsem z originálního kódu odstranil cachování, které zajišťuje, aby se při vícenásobném volání nemusel neustále vytvářet stejný objekt <em>Func&lt;int, string></em>.</p>
<h2>Closures</h2>
<p>A teď zpátky ke closures, tedy delegátům, které si sahají mimo své tělo. Všimněte si, že to výše uvedené příklady nedělaly &#8211; pracovaly jen se svými parametry. Další příklad ale closure již obsahuje:</p>
<pre class="brush: csharp">public class Test
{
  public static void Main()
  {
    string prefix = GetPrefix();
    Func&lt;int, string> d = i => prefix + i.ToString();
    Console.WriteLine(d(1));
  }
}</pre>
<p>Nyní máme proměnnou <em>prefix</em>, na kterou si saháme z těla delegáta do nadřazené metody.<br />
Důležité je si uvědomit, že s delegátem <em>d</em> můžeme dělat cokoliv, tj. třeba ho vrátit jako návratovou hodnotu nebo ho někam uložit &#8211; tedy životnost delegáta může být delší než život lokální proměnné metody. Jak se s tímto vypořádal kompilátor?</p>
<pre class="brush: csharp">public class Test
{
  [CompilerGenerated]
  private sealed class &lt;>c__DisplayClass1
  {
    public string prefix;
    public string &lt;Main>b__0(int i)
    {
       return (this.prefix + i.ToString());
    }
  }

  public static void Main()
  {
    &lt;>c__DisplayClass1 CS$&lt;>8__locals2 = new &lt;>c__DisplayClass1();
    CS$&lt;>8__locals2.prefix = GetPrefix();
    Func&lt;int, string> d = new Func&lt;int, string>(CS$&lt;>8__locals2.&lt;Main>b__0);
    Console.WriteLine(d(1));
  }
}</pre>
<p>Proměnná <em>prefix</em> nemůže být v tomto případě nadále lokální proměnnou (umístěnou na stacku), ale je třeba ji umístit do pomocné, automaticky vygenerované třídy. Spolu s lokální proměnnou <em>prefix</em> se do ní přesunula i anonymní metoda. Instance této třídy je vytvořena při každém volání metody <em>Main</em>.<br />
Automaticky vygenerovaná třída <em>&lt;>c__DisplayClass1</em> je tedy jakýmsi zhmotněním pojmu closure (uzávěr) <img src='http://www.augi.cz/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<h2>Vhnízděné closures</h2>
<p>Začněme složitejším příkladem &#8211; vytvoříme pole delegátů, kde každý delegát vrátí jedno číslo:</p>
<pre class="brush: csharp">public class Test
{
  public static void Main()
  {
    var delegates = new Func&lt;string>[5];
    for(int i = 0; i &lt; delegates.Length; i++)
    {
      delegates[i] = () => i.ToString();
    }
    foreach(var d in delegates)
    {
      Console.WriteLine(d());
    }
  }
}</pre>
<p>Tento kód nefunguje tak, jak by se mohlo na první pohled zdát. Nevypíšou se totiž čísla 0 až 4, ale vypíše se pěkrát číslo 5. Lokální proměnná <em>i</em> je totiž takto deklarována se scopem na celé metodě. A jak jsme si ukázali, delegáti mají živou vazbu na lokální proměnné, takže v okamžiku, kdy je voláme z <em>foreach</em> cyklu, pracují s aktuální hodnotou proměnné <em>i</em>.<br />
Pokud chceme, aby kód pracoval podle našich představ (tj. vypsal čísla 0 až 4), musíme zajistit, aby si tělo delegátu sahalo na proměnnou, která se nebude dále měnit:</p>
<pre class="brush: csharp">public class Test
{
  public static void Main()
  {
    var delegates = new Func&lt;string>[5];
    for(int i = 0; i &lt; delegates.Length; i++)
    {
      var scopedI = i;
      delegates[i] = () => scopedI.ToString();
    }
    foreach(var d in delegates)
    {
      Console.WriteLine(d());
    }
  }
}</pre>
<p>Zavedli jsme pomocnou proměnnou <em>scopedI</em>, která již nemá scope na celé metodě, ale je deklarována na úrovni bloku. Můžeme si to tedy představit tak, že proměnná <em>scopedI</em> vznikne znovu při každém vstupu do bloku (v našem případě do těla <em>for</em> cyklu). A co na to kompilátor?</p>
<pre class="brush: csharp">public class Test
{
  [CompilerGenerated]
  private sealed class &lt;>c__DisplayClass1
  {
    public int scopedI;
    public string &lt;Main>b__0()
    {
        return this.scopedI.ToString();
    }
  }
  public static void Main()
  {
    var delegates = new Func&lt;string>[5];
    for (int i = 0; i &lt; delegates.Length; i++)
    {
        &lt;>c__DisplayClass1 CS$&lt;>8__locals2 = new &lt;>c__DisplayClass1();
        CS$&lt;>8__locals2.scopedI = i;
        delegates[i] = new Func&lt;string>(CS$&lt;>8__locals2.&lt;Main>b__0);
    }
    foreach (var d in delegates)
    {
        Console.WriteLine(d());
    }
  }
}</pre>
<p>Jak vidno, kompilátor správně detekoval, že je třeba vytvořit instanci pomocné třídy (držící hodnotu lokální proměnné) v každé iteraci cyklu. Delegát opět ukazuje na metodu v nově vytvořené instanci.</p>
<p>Předchozí příklady byly příprava pro <em>la grande finale</em> &#8211; vhnízděné closures. Nejzajímavější kód totiž kompilátor vygeneruje, když máme více vnořených bloků:</p>
<pre class="brush: csharp">public class Test
{
  public static void Main()
  {
    string prefix = GetPrefix();
    var delegates = new Func&lt;string>[5];
    for(int i = 0; i &lt; delegates.Length; i++)
    {
      var scopedI = i;
      delegates[i] = () => prefix + scopedI.ToString();
    }
    foreach(var d in delegates)
    {
      Console.WriteLine(d());
    }
  }
}</pre>
<p>Opět se zaměřme hlavně na tělo delegáta. To si nyní nesahá na vnitřní closure, obhospodařující lokální proměnnou <em>scopedI</em>, ale sahá i o blok výše &#8211; na proměnnou <em>prefix</em>.</p>
<pre class="brush: csharp">public class Test
{
  [CompilerGenerated]
  private sealed class &lt;>c__DisplayClass1
  {
    public string prefix;
  }

  [CompilerGenerated]
  private sealed class &lt;>c__DisplayClass3
  {
    public Test.&lt;>c__DisplayClass1 CS$&lt;>8__locals2;
    public int scopedI;
    public string &lt;Main>b__0()
    {
        return (this.CS$&lt;>8__locals2.prefix + this.scopedI.ToString());
    }
  }

  public static void Main()
  {
    &lt;>c__DisplayClass1 CS$&lt;>8__locals2 = new &lt;>c__DisplayClass1();
    CS$<>8__locals2.prefix = GetPrefix();
    var delegates = new Func&lt;string>[5];
    for (int i = 0; i &lt; delegates.Length; i++)
    {
      &lt;>c__DisplayClass3 CS$&lt;>8__locals4 = new &lt;>c__DisplayClass3();
      CS$&lt;>8__locals4.CS$&lt;>8__locals2 = CS$&lt;>8__locals2;
      CS$&lt;>8__locals4.scopedI = i;
      delegates[i] = new Func&lt;string>(CS$&lt;>8__locals4.&lt;Main>b__0);
    }
    foreach (Func&lt;string> d in delegates)
    {
      Console.WriteLine(d());
    }
  }
}</pre>
<p>Jak vidno, kompilátor se s nastalou situací hrdinně vypořádal. Vytvořil si pomocnou třídu, která obsahuje lokální proměnné deklarované na úrovni celé metody. Stejně jako v předchozích příkladech si vytvořil další pomocnou třídu, která se stará o proměnné deklarované v těle cyklu. A to nejdůležitější &#8211; tato třída obsahuje odkaz na první jmenovanou (viz přiřazení na druhém řádku v cyklu).</p>
<h2>Shrnutí</h2>
<p>Kompilátor C# od verze 2.0 nabízí možnost sahat si z anonymních metod (resp. lambda funkcí) mimo jejich tělo &#8211; podporuje tzv. closures. Ty jsou implementovány celkem přímočaře &#8211; každý uzávěr je reprezentovaný pomocnou třídou a při každém vstupu do bloku je vytvořena instance odpovídající pomocné třídy (reprezentující closure).<br />
Je to vlastnost, bez které bychom se jistě dokázali v jazyce obejít, ale mít možnost zanést do delegáta kontext prostředí, ve kterém vznikl, je velmi užitečný a překvapivě častý. Např. i tento, na první pohled primitivní kód, využívá closures!</p>
<pre class="brush: csharp">public class Test
{
  public static void Main()
  {
    var toShow = int.Parse(Console.ReadLine());
    foreach(var number in GetArray().Where(i => i == toShow))
    {
      Console.WriteLine(number);
    }
  }
}</pre>
<p>P.S.: Na toto téma jsem <a href="http://www.augi.cz/programovani/variable-scope-v-lambda-expressions-v-c-30/">již blogoval</a>, ale tentokrát jsem to chtěl vzít trošku podrobněji.</p>
<p><script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js"></script><br />
	<script type="text/javascript" src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCSharp.js"></script></p>
<link type="text/css" rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/current/styles/shCore.css"/>
<link type="text/css" rel="stylesheet" href="http://alexgorbatchev.com/pub/sh/current/styles/shThemeDefault.css"/>
<p>	<script type="text/javascript">
		if (SyntaxHighlighter) {
			SyntaxHighlighter.all();
		}
	</script></p>
]]></content:encoded>
			<wfw:commentRss>http://www.augi.cz/programovani/closures-v-c/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>

