První kroky při tvorbě webové aplikace

November 9th, 2010

Jelikož se v posledních dnech na českém internetu rozjela debata (zde, zde a nebo třeba zde), zda je lepší Doctrine 2, nebo NotORM Jakuba Vrány, rozhodl jsem se udělat menší průzkum. Měl mi ukázat ukázat první kroky, které podnikáme, programujeme-li novou webovou aplikaci, neb si myslím, že odpověď na výše zmíněnou otázkou s tím velice úzce souvisí. Otázka zněla: “Když začnu programovat novou webovou aplikaci, udělám napřed…” a měla tři možnosti:

  1. Udělám databázové schéma
  2. Začnu programovat třídy entit
  3. Něco jiného

Důležité pro mne byly první dvě možnosti. Třetí jsem zařadil pouze ze zvědavosti a také kvůli tomu, aby někdo neměl pocit, že ho do něčeho tlačím.

Proč právě tyto možnosti?

Inu, to máte tak. Ještě před pár měsíci, když mi někdo začal vykládat problém, který by aplikace měla řešit, mi jako první věc v hlavě šrotovalo: “Jo, tak to bude tahle tabulka, tohle rozložíme do vazby m:n, tohle, tohle bude odkazovat samo na sebe…”, a tak dále a tak dále. Nicméně, pak přišla změna. Nevím, kdy nebo kde to přesně začalo, ale nejintenzivnější to bylo na jaře 2010, kdy jsme v Mediu hodně debatovali o tom, jak řešit modelovou část v MVC. V tu dobu jsem se dozvěděl, že existuje nějaké DDD, že existují entity a že se celý model dá velice hezky vrstvit (tedy, to jsem už nějakou dobu věděl, ale tápal jsem mnohem více než tápu nyní :-)).

Když nad tím nyní přemýšlím, byl to přesně ten okamžik, kdy se ve mně zlomil názor, že přemýšlet jako první o rozložení modelu do databázových relací, je naivní, protože to není v danou chvíli vůbec podstatné. Mnohem důležitější je přemýšlet jak vyrobit kód, který na základě zpodobnění věcí z reálného světa začne řešit problémy uživatele. A to, jestli budeme ukládat data do nějaké (relační) databáze, to mi může být zatím jedno.

Jaké jsou výsledky

Po několika hodinách jsou výsledky následující:

  • 53% – nejdříve dělá databázové schéma
  • 31% – začne psát třídy entit
  • 16% – dělá něco jiného

Hlasovalo celkem 62 lidí (díky všem hlasujícím). Myslím, že pro základní zorientování nám to postačí. Nepředpokládám, že by se procenta ještě nějak zásadně hýbala. Pokud vás zajímá konkrétní podoba třetích odpovědí, podívejte se na výsledky, stejně tak tam naleznete nejaktuálnější výsledky.

Jak si výsledky interpretuji já a jak to souvisí s naší ORM otázkou

Jak jsem již napsal, myslím, že souvisí úzce. Z mého pohledu se totiž Doctrine 2 výborně hodí pro situaci, kdy dostanu problém a chci ho začít řešit tak, že po úvodním rozmyšlení začnu psát přes testy prototypové třídy. Na způsob persistování stavů objektů myslet nemusím, protože to mi Doctrine nějak zajistí. Ti odvážnější se dokonce mohou spolehnout na automatické generování SQL přímo z entit :-). Teď se chci soustředit na to, jak vyřešit doménu problému.

První možnost mi naopak přijde jako překonaná. Soustředění se na tvorbu databáze je v tuto chvíli plýtvání energií. Důležité je co nejdříve vyřešit problémy, se kterými za námi zadavatel přišel, ne je rozkládat do nějakých tabulek.

Nechci, aby to vypadalo, že prohlašuji, že NotORM nabádá stavět se k tvorbě aplikací překonaným způsobem. Na to NotORM neznám dostatečně dobře (ostatně otázka neznalosti jednoho či druhého je zde asi ten nejzásadnější problém, dokud nepřijde někdo nestranný a dostatečně fundovaný, budeme se přít donekonečna) a věřím, že Jakub bude mít v každém rukávu hromadu důkazům že to tak není. Z ukázek na webu NotORM mi ale přišlo, že nevede programátory k tomu, aby začali psát nějaké entity a nestarali se o podobu dat v databázi. Přišlo mi, že se spíš hodí na řešení menších problémů pomocí tzv. transakčních skriptů. Transakční skripty jsou efektivní na malé problémy, nebo lépe řečeno na problémy u menších aplikací či v menším (cca 1 – 2 soudím) týmu programátorů. Ve svých prasárnách se každý přeci vyzná :-)

Na závěr zbývá uvést několik věcí na pravou míru

Napsal jsem, že mi přijde správné, že se člověk nemusí starat o podobu uložení dat v databázi. Pokud mne někdo trochu znáte, tak možná víte, že občas žehrám na to, že většina webových programátorů nerozumí databázím (respektive SQL) a že se v tomhle ohledu musí ještě hodně co učit (včetně mne). To, že mi ORM dává možnost soustředit se napřed na doménové problémy mi ale nepřijde jako rozpor. Na optimalizaci dat uložených v databázi bude ještě spousta času. Stejně většinu problémů poznáte až za ostrého běhu a bude-li aplikace úspěšná, začnou problémy přicházet stejně rychle jako bude růst počet aktivních uživatelů.

Stejně tak často říkám, že ORM jsou neefektivní co do alokace systémových prostředků. Ano, opravdu jsou. Zde z mého pohledu ale také nejsem v rozporu sám se sebou. Jsou typy aplikací, u kterých vím, že mi ORM přinese více problémů než-li užitku, takže na něj rovnou zapomenu a začnu entity stavět nad nějakou jednodušší databázovou vrstvou. O těch zde ale nepíši, vetšinou je jich méně než těch malých a středně velkých, na které ORM stačí.

A v neposlední řadě věřím v to, že je Jakubovo NotORM po výkonnostní stránce někde jinde, než je Doctrine 2.

I přesto ale můj palec nahoru míří k Doctrine 2, protože je to ona, kdo mi umožní rychle psát v duchu DDD jednotlivé vrstvy modelu.

Tags: , , ,
Posted in Uncategorized | 6 Comments »

Architektura Doctrine 2

May 16th, 2010

Pozor, článek je notně zastaralý a prozatím jsem nenašel čas ho zrevidovat. Berte prosím zde prezentované informace s rezervou. Pokud byste se rádi dozvěděli více informací o Doctrine 2, přečtěte si seriál Doctrine 2 od Jana Tichého.

Rád bych ukázal základní stavební kameny PHP ORM nástroje Doctrine 2 a srovnal je s 5-ti vrstevným modelem, který představil Honza Tichý. Nebudu se zde věnovat databázové vrstvě (DBAL), kterou Doctrine používá a budu se snažit zaměřit více na vrstvy, které jsou blíže modelu. Stejně tak se nebudu snažit představit práci s Doctrine 2, která by vydala na několik samostatných článků. Použiji pouze to nejnutnější, pokud to bude potřeba.

Základní stavební kameny

V ORM Doctrine 2 nalezneme tyto základní členy:

  • Entity
  • Entity manager
    • Identit map
    • Unit of Work
  • Repository
  • Persister

Entity – entita doménového objektu

Entita v Doctrine 2 představuje libovolný doménový objekt. V případě klasického CMS to tedy může být například entita Article. Doctrine 2 nám absolutně nic nediktuje, což je její největší výhoda. Abychom naší třídu Article připravili na spolupráci s Doctrine, oanotujeme ji za pomocí konstrukce”@Entity”. Vypadá to takto:

/**
 * @Entity
 */
class Article
{
   /** ... */
   private $id;
   /** ... */
   private $title;
   /** ... */
   private $text;

   // Setters and getters
   ...
}

Entita má několik atributů, které odpovídají určitým sloupcům v určité tabulce. Z pohledu architektury je to ale nezajímavá věc, takže si to dovolím přeskočit. Zajímavější je možná to, že entita spolupracující s Doctrine 2 se může v aplikaci nacházet v různých stavech.

  • nová (new)
  • řízená (managed)
  • neřízená (detached)
  • odstraněná (removed)

Nová entita

Nová entita je taková entita, kterou jsme vytvořili a neřekli entity manageru, aby ji uložil. Pokud novou entitu nepředáme entity manageru pro uložení, změny v entitě provedené se nám neuchovají.

Řízená entita

Řízená entita je entita, která byla předána entity manager pro uložení do repozitáře, nebo již uložená entita, která byla z repozitáře načtena. Změny v této entitě se nám uloží.

Neřízená entita

Neřízená entita je taková entita, která je uložena v repozitáři, ale my jsme ji od něho odpojili. Změny, které v entitě provedeme, se nám neuloží a v příštím načtení dostaneme entitu ve stejném stavu, jak jsme ji dostali při aktuálním načtení.

Odstraněná entita

Odstraněná entita je entita, která byla řízená, ale my jsme se jí rozhodli odstranit z repositáře. Entita se vymaže.

Entity manager

Entity manager je ústřední část ORM. Je pouze jeden a obhospodařuje práci se všemi entitami přes jejich repozitáře. Samotný Entity manager se v Doctrine 2 skládá ze dvou částí.

Unit of Work

Tato část entity manageru má na starosti řízení SQL dotazů. Zajišťuje, že se příkazy nevykonávají hned, ale co nejpozději, což zajišťuje větší efektivitu v práci s databází. Jedná se o typickou implementaci vzoru Unit of Work.

Identity map

Implementace vzoru Identity map. Tato část zajišťuje to, že máme v entity manageru vždy pouze jednu instanci entity, což má hned několik výhod. Například to, že ne zbytečně neptáme vícekrát na jedno a to samé, nebo že si omylem nepřepisujeme data v případě, že bychom omylem vytvořili více instancí jedné entity. V reálu to tedy vypadá následovně:

$article = new Article();
$article->title = 'Foo';
$article->text = 'Big white bra.'
$em->persist($article); // Entity manager instance
...
...
...
$theSameArticle1 = $em->find('Article', $article->id);
$theSameArticle2 = $em->find('Article', $article->id);

Entity $theSameArticle1 a $theSameArticle2 jsou úplně to samé jako entita $article. Zde je dokonce pravděpodobné (v závislosti na tom, co ve ve vynechaném kódu), že vůbec neproběhla žádná komunikace s databází. Na začátku jsme sice $article uložili, ale jak jsme psal výše, Unit of Work nechává komunikaci s databází na co nejpozději, takže pokud mu to nikdo ještě neřekl pomocí metody flush, drží si data pouze v sobě a do databáze je odešle někde dál.

Repository – zdroj entit

Možná jste si všimli, že jsem několikrát psal o tom, že se entity načítají z repozitáře, ale já jsem entitu hledal v entity manageru. Pravdou je, že volání

$em->find('Article', $article->id);

je pouhou zkratkou k repozitáři, který si entity manager načítá. Opravdové volání by vypadalo nějak takto

$em->getRepository('Article')->find($article->id);

A co je to ten repozitář? Repozitář je zdroj entit. Můžeme si ho buď napsat sami, nebo můžeme využít výchozí repozitář, který nám Doctrine 2 nabízí. Ten se jmenuje EntityRepository. Pro většinu entit nám tento výchozí repozitář bude pravděpodobně stačit, ale občas je dobré napsat si vlastní repozitář pro nějakou entitu. V tomto nám Doctrine 2 nechává otevřená vrátka.

Persister – mapovač entit

Persister je o úvroveň nižší vrstva než repozitář, která slouží k namapování (přes anotace, XML, nabo YAML) dat na atributy entity. Persistory jsou jádrem ORM a ve většině případů se s nimi nesetkáme. Je ale dobré vědět, jaká část ORM přebírá mapovací konfiguraci a pracuje s ní.

Zhodnocení architektury Doctrine 2 s ohledem na HoTův 5-ti vrstesný model

Možná znáte článek Honzy Tichého, ve kterém píše o 5-ti vrstevném modelu. S dovolením si vypůjčím jeho obrázek. Model je rozvrstvený takto:

Model podle Doctrine 2 je rozvrstvený takto:


Ze schémat můžeme vidět, že se modely nijak výrazně neliší, právě naopak. Pět vrstev modelu nám zůstalo zachováno  a navíc jsme dostali vylepšenou komunikaci s databází (přes Unit of Work a Identity map), která částečně vynahradí fakt, že ORM SQL dotazy generuje, což se často negativně podepisuje na výkonu.

Externí odkazy

Tags: , ,
Posted in Uncategorized | Comments Off

Zápisky z přednášky: Productive and Scalable Software Engineering

April 28th, 2010

Dnes jsem se byl podívat v nové Národní technické knihovně na zajímavou přednášku s názvem Productive and Scalable Software Engineering, kterou pořádala GUG při ČVUT.

Následují mé poznámky, které jsem si během přednášky udělal.

Jak se k projektu postavit

  • Aby byl projekt úspěšný, programátoři mu musejí věřit. Pokud programátoři nevěří v jeho úspěch, projekt s největší pravděpodobností skončí krachem.
  • Při vývoji bychom měli klást důraz na malé iterace.

Ideální velikost týmu

  • 3-9 vývojářů pracujících na středně velkém projektu, nebo větší komponentě.
  • <5 vývojářů na jedné komponentě.

Metodiky

  • Vodopád je dobrý leda tak kvůli tomu, že byl jako první zdokumentován. Je to klasické Plan driven.
  • Spirála dělí projekt na části, nad kterými probíhají iterace. Je to v podstatě několikanásobný vodopád.
  • Agilní vývoj je souborem metodik (např. Test Driven Development, Behavior Driven Development, Pair Programming, Planning Poker, RITE method). Ještě menší predikce budoucnosti. Je to adaptivní přístup, snažíme se přizpůsobit aktuálním podmínkám.

SCRUM

  • Procesní kostra použitelná i na jiné situace než je vývoj softwaru.
  • Úkol by měl zabrat maximálně 2 – 3 dny. Pokud zabere více, vystavujeme se riziku, protože člověk přestává ztrácet koncentraci na podstatu problému.
  • Google neprovozuje plnohodnotný SCRUM, ale používají agilní přístup a jejich vývoj je agilní.
  • V Googlu mají maximálně 1 měsíční iterace. Delší jsou výjimkou.
  • Některé týmy na ranním stand-upu stojí pouze na jedné noze, aby schůzka trvala ještě kratší dobu.
  • Obecně se Google snaží spíše adaptovat na aktuální situaci, než že by dlouhodobě plánoval.

Test Driven Development

  • Ušetří plno času stráveného na debuggerem.
  • 100% code coverage toho ještě moc neznamená. Občas vývojáři kompletně pokrývají kód testy za příliš velkou cenu.
  • Unit testy nám mohou dát falešný pocit toho, že je aplikace bezpečná.
  • Po nějaké době je dobré dělat revizi testů.

Jak to dělá Google

  • Nemají oddělené programátory od QA. Místo toho tam mají takovou smíšenou strukturu.
  • Obecně se vývojáři dělí na programátor, testery a maintainery běžících aplikací.
  • Projekty jsou ohodnocené podle obtížnosti na stupnici 0 – 5.
  • Pokud chce člověk dělat na nějakém projektu, musí mít minimálně příslušnou kvalifikaci.
  • Kvalifikace se dá zvýšit tak, že se člověk učí využívat potřebné nástroje a postupy.
  • Google je tvořen z velkého počtu malých týmů (AFAIK to takhle funguje i v Seznamu).
  • Žádný řádek kódu neprojde dál, dokud si ho neprohlédne ještě někdo další.

Debugging

  • Hodně zajímavých věcí napsal Andreas Zeller. Například “Why programs fail”.
  • Propagace automatického debuggingu.
  • Delta debugging.
  • Pokud nám nějaké změna způsobila chybu/chyby v testech, musíme hledat minimální změnu, která nám chybu způsobí a chybu opravit.

Na závěr ještě dodám, že výše napsané body jsou pouze mé zápisky z jedné přednášky jednoho člověka, který pracoval ve Skypu a nyní pracuje v Googlu. Poznámky nemají za cíl shrnout problematiku odvětví, do kterých spadají.

Tags: , ,
Posted in Uncategorized | 257 Comments »