<?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/"
	>

<channel>
	<title>Jiří Hradil blog</title>
	<atom:link href="http://www.hradil.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.hradil.org</link>
	<description>o software</description>
	<pubDate>Sun, 08 May 2011 16:35:53 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Desatero pro vývoj software</title>
		<link>http://www.hradil.org/desatero-pro-vyvoj-software/</link>
		<comments>http://www.hradil.org/desatero-pro-vyvoj-software/#comments</comments>
		<pubDate>Sun, 08 May 2011 16:35:53 +0000</pubDate>
		<dc:creator>Jiří Hradil</dc:creator>
		
		<category><![CDATA[Nezařazené]]></category>

		<guid isPermaLink="false">http://www.hradil.org/?p=377</guid>
		<description><![CDATA[1. Ideální software je takový, který neexistuje.
2. Pokud existuje, ať není vidět.
3. Pokud je vidět, ať v něm pracují jen roboti.
4. Pokud v něm musí pracovat člověk, ať tam tráví minimum času s maximální efektivitou.
5. Minimum času musí být zábava.
6. Časem rozumíme vteřiny, největší jednotkou budiž minuty.
7. Efektivitou budiž chytrost.
8. Software pomáhá, software neotravuje. Ani [...]]]></description>
			<content:encoded><![CDATA[<p>1. Ideální software je takový, který neexistuje.<br />
2. Pokud existuje, ať není vidět.<br />
3. Pokud je vidět, ať v něm pracují jen roboti.<br />
4. Pokud v něm musí pracovat člověk, ať tam tráví minimum času s maximální efektivitou.<br />
5. Minimum času musí být zábava.<br />
6. Časem rozumíme vteřiny, největší jednotkou budiž minuty.<br />
7. Efektivitou budiž chytrost.<br />
8. Software pomáhá, software neotravuje. Ani člověka, ani robota.<br />
9. Pokud software otravuje, nesmí existovat.<br />
10. Pokud nechápeme některé z pravidel, držme se pouze pravidla č. 1 a raději nic nepišme.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hradil.org/desatero-pro-vyvoj-software/feed/</wfw:commentRss>
		</item>
		<item>
		<title>CZJUG: Ruby on Rails: zapomeňte na Javu</title>
		<link>http://www.hradil.org/czjug-ruby-on-rails-zapomente-na-javu/</link>
		<comments>http://www.hradil.org/czjug-ruby-on-rails-zapomente-na-javu/#comments</comments>
		<pubDate>Sun, 13 Mar 2011 19:44:20 +0000</pubDate>
		<dc:creator>Jiří Hradil</dc:creator>
		
		<category><![CDATA[Nezařazené]]></category>

		<guid isPermaLink="false">http://www.hradil.org/?p=373</guid>
		<description><![CDATA[
]]></description>
			<content:encoded><![CDATA[<p><iframe title="YouTube video player" width="480" height="390" src="http://www.youtube.com/embed/eOdSO1sk3mA" frameborder="0" allowfullscreen></iframe></p>
]]></content:encoded>
			<wfw:commentRss>http://www.hradil.org/czjug-ruby-on-rails-zapomente-na-javu/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Fulltext v Ruby on Rails a Apache Solr</title>
		<link>http://www.hradil.org/fulltext-v-ruby-on-rails-a-apache-solr/</link>
		<comments>http://www.hradil.org/fulltext-v-ruby-on-rails-a-apache-solr/#comments</comments>
		<pubDate>Sat, 02 Oct 2010 11:33:05 +0000</pubDate>
		<dc:creator>Jiří Hradil</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.hradil.org/?p=352</guid>
		<description><![CDATA[Fulltextové vyhledávání je příkladem technologie, kterou řešíme téměř v každé aplikaci. Požadavky a vize systému určují složitost celého řešení a naším cílem je použít nejjednodušší možné řešení.
Pro jednoduché a zlehka používané aplikace můžeme &#8220;fulltext&#8221; řešit jednoduchými SQL dotazy typu &#8220;SELECT * FROM contacts WHERE name LIKE &#8216;neco%&#8217;&#8221;, což není žádná ostuda, pokud to aplikaci a [...]]]></description>
			<content:encoded><![CDATA[<p>Fulltextové vyhledávání je příkladem technologie, kterou řešíme téměř v každé aplikaci. Požadavky a vize systému určují složitost celého řešení a naším cílem je použít nejjednodušší možné řešení.</p>
<p>Pro jednoduché a zlehka používané aplikace můžeme &#8220;fulltext&#8221; řešit jednoduchými SQL dotazy typu &#8220;SELECT * FROM contacts WHERE name LIKE &#8216;neco%&#8217;&#8221;, což není žádná ostuda, pokud to aplikaci a klientovi stačí.</p>
<p>Pokud tvoří fulltext páteř našeho systému, nebo máme požadavky na vyhledávání typu &#8220;chceme synonyma&#8221;, &#8220;váhy&#8221;, &#8220;vyhledávat v obsahu dokumentů&#8221; a nám se nepodaří klienta přesvědčit, že to opravdu nepotřebuje, musíme použít skutečný fulltext, čímž si zajistíme práci na několik týdnů či měsíců. Kvalitní fulltextové vyhledávání je složitý problém, který je vždy o kompromisech.</p>
<p>Nejdříve doporučuji zkusit fulltext, který nabízí přímo relační databáze. Například v PostgreSQL je to modul <a href="http://www.postgresql.org/docs/8.4/static/textsearch.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.postgresql.org');">TSearch</a>, který je od verze 8.3 přímo součástí databáze a nemusí se instalovat externě. TSearch lze nakonfigurovat tak, aby používal české a slovenské slovníky z Open Office, řešil stemování (převod slova na kořen), stoplist, apod. Integrace s databází nám zároveň vyřeší spoustu nepříjemných problémů jako přístupová práva k objektům (chci vyhledat pouze dokumenty, ke kterým má určitý uživatel právo), stabilitu, nezávislost na další vrstvě, testování, apod. Konkrétně s TSearch mám vynikající zkušenosti. Pokud můžete a neočekáváte mnoho, použijte databázový fulltext.</p>
<p>Jestliže potřebujeme vyhledávání dle částí slov, wildcards na začátku či na konci, podrobné váhy, n-gramy, škálování, distribuované vyhledávání, zřejmě musíme použít externí řešení a náš fulltext delegovat na něj. Google je nám tady vhodnou inspirací, ke které se můžeme blížit.</p>
<p>Přestože jsem railsista, jsem také javista, takže znám <a href="http://lucene.apache.org/java/docs/index.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/lucene.apache.org');">Apache Lucene</a>. Perfektní a enormně složitá technologie, jejíž ovládnutí sice znamená několik měsíců těžkého studia, ale dokážete z ní těžit několik let. Na vlastní implementaci v Lucene zapomeňme, je to objevování kola a zbytečná práce. Pokud chceme řešení v Javě a používáme Hibernate, pak vřele doporučuji <a href="http://www.hibernate.org/subprojects/search.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.hibernate.org');">Hibernate Search</a>, který jsem <a href="http://www.hradil.org/hibernate-search-fulltext-nad-hibernate-orm/" onclick="">zkusil se skvělými výsledky</a>.</p>
<p>HTTP servletem nad Lucene je <a href="http://lucene.apache.org/solr/" onclick="javascript:pageTracker._trackPageview('/outbound/article/lucene.apache.org');">Apache Solr</a>, skvělá technologie, která nás odstíní od složité práce se samotným Lucene a s indexem pracuje přes HTTP požadavky. Protože HTTP lze použít snad z každého normálního jazyka, máme řešení, které je nezávislé na použitém programovacím jazyce či frameworku. Samotný Solr je stále docela složitý, ale poskytne nám mnoho. Doporučuji zakoupit knihu [SOLR] a prostudovat ji. Minimálně tím získáte přehled, co je možné a co raději nechceme.</p>
<p>Pro napojení Apache Solr na Ruby on Rails lze použít plugin <a href="http://github.com/mattmatt/acts_as_solr" onclick="javascript:pageTracker._trackPageview('/outbound/article/github.com');">acts_as_solr</a> a mít super fulltext  v aplikaci v řádu minut.</p>
<h2>1. Instalace pluginu</h2>
<p><code> script/plugin install git://github.com/mattmatt/acts_as_solr.git<br />
</code></p>
<h2>2. Nastartujeme Solr</h2>
<p><code> rake solr:start<br />
</code></p>
<p>Solr by teď měl odpovídat na <a href="http://localhost:8982/solr/" onclick="javascript:pageTracker._trackPageview('/outbound/article/');">ttp://localhost:8982/solr/</a>, kde najdeme přehledné admin rozhraní.</p>
<h2>3. Integrace do modelu</h2>
<p><code><br />
class Address &lt; ActiveRecord::Base<br />
#z modelu chceme indexovat ulici, město, psč<br />
acts_as_solr :fields =&gt; [:street, :town, :zip]<br />
end<br />
</code><br />
Od teď se při každém save adresy provede zápis do Lucene indexu v Solr.</p>
<h2>4. Reindex</h2>
<p>Pokud máme plnou databázi a chceme reindexovat všechny modely najednou, v console spustíme:</p>
<p><code> Address.rebuild_solr_index<br />
</code></p>
<h2>5. Používání</h2>
<p><code><br />
Address.find_by_solr("Praha")<br />
</code></p>
<p>Solr umí také vyhledávat přes více modelů najednou, používat wildcards, facets, syntax highlighting, našeptávat, apod. Zájemce odkazuji na zdroje pod článkem.</p>
<p>I když plugin acts_as_solr vypadá opravdu jednoduše,  je vhodné nastudovat minimálně doporučený [SOLR] a ještě lépe [LUCENE]. Musíme mít na paměti, že pokud si Solr pustíme do infrastruktury, budeme s ním muset pracovat a podporovat ho řadu let, takže je třeba vědět, jak vlastně technologie funguje. Minimálně pro debugování, až jednoho dne fungovat přestane :).</p>
<h2>Zdroje:</h2>
<ul>
<li>[SOLR] - David Smiley, Eric Pugh, Solr 1.4 Enterprise Search Server, PACKT Publishing, 2009, ISBN: 1847195881. Dostupný z WWW: <a href="https://www.packtpub.com/solr-1-4-enterprise-search-server/book" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.packtpub.com');">https://www.packtpub.com/solr-1-4-enterprise-search-server/book</a></li>
<li>[LUCENE] - Michael McCandless, Erik Hatcher, and Otis Gospodnetić, Lucene in Action, Second Edition, Manning Publications Co., 2010, ISBN: 1933988177. Dostupný z WWW: <a href="http://www.manning.com/hatcher3/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.manning.com');">http://www.manning.com/hatcher3/</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.hradil.org/fulltext-v-ruby-on-rails-a-apache-solr/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Ruby on Rails z pohledu odběratele</title>
		<link>http://www.hradil.org/ruby-on-rails-z-pohledu-odberatele/</link>
		<comments>http://www.hradil.org/ruby-on-rails-z-pohledu-odberatele/#comments</comments>
		<pubDate>Sun, 05 Sep 2010 21:10:42 +0000</pubDate>
		<dc:creator>Jiří Hradil</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.hradil.org/?p=346</guid>
		<description><![CDATA[V návaznosti na minulý článek Rails and the Enterprise a první otázku &#8220;jak byste definovali enterprise ?&#8221;.
Pokud budeme uvažovat o &#8220;enterprise&#8221; jako o &#8220;podnikovém&#8221; software, tak je otázka postavena &#8220;jsou vhodné Ruby on Rails pro používání v podnicích&#8221;? Pak je třeba definovat kritéria, která rozhodují o vhodnosti používání technologie v podnikovém prostředí. Uvažujme podnik/společnost, která [...]]]></description>
			<content:encoded><![CDATA[<p>V návaznosti na minulý článek <a href="http://www.hradil.org/rails-and-the-enterprise/" onclick="">Rails and the Enterprise</a> a první otázku &#8220;<em>jak byste definovali enterprise ?&#8221;.</em></p>
<p>Pokud budeme uvažovat o &#8220;enterprise&#8221; jako o &#8220;podnikovém&#8221; software, tak je otázka postavena &#8220;jsou vhodné Ruby on Rails pro používání v podnicích&#8221;? Pak je třeba definovat kritéria, která rozhodují o vhodnosti používání technologie v podnikovém prostředí. Uvažujme podnik/společnost, která je příjemcem, nikoli dodavatelem software. Podnik chce:</p>
<p>1. Aby software řešil problémovou domému podniku. Pokud podnik potřebuje dostat jakoukoli logiku na web, nepotřebuje specifika jako např. real-time software a tato logika se dá nacpat do klasického request+response+relační db, jsou Ruby on Rails skvělou volbou. Jako programátoři pomocí Ruby skvěle popíšeme problémovou doménu, můžeme vytvořit DSL (<a href="http://en.wikipedia.org/wiki/Domain-specific_language" onclick="javascript:pageTracker._trackPageview('/outbound/article/en.wikipedia.org');">domain specific language</a>) a jazyk si v podstatě ohnout podle sebe. Příjemci software je v podstatě jedno, jaký jazyk je v pozadí. Je na schopnostech poskytovatele/dodavatele dokázat, že použitá technologie prostě &#8220;bude fungovat&#8221;.</p>
<p>2. Aby software fungoval dostatečně dlouho, ideálně aby přežil (časově) potřeby podniku. Tento požadavek je pro příjemce jasný. Pro poskytovatele to znamená přijmout dostatečně agilní model vývoje, který bude rychle reagovat na změny. Podnik se mění společně se světem okolo něj a neexistuje zadání, které by bylo časově neměnné a bez nutných modifikací. Opět je na schopnostech poskytovatele dokázat, že jeho technologie je časově odolná. Ruby on Rails mají za sebou dostatečně dlouhou historii a pokud stále fungují a jsou nasazovány, pak testem odolnosti prošly. Tady je nutno chápat, že 17 let existence Ruby a 6 let existence Rails jsou v IT tak dlouhé etapy, že neschopná technologie by již dávno zanikla. Takže ano, Ruby on Rails jsou časově odolné a nejsou žádný prázdninový hype.</p>
<p>3. Aby měla technologie &#8220;zázemí&#8221;. Některé podniky se rády šťourají v referencích na použitou technologii a rády slyší, že existuje tzv. &#8220;zázemí velké společnosti&#8221;. To připomíná známý vtip &#8220;Nikdo ještě neudělal chybu tím, že vybral IBM&#8221;. Tento pocit bezpečí je falešný, jak jsme nedávno viděli na příkladu Sunu a Javy. Molochy, které poskytují zázemí nefungují. Firmy platí miliony za SLA, konzultanty, metodiky a procesy velkým korporacím, které jako celek degradovaly do bezpohlavních bytostí, jejichž jediným cílem je dosahovat zisku. Mám z 6-leté historie <a href="http://www.kyberie.cz" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.kyberie.cz');">Kyberie</a> bezpočet příkladů, kdy spoléháni na &#8220;velkého&#8221; dodavatele nefungovalo. Počínaje HW supportem, SW konzultacemi, návrhy na metodiky vývoje, řešení infrastruktury a konče poskytováním SLA&#8230; Nejlepší, co lze dle mého názoru udělat je spolehnout se sám na sebe a příjemci/odběrateli poskytnout vlastní zázemí. Ono &#8220;velké zázemí&#8221; či zvučné jméno může fungovat jen jako pojistka či reference. Ne jako základní stavební kámen.</p>
<p>4. Aby šel software napojit na existující systémy. Možná dostaneme rozhraní, na které se musíme napojit a je možné, že třeba v Javě to půjde jednodušeji. Tady nelze předjímat, vše záleží na konkrétní situaci. Ovšem i s <a href="http://en.wikipedia.org/wiki/REST" onclick="javascript:pageTracker._trackPageview('/outbound/article/en.wikipedia.org');">RESTem</a>, který Ruby on Rails používají, případně s web hooks lze dokázat divy.</p>
<p>5. Aby software stál rozumné peníze. Pokud přijmeme klasický platební model &#8220;cena za člověkoden&#8221;, tak tady jsou Ruby on Rails v obrovské výhodě. Jak jsem uvedl, v <a href="http://kyberie.cz" onclick="javascript:pageTracker._trackPageview('/outbound/article/kyberie.cz');">Kyberii</a> jsou Ruby on Rails při vývoji asi 10x rychlejší než stack Java+Spring+Hibernate+Wicket+dalších X špaget. Pokud budeme uvažovat jednoduše linárně, tak oproti konkurenci můžeme poskytnout software 10x levněji.</p>
<p>A to už stojí za to vyzkoušet <a href="http://rubyonrails.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/rubyonrails.org');">Ruby on Rails</a>, ne?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hradil.org/ruby-on-rails-z-pohledu-odberatele/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Rails and the Enterprise</title>
		<link>http://www.hradil.org/rails-and-the-enterprise/</link>
		<comments>http://www.hradil.org/rails-and-the-enterprise/#comments</comments>
		<pubDate>Wed, 25 Aug 2010 20:42:09 +0000</pubDate>
		<dc:creator>Jiří Hradil</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.hradil.org/?p=339</guid>
		<description><![CDATA[Posílám skvělý článek Rails and the Enterprise, který je povinností pro každého programátora v Ruby on Rails.
Zajímá mě:

jak byste s ohledem na obsah článku definovali &#8220;enterprise&#8221;?
kde je hranice, od které považujete systém za &#8220;velký&#8221;?
proč a jak jsou některé jazyky či frameworky vhodnější pro vývoj &#8220;velkých&#8221; systémů?
kdo či co je autorita, která definuje tuto &#8220;vhodnost&#8221;?

]]></description>
			<content:encoded><![CDATA[<p>Posílám skvělý článek <a href="http://weblog.rubyonrails.org/2010/3/24/rails-and-the-enterprise?utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed:+RidingRails+(Riding+Rails)" onclick="javascript:pageTracker._trackPageview('/outbound/article/weblog.rubyonrails.org');">Rails and the Enterprise</a>, který je povinností pro každého programátora v Ruby on Rails.</p>
<p>Zajímá mě:</p>
<ol>
<li>jak byste s ohledem na obsah článku definovali &#8220;enterprise&#8221;?</li>
<li>kde je hranice, od které považujete systém za &#8220;velký&#8221;?</li>
<li>proč a jak jsou některé jazyky či frameworky vhodnější pro vývoj &#8220;velkých&#8221; systémů?</li>
<li>kdo či co je autorita, která definuje tuto &#8220;vhodnost&#8221;?</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.hradil.org/rails-and-the-enterprise/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Active Record a transakce</title>
		<link>http://www.hradil.org/active-record-a-transakce/</link>
		<comments>http://www.hradil.org/active-record-a-transakce/#comments</comments>
		<pubDate>Tue, 24 Aug 2010 08:26:59 +0000</pubDate>
		<dc:creator>Jiří Hradil</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.hradil.org/?p=306</guid>
		<description><![CDATA[Použití transakcí je v Active Record opravdu triviální. Samotná dokumentace k modulu ActiveRecord::Transactions::ClassMethods je jednoduchá a ovládnutelná za 5 minut. Zapomeňme na dlouhá studia románů typu Spring transaction management, zapomeňte na AOP, advisory a jiné ptákoviny. Nepoužíváme technologii pro technologii. Transakce potřebujeme jednoduše proto, aby data v databázi byla v každém okamžiku konzistentní. Pro polévku [...]]]></description>
			<content:encoded><![CDATA[<p>Použití transakcí je v Active Record opravdu triviální. Samotná dokumentace k modulu <a href="http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/api.rubyonrails.org');">ActiveRecord::Transactions::ClassMethods</a> je jednoduchá a ovládnutelná za 5 minut. Zapomeňme na dlouhá studia románů typu <a href="http://static.springsource.org/spring/docs/2.0.8/reference/transaction.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/static.springsource.org');">Spring transaction management</a>, zapomeňte na AOP, advisory a jiné ptákoviny. Nepoužíváme technologii pro technologii. Transakce potřebujeme jednoduše proto, aby data v databázi byla v každém okamžiku konzistentní. Pro polévku kolem odkazuji třeba na <a href="http://cs.wikipedia.org/wiki/Datab%C3%A1zov%C3%A1_transakce" onclick="javascript:pageTracker._trackPageview('/outbound/article/cs.wikipedia.org');">Wikipedii</a>.</p>
<h2>Automatické transakce pro create, save a destroy</h2>
<p>Pokud voláme jen jednu metodu <em>create</em>, <em>save</em> nebo <em>destroy</em>, transakce nemusíme řešit, Active Record volání metod obalí transakcí automaticky:<br />
<code><br />
Contact.create(:name=&gt;'Jirka Hradil')<br />
</code><br />
Vygeneruje:<br />
<code><br />
BEGIN<br />
INSERT INTO "contacts" ("name") VALUES('Jirka Hradil') RETURNING "id"<br />
COMMIT<br />
</code></p>
<p>Je to logické - 1 volání <em>create</em>, <em>save</em> nebo <em>destroy</em> buď je nebo není provedeno. Toto volání už nemáme jak kouskovat. Samozřejmě pokud je insert, update nebo delete pouze 1, nebylo by třeba vůbec transakci používat, samostatný sql statement je atomický sám o sobě.</p>
<p>Stejně můžeme uložit více objektů najednou, pokud se ovšem vejdeme do volání 1 metody:<br />
<code><br />
Contact.create(:name=&gt;'Jirka Hradil', :addresses=&gt;[Address.new(:address=&gt;'Pod Valhallou 1')])<br />
</code><br />
Vygeneruje:<br />
<code><br />
BEGIN<br />
INSERT INTO "contacts" ("name") VALUES('Jirka Hradil') RETURNING "id"<br />
INSERT INTO "addresses" ("address", "contact_id") VALUES('Pod Valhallou 1', 4) RETURNING "id"<br />
COMMIT<br />
</code></p>
<h2>Ruční transakce přes více metod</h2>
<p>Pokud potřebujeme zavolat více metod, které musí být provedeny všechny najednou nebo žádná z nich, obalíme je metodou <em>transaction</em>, která je jak metodou třídy, tak instance každého modelu (třídy jsou v Ruby také objekty):<br />
<code><br />
c = Contact.new(:name=>'Jirka Hradil')<br />
a = Address.new(:address=>'Pod Valhallou 1', :contact=>c)</p>
<p>Contact.transaction do #tady by klidně mohlo být c.transaction nebo Address.transaction<br />
c.save!<br />
a.save!<br />
end<br />
</code><br />
Vygeneruje stejné:<br />
<code><br />
BEGIN<br />
INSERT INTO "contacts" ("name") VALUES('Jirka Hradil') RETURNING "id"<br />
INSERT INTO "addresses" ("address", "contact_id") VALUES('Pod Valhallou 1', 5) RETURNING "id"<br />
COMMIT<br />
</code></p>
<p>Pokud používáme jen jedno databázové spojení (default nastavení Rails), je jedno, ze kterého modelu metodu <em>transaction</em> použijeme, tuto metodu každý model dědí z <a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/api.rubyonrails.org');">ActiveRecord::Base</a>, který includuje modul <a href="http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/api.rubyonrails.org');">ActiveRecord::Transactions::ClassMethods</a>.</p>
<h2>Transakce napříč databázovými spojeními</h2>
<p>Tuto možnost jsem nikdy nezkoušel, ale dle dokumentace stačí vnořit volání metod transaction do sebe napříč modely, které jsou ukládány do různých databází:<br />
<code><br />
c = Contact.new(:name=>'Jirka Hradil')<br />
a = Address.new(:address=>'Pod Valhallou 1', :contact=>c)</p>
<p>Contact.transaction do<br />
Address.transaction do<br />
c.save!<br />
a.save!<br />
end<br />
end<br />
</code><br />
Plně distribuované transakce napříč různými databázemi Active Record nepodporuje. Já osobně jsem tohle nikdy nepotřeboval a dávám si moc záležet, abych o distribuované transakce ani nezavadil, ale pro někoho jejich absence může být omezením.</p>
<h2>A co rollback a commit?</h2>
<p>Commit neřešíme. Pokud žádné volání metod uvnitř transakčního bloku nevyhodí výjimku, na konci bloku se provede commit automaticky.</p>
<p>Rollback také nemusíme řešit. Vyvolá se sám, pokud některá z metod vyhodí výjimku.</p>
<h2>Na co si dávat pozor při použití save namísto save!</h2>
<p>Pokud voláme více metod, které obalíme do transakčního bloku a pro ukládání změn voláme <em>save</em> namísto <em>save!</em>, pak pozor - metoda <em>save</em> (bez vykřičníku) nevyhazuje výjimku a tedy se ani neprovede rollback v případě neuložení objektu (třeba když neprojde validace). Výsledkem je nekonzistentní stav, který je na konci potvrzen &#8220;sprostým&#8221; commitem:<br />
<code><br />
Contact.transaction do<br />
c.save #nevyhodí výjimku, ale nemusí se uložit do db, pokud např. neprojde validace<br />
a.save #nevyhodí výjimku, ale nemusí se uložit do db, pokud např. neprojde validace<br />
end<br />
</code><br />
Pokud třeba selhala validace u adresy, vygeneruje se jen insert pro kontakt:<br />
<code><br />
BEGIN<br />
INSERT INTO "contacts" ("name") VALUES('Jirka Hradil') RETURNING "id"<br />
COMMIT<br />
</code><br />
&#8230;a databázi máme v nekonzistentním stavu. Což je logické, protože jak jsem uvedl, rollback se zavolá jen tehdy, pokud něco v transakčním bloku vyhodí výjimku.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hradil.org/active-record-a-transakce/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Active Record a propojení objektů</title>
		<link>http://www.hradil.org/active-record-a-propojeni-objektu/</link>
		<comments>http://www.hradil.org/active-record-a-propojeni-objektu/#comments</comments>
		<pubDate>Sun, 15 Aug 2010 11:54:33 +0000</pubDate>
		<dc:creator>Jiří Hradil</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.hradil.org/?p=270</guid>
		<description><![CDATA[Propojení objektů je v Active Record velmi jednoduché a pokud znáte ORM, zabere vám pochopení několik minut. Nemá smysl přepisovat napsané a zájemce odkazuji na ActiveRecord::Associations::ClassMethods. Active Record má pro asociace opravdu hodně možností, ale pro základní použití vám bude stačit jen minimum z nich.
Pro jednoduchost si projdeme vztahy one-to-one a one-to-many.
One to one
&#8220;Kontakt má [...]]]></description>
			<content:encoded><![CDATA[<p>Propojení objektů je v <a href="http://ar.rubyonrails.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/ar.rubyonrails.org');">Active Record</a> velmi jednoduché a pokud znáte ORM, zabere vám pochopení několik minut. Nemá smysl přepisovat napsané a zájemce odkazuji na <a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/api.rubyonrails.org');">ActiveRecord::Associations::ClassMethods</a>. Active Record má pro asociace opravdu hodně možností, ale pro základní použití vám bude stačit jen minimum z nich.</p>
<p>Pro jednoduchost si projdeme vztahy one-to-one a one-to-many.</p>
<h2>One to one</h2>
<p><em>&#8220;Kontakt má jednu adresu&#8221;</em> definujeme pomocí metod modulu <a href="http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/api.rubyonrails.org');">ActiveRecord::Associations::ClassMethods</a> a to <em>has_one</em> a <em>belongs_to</em>. Netřeba se obávat, nic nemusíme importovat, includovat, requirovat ani nic podobného. Vše potřebné již udělal Active Record. Rozdíl mezi <em>has_one</em> a <em>belongs_to</em> metodami je v tom, že strana, která má <em>belongs_to</em> obsahuje cizí klíč v db tabulce. Teoreticky nemusíme vůbec <em>has_one</em> definovat, ale potom se připravíme o možnost jednoduše objektově dosáhnout na adresu z kontaktu.</p>
<p><code><br />
class Contact &lt; ActiveRecord::Base<br />
has_one :address<br />
end<br />
</code></p>
<p><code><br />
class Address &lt; ActiveRecord::Base<br />
belongs_to :contact<br />
end<br />
</code></p>
<p>Databázové tabulky:</p>
<p><code><br />
CREATE TABLE contacts (<br />
id integer NOT NULL PRIMARY KEY,<br />
name varchar(255)<br />
);<br />
</code></p>
<p><code><br />
CREATE TABLE addresses (<br />
id integer NOT NULL PRIMARY KEY,<br />
contact_id integer NOT NULL,<br />
address varchar(255)<br />
);<br />
</code></p>
<p>Ukládáme:<br />
<code><br />
c = Contact.new(:name=>'Jirka Hradil', :address=>Address.new(:address=>'Valhalla'))<br />
c.save<br />
</code><br />
Tento kód nám vygeneruje potřebné inserty:<br />
<code><br />
BEGIN<br />
INSERT INTO "contacts" ("name") VALUES('Jirka Hradil') RETURNING "id"<br />
INSERT INTO "addresses" ("address", "contact_id") VALUES('Valhalla', 1) RETURNING "id"<br />
COMMIT<br />
</code></p>
<p>Všimněte si automatické transakce okolo obou insertů. Vzpomínáte si, že bychom je někde definovali? Ne, Active Record to za nás udělal automaticky. Na kontaktu jsme zavolali metodu <em>save</em>, což je 1 &#8220;atomické&#8221; volání metody, tudíž se vše obalilo do 1 transakce.<br />
Samozřejmě bychom mohli nejdřív uložit kontakt a teprve pak adresu, pak bychom si ovšem hranice transakce museli řídit sami. To si ukážeme příště.</p>
<p>A teď vyhledáváme:<br />
<code><br />
c = Contact.first #najdeme první kontakt<br />
puts c.address #a vypíšeme jeho adresu<br />
</code></p>
<p>Což nám generuje selecty:<br />
<code><br />
SELECT * FROM "contacts" LIMIT 1<br />
SELECT * FROM "addresses" WHERE ("addresses".contact_id = 1) LIMIT 1<br />
</code></p>
<p>Tady si všimněte, že nikde nedefinuji eager, lazy ani nic podobného. Active Record standardně používá lazy inicializaci a prostě pokud mu chybí adresa, tak si ji při prvním použití dotáhne přes samostatný select. Podle mě v Active Record 2.3.x neexistuje default způsob, jak zajistit, aby se při výběru kontaktu VŽDY joinovala automaticky jedna jeho adresa (lze však použít <em>Contact.find_by_sql</em> a select si napsat dle libosti). Eager inicializace se používají při vztahu <em>has_many</em> a <em>has_and_belongs_to_many</em> a fungují na principu dotažení všech podřízených entit najednou v samostatném subselectu, jak si ukážeme.</p>
<h2>One to many</h2>
<p><em>&#8220;Kontakt má hodně adres&#8221;</em> definujeme pomocí <em>has_many</em> a adresy přepíšeme do množného čísla na <em>addresses</em>.<br />
<code><br />
class Contact < ActiveRecord::Base<br />
    has_many :addresses<br />
end<br />
</code></p>
<p>Třída Address zůstává stejná (má jen belongs_to), stejně tak databázové schéma.</p>
<p>Teď uložíme kontakt s více adresami najednou. Všimněte si použití slova <em>addresses</em> jako množného čísla. Adresy jsou rovněž pole, nikoli samostatný objekt:<br />
<code><br />
c = Contact.new(:name=>'Jirka Hradil', :addresses=>[Address.new(:address=>'První adresa'), Address.new(:address=>'Druhá adresa')])<br />
c.save<br />
</code><br />
Vygenerované inserty:<br />
<code><br />
BEGIN<br />
INSERT INTO "contacts" ("name") VALUES('Jirka Hradil') RETURNING "id"<br />
INSERT INTO "addresses" ("address", "contact_id") VALUES('První adresa', 2) RETURNING "id"<br />
INSERT INTO "addresses" ("address", "contact_id") VALUES('Druhá adresa', 2) RETURNING "id<br />
COMMIT<br />
</code><br />
Opět, vše automaticky zabaleno do transakce, protože jsme volali jen 1 &#8220;atomické&#8221; save.<br />
</code><br />
Vyhledáváme:<br />
<code><br />
c = Contact.first #najdeme první kontakt<br />
puts c.addresses #pole adres<br />
</code></p>
<p>Vygenerované selecty:<br />
<code><br />
SELECT * FROM "contacts" LIMIT 1<br />
SELECT * FROM "addresses" WHERE ("addresses".contact_id = 1)<br />
</code></p>
<h3>Lazy vs eager</h3>
<p>Active Record je při načítání podřízených objektů velmi chytrý. Zapomeňte na nějakou LazyInitializationException nebo podobné ptákoviny, které vás jen stojí spoustu času. Podřízené objekty se natahují vždy přes samostatný select.<br />
<code><br />
Contact.all.each {|c| puts c.addresses} # vypíšeme si všechny adresy<br />
</code><br />
Generované selecty:<br />
<code><br />
SELECT * FROM "contacts"<br />
SELECT * FROM "addresses" WHERE ("addresses".contact_id = 1)<br />
SELECT * FROM "addresses" WHERE ("addresses".contact_id = 2)<br />
</code><br />
&#8230;což nám vede ke známému &#8220;N+1&#8243; select problému - máme 2 adresy a udělají se celkem 3 dotazy.<br />
Eliminace je jednoduchá pomocí atributu <em>:include</em><br />
<code><br />
Contact.all(:include=>:addresses).each {|c| puts c.addresses}<br />
</code><br />
Pak se selecty transformují do 1+1, kdy je jeden select na všechny kontakty a další select na všechny adresy kontaktů, načtených v předchozím selectu:<br />
<code><br />
SELECT * FROM "contacts"<br />
SELECT "addresses".* FROM "addresses" WHERE ("addresses".contact_id IN (1,2))<br />
</code><br />
Jednoduché a efektivní.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hradil.org/active-record-a-propojeni-objektu/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Active Record a automatické findery</title>
		<link>http://www.hradil.org/active-record-a-automaticke-findery/</link>
		<comments>http://www.hradil.org/active-record-a-automaticke-findery/#comments</comments>
		<pubDate>Sun, 08 Aug 2010 15:22:43 +0000</pubDate>
		<dc:creator>Jiří Hradil</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.hradil.org/?p=240</guid>
		<description><![CDATA[Jako další pěknou vlastnost Active Record vypíchnu automatické findery.
Zděděním modelu (Ruby třídy, která reprezentuje &#8220;business object&#8221;) od ActiveRecord::Base získáváme automatické findery na všechny atributy, načtené reflexí z databázové tabulky i včetně jejich kombinací.
Příklad:
Stejně jako v minulém příspěvku použijeme třídu Contact:

class Contact &#60; ActiveRecord::Base
#to je vsechno
end

A její tabulku contacts:

CREATE TABLE contacts (
id integer NOT NULL PRIMARY KEY,
name [...]]]></description>
			<content:encoded><![CDATA[<p>Jako další pěknou vlastnost <a href="http://ar.rubyonrails.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/ar.rubyonrails.org');">Active Record</a> vypíchnu automatické findery.</p>
<p>Zděděním modelu (Ruby třídy, která reprezentuje &#8220;business object&#8221;) od <em>ActiveRecord::Base</em><span> získáváme automatické findery na všechny atributy, načtené reflexí z databázové tabulky i včetně jejich kombinací.</span></p>
<p>Příklad:</p>
<p>Stejně jako v <a href="http://www.hradil.org/active-record-je-nejlepsi-orm/" onclick="">minulém příspěvku</a> použijeme třídu Contact:<br />
<code><br />
class Contact &lt; ActiveRecord::Base<br />
#to je vsechno<br />
end<br />
</code><br />
A její tabulku <em>contacts</em>:<br />
<code><br />
CREATE TABLE contacts (<br />
id integer NOT NULL PRIMARY KEY,<br />
name varchar(255),<br />
address varchar(255)<br />
);<br />
</code><br />
Atribut <em>id</em> je default primární klíč (ve třídě jsme tohle nikde neurčili, je to default chování Active Record). Pak můžeme kontakt najít jednoduše dle id:<br />
<code><br />
c = Contact.find(1) #najde kontakt s id 1<br />
</code><br />
Metodu <em>find</em> třídy <em>Contact</em> jsme nikde nenapsali, je zděděna z <em>ActiveRecord::Base</em>. Zajímavé jsou však další &#8220;automatické findery&#8221; dle atributů tabulky, aniž bychom je kdekoli definovali:<br />
<code><br />
c = Contact.find_by_name('Jirka') #metodu find_by_name jsem nikde nepsal<br />
c = Contact.find_by_address('Valhalla') #tuhle jsem taky nikde nepsal<br />
</code><br />
Fungují dokonce kombinace atributů. Je jedno v jakém pořadí, všimněte si spojky &#8220;and&#8221; mezi atributy:<br />
<code><br />
c = Contact.find_by_name_and_address('Jirka', 'Valhalla') #nejdriv jmeno, pak adresa<br />
c = Contact.find_by_address_and_name('Valhalla', 'Jirka') #naopak<br />
</code></p>
<p>Tohle je vývojářův sen. Žádné rozhraní, žádné implementace, při změně atributů v tabulce nemusíme findery měnit či připisovat nové. Změníme pouze schéma tabulky a nové findery a jejich kombinace máme okamžitě k dispozici. <strong>Samozřejmě bez redeploy aplikace či restartu serveru</strong>.</p>
<p>Vypadá to jako magie, ale Active Record využívá Ruby metodu <a href="http://ruby-doc.org/core/classes/Kernel.html#M005925" onclick="javascript:pageTracker._trackPageview('/outbound/article/ruby-doc.org');">method_missing</a>, která se zavolá vždy, když metoda v objektu neexistuje.  V tomto případě si <em>method_missing</em> sáhne do schématu tabulku a za běhu přidá novou metodu dle kombinace atributů.</p>
<p>Protože máme logiku i data pěkně pohromadě, pak se nemusíme rozpomínat či studovat, jaké rozhraní používat pro hledání, jaké pro ukládání, co pro změnu či mazání, apod. Prostě potřebuju pracovat s kontaktem, tak použiju třídu <em>Contact </em>či některou z jejich instancí.</p>
<p>Příklad:<br />
<code><br />
c1 = Contact.new(:name=>'Hradil')<br />
c1.save #ulozime novy kontakt<br />
c1.name = 'Jirka Hradil' #zmenime jmeno<br />
c1.save #ulozime zmeny, provede se UPDATE, protoze zaznam uz byl persistovan a ma id<br />
c2 = Contact.find_by_name('Jirka Hradil') #najdeme si kontakt<br />
c2.delete #smazeme kontakt, provede se DELETE<br />
</code></p>
<p>Zkuste si to a uvidíte, jak neradi se budete vracet k Hibernate :).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hradil.org/active-record-a-automaticke-findery/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Active Record je nejlepší ORM</title>
		<link>http://www.hradil.org/active-record-je-nejlepsi-orm/</link>
		<comments>http://www.hradil.org/active-record-je-nejlepsi-orm/#comments</comments>
		<pubDate>Tue, 03 Aug 2010 20:23:45 +0000</pubDate>
		<dc:creator>Jiří Hradil</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://www.hradil.org/?p=212</guid>
		<description><![CDATA[Při vývoji webových aplikací pomocí Ruby on Rails se okamžitě setkáme s potřebou ukládat objekty do databáze. Ruby on Rails používají Active Record, což je první ORM, které je opravdu radost používat. Ve srovnání třeba s Toplinkem nebo Hibernate mě nijak nebrzí a neuvěřitelně urychluje vývoj.
Za pozornost stojí:
Konvence před konfigurací (Convention over Configuration)
A to narozdíl třeba [...]]]></description>
			<content:encoded><![CDATA[<p>Při vývoji webových aplikací pomocí <a href="http://rubyonrails.org" onclick="javascript:pageTracker._trackPageview('/outbound/article/rubyonrails.org');">Ruby on Rails</a> se okamžitě setkáme s potřebou ukládat objekty do databáze. Ruby on Rails používají <a href="http://ar.rubyonrails.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/ar.rubyonrails.org');">Active Record</a>, což je první ORM, které je opravdu radost používat. Ve srovnání třeba s Toplinkem nebo Hibernate mě nijak nebrzí a neuvěřitelně urychluje vývoj.</p>
<p>Za pozornost stojí:</p>
<h2>Konvence před konfigurací (Convention over Configuration)</h2>
<p>A to narozdíl třeba od Springu bez keců. Žádné XML, žádné mapování databázových atributů do pofidérních XML objektů či anotací, nic. Stačí Ruby business objekt podědit od třídy <em>ActiveRecord::Base</em> Mapování se bere rovnou z databázové tabulky a v Ruby objektu o něm není ani zmínka.</p>
<p>Příklad:</p>
<p>Třída<br />
<code><br />
class Contact &lt; ActiveRecord::Base<br />
#to je vsechno<br />
end<br />
</code><br />
&#8230;si všechny atributy včetně datových typů načte dle databázové tabulky <em>contacts</em>:<br />
<code><br />
CREATE TABLE contacts (<br />
id integer NOT NULL,<br />
name varchar(255),<br />
address varchar(255)<br />
);<br />
</code><br />
Protože se používá CoC, nemusíme mít nikde žádný soubor, který definuje, že třída <em>Contact</em> se má podívat do <em>contacts</em>, spojení je definováno automaticky (Contact se automaticky převede na malá písmena a dá se do množného čísla).</p>
<p>Protože je použita reflexe dle struktury tabulky, ve třídě <em>Contact</em> máme opět automaticky k dispozici gettery a settery na všechny atributy z tabulky, takže můžeme klidně hned použít:<br />
<code><br />
c=Contact.new<br />
c.name='Jirka Hradil'<br />
c.address='Valhalla'<br />
</code></p>
<p>nebo ještě rychlejší:<br />
<code><br />
c = Contact.new(:name=&gt;'Jirka Hradil', :address=&gt;'Valhalla')<br />
</code></p>
<p>Tohle je, vážení kolegové, jednoduchost v ryzí formě. Napadá někoho, jak to udělat ještě líp?</p>
<h2>Data a logika pohromadě</h2>
<p>Klasický Java patternista s tímhle bude mít asi problém. Dobré je přece mít servisní vrstvu, pod ní DAO vrstvu, logika je v servisní vrstvě striktně oddělená od DAO, vše pro jistotu přes rozhraní, pak implementovat&#8230; Proč? Pokud byste někdy potřebovali změnit implementaci, tak &#8220;jen&#8221; implementujete rozhraní. Já osobně jsem si ale vždy vystačil pouze s jedinou implementací a tyto patterny mě jen zdržovaly. <em>ActiveRecord::Base</em> nám do třídy přidá rovnou instanční metody pro uložení. Takže jakmile máme vytvořen náš kontakt, ukládáme:</p>
<p><code> c.save #to je vsechno<br />
</code><br />
Tímto se vygeneruje klasický <em>INSERT INTO&#8230;</em> a záznam je persistován. Žádný service locator, žádné vytváření session, nic. Pokud potřebujeme ukládat třeba více objektů najednou nebo dát před ukládání nějakou logiku, vytvoříme si vlastní metodu a v ní si uděláme, co je třeba.</p>
<h2>YAML místo XML či properties souborů</h2>
<p><a href="http://www.yaml.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.yaml.org');">YAML</a> je formát pro serializaci či definici dat a v Rails se používá pro konfigurační soubory. Někde přece jen musí být napojení Rails aplikace do databáze definováno a tímto souborem je <em>database.yml</em>:</p>
<p><code> ...<br />
development:<br />
adapter: postgresql<br />
encoding: unicode<br />
database: book_development<br />
pool: 5<br />
username: uzivatel<br />
password: heslo<br />
...<br />
</code></p>
<p>To je v kostce veškeré napojení Active Record na konkrétní databázi a všechna potřebná konfigurace. Opět - jde to jednodušeji?</p>
<p>V některém z dalších článků se zmíním o tom, jak je to s transakcemi, asociacemi a s <em>lazy</em> vs <em>eager</em>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hradil.org/active-record-je-nejlepsi-orm/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Java vs Ruby on Rails - cesta tam a zase zpátky</title>
		<link>http://www.hradil.org/java-vs-ruby-on-rails-cesta-tam-a-zase-zpatky/</link>
		<comments>http://www.hradil.org/java-vs-ruby-on-rails-cesta-tam-a-zase-zpatky/#comments</comments>
		<pubDate>Mon, 26 Jul 2010 14:48:34 +0000</pubDate>
		<dc:creator>Jiří Hradil</dc:creator>
		
		<category><![CDATA[Ruby on Rails]]></category>

		<category><![CDATA[java]]></category>

		<guid isPermaLink="false">http://www.hradil.org/?p=196</guid>
		<description><![CDATA[Historie
Než se dostanu k jádru věci, dovolte mi malou cestu časem.
Někdy kolem roku 1999 jsem se jako první jazyk začal učit PHP. Zadáním bylo vytvoření interního web systému pro hodnocení zaměstnanců. Protože jsem se v jazycích nevyznal, vzal jsem první knihu, která mi přišla pod ruku - &#8220; PHP - Hypertextový preprocesor&#8221; od Jirku Koska. Už [...]]]></description>
			<content:encoded><![CDATA[<h2>Historie</h2>
<p>Než se dostanu k jádru věci, dovolte mi malou cestu časem.</p>
<p>Někdy kolem roku 1999 jsem se jako první jazyk začal učit PHP. Zadáním bylo vytvoření interního web systému pro hodnocení zaměstnanců. Protože jsem se v jazycích nevyznal, vzal jsem první knihu, která mi přišla pod ruku - &#8220; <a href="http://www.kosek.cz/php/" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.kosek.cz');">PHP - Hypertextový preprocesor</a>&#8221; od Jirku Koska. Už tehdy mě překvapila neuvěřitelná rychlost vývoje. Za týden jsem zpatlal první verzi, napojenou na MySQL databázi. Žádné šablony, žádné navrhové vzory, žádné transakce, žádná 3-vrstvá architektura. Logika pěkně zmatlaná s HTML, pár stránek. Autorizace spočívala ve vsunutí kouzelného atributu do HTML requestu s hodnotou 1, což bylo dle mé naivní představy dostatečné.</p>
<p>Jirka Kosek mi pak stačil pro další 3 roky, abych se uživil jako PHP programátor. Postupně jsem se naučil, že je dobré oddělit logiku od aplikační vrstvy, že existuje něco jako &#8220;normální forma&#8221;, &#8220;sql inject&#8221;, &#8220;databázové transakce&#8221;, apod. Měl jsem však pocit, že musí existovat něco &#8220;jednoduššího&#8221;, více výkonného, standardního. Tak jsem se dostal k Javě, která byla v té době (kolem roku 2002) opravdu moc sexy. Pomocí <a href="http://www.netbeans.org" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.netbeans.org');">Netbeans</a> bylo docela rychlé napsat jednoduchou aplikaci ve Swingu přes GUI editor. Co na tom, že metody v kódu byly zamknuté, nedalo se do nich zasáhnout ručně, třída byla pořád delší a Netbeans byly opravdu pomalé. Psal jsem v Javě, takže jsem byl na špičce, to bylo jasné ;).</p>
<p>Od Swingu jsem se chtěl dostat k Java web aplikacím. A tady jsem poprvé narazil. Napsat Java web aplikaci nebylo vůbec jednoduché. Najednou jsem toho měl umět opravdu dost. JSP, JSTL, EJB, JDBC. Samé stupidní zkratky a co bylo nejhorší - pořad přibývaly. Jen jsem se začal zhruba orientovat, co je vlastně JSP, tak přišlo JSTL se sdělením &#8220;jsi idiot, že píšeš v JSP, použij mě&#8221;. Jen co jsem zkusil JDBC, dočetl jsem se &#8220;JDBC je pro lamy, EJB, to je budoucnost&#8221;. Ale protože jsem byl čínský pionýr, který si sám dává překážky, aby je mohl zdolávat, do všech těch buzz jsem se zakousl. Když něco dělám, tak to dělám pořádně a <a href="http://www.hradil.org/certifikace-java-2-platform/" onclick="">tak jsem to vzal a dal včetně certifikace</a>. Alespoň jsem se naučil základy Javy. To mi ovšem na psaní web aplikace nestačilo. Musel jsem projít všemi těmi Sun srandami. Než jsem byl schopen web aplikaci napsat, musel jsem studovat několik měsíců. To mi nevadilo, protože na konci přece čekala nirvána - něco se naučím a pak už budu web aplikace sekat jako Baťa cvičky.</p>
<p>Jenže Java je nevěrná mrcha. Něco se naučíte a hned přijdou další frameworky, které vše řeší lépe a radostněji. Takhle jsem se postupně dostal k ORM (Hibernate, Toplink), dalším  prezentačním frameworkům (JSF, Stripes, Wicket, Spring MVC), must-have nástrojům (Ant, Maven, Spring, JUnit) a dalšímu, občas dobrému balastu (princip nepřetržité integrace, statická analýza kódu, normy psaní zdrojových kódů&#8230;). Tohoto období nelituji, určitě mě neustálé studium posunulo dál. Javu jsem také několik let školil a všechny své kolegy (a později zaměstnance či klienty) dostal, jemně nasměroval či dokopal k Sun certifikacím.</p>
<p>Poslední rok jsem však začal pochybovat ohledně celé Java platformy. Nikoli z pohledu nefunkčnosti, spíše z pohledu efektivity vývoje. V <a href="http://www.kyberie.cz" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.kyberie.cz');">Kyberii</a> používáme striktně agilní vývoj, což je komplikované označení pro &#8220;nevím-co-bude-zítra-vývoj&#8221;. Agilní vývoj (a jeho implementace XP a Scrum) stále považuji za nejefektivnější možný způsob vývoje software. A tady mě Java brzdila.</p>
<p>Největší překážky v Javě při vývoji webových aplikací:</p>
<h2>Složitost jazyka</h2>
<p>Java není jednoduchý jazyk. Ze začátku to vypadá, že ano, ale pár tříd aplikaci nedělá. Po &#8220;hello world&#8221; následuje polymorfismus, modifikátory přístupu, kontejnery, knihovny ze základního API, chuťovky jako reflexe či vlákna&#8230; Jistě, nemusíme znát všechno, ale většinu ze standardního API bychom znát měli. Obecně trvá vyškolení Java začátečníka na programátora, který projde standardní certifikací <a href="http://in.sun.com/training/certification/java/scjp.xml" onclick="javascript:pageTracker._trackPageview('/outbound/article/in.sun.com');">SJCP</a>, asi 20 týdnů (zdroj: moje zkušenosti). Po této době ovšem tento programátor umí jen základy jazyka a není schopen psát produkční aplikaci (nezná ORM, JSP, apod&#8230;). Celý proces vyškolení nováčka do produkčního programátora trvá asi rok. Zkuste si to přepočítat na peníze. To byl IMHO také důvod, proč byli a jsou Java experti přeplacení. Samotný vývoj software je pak pro klienty zbytečně drahý a pokud budeme předpokládat, že Java je trend, pak trh trpí nedostatkem kvalitního software.</p>
<h2>Širokost platformy</h2>
<p>Sun nasměruje budoucí vývoj platformy přes JCP, vznikne nějaké JSR a pak se začne implementovat. Z různých implementací si vývojový tým musí vybrat. A právě možnost výběru vývoj komplikuje. Začínáme pochybovat, zda jsme si vybrali správně, porovnáváme, zkoušíme. U nás jsme třeba začali s JPA přes Toplink, ale později jsme migrovali na Hibernate, protože měl prostě větší komunitní základnu. Byla to jistě správná volba, ale stálo nás to nemalé úsilí a spoustu času.</p>
<h2>Špagetování</h2>
<p>Pokud už vyberete správné frameworky (u nás to byla kombinace Hibernate JPA - Wicket - Maven2 - Spring - Hudson CI - JUnit-Lucene-Hibernate Search), tak celou aplikaci musíte provázat spoustou špaget, aby vám držela pohromadě. Na špagetování se ukázal vhodný Spring, který je pro default použití jednoduchý, ale při bližším koketování <a href="http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html" onclick="javascript:pageTracker._trackPageview('/outbound/article/static.springsource.org');">neuvěřitelně složitý</a>. Křivka učení je hlavně ze začátku velmi nestrmá.</p>
<h2>Kompilace a redeploy</h2>
<p>Tohle byla největší překážka. Při každé změně třeba i v prezentační vrstvě jsme museli aplikaci redeployovat. Servlet kontejner (Tomcat nebo pro vývoj Jetty) namísto nabušeného aplikačního serveru (Glassfish, apod.) proces dost urychlil, ale stejně jsme museli čekat typicky desítky vteřin, než se po reloadu stránky změna projevila (počet tříd v naší aplikaci šel do několika stovek či tisíc). Zkoušeli jsme i hot-redeploy, Java Rebel, apod. Ale stejně jsme museli čekat. Se slzami v očích jsem vzpomínal na PHP, které sice bylo vedle Javy jako ošlivý nepříbuzný, ale zato pekelně rychlý.</p>
<h2>Nepřetržitá integrace a testování</h2>
<p>V Javě není na testování ani nepřetržitou integraci žádný standard či implementace, která by proces napříč různě použitými frameworky zjednodušila a urychlila. Všechno jsme museli vybudovat ručně - Maven, Hudson CI, scripty pro naplnění testovací databáze, vyhodnocení, pokrytí testy, posílání mailem, apod. Což jsme zvládli v řádu týdnů, ale samozřejmě jsem se musel ptát - copak to nejde jednodušeji?</p>
<h2>Ruby on Rails - zpátky na koleje</h2>
<p>A ono to jde. Po několika týdnech experimentování, setkání s <a href="http://www.jetminds.com" onclick="javascript:pageTracker._trackPageview('/outbound/article/www.jetminds.com');">Jiřím Fabiánem z JetMinds</a> a vytvoření pilotního projektu jsme na konci roku 2009 z Javy migrovali na <a href="http://rubyonrails.org/" onclick="javascript:pageTracker._trackPageview('/outbound/article/rubyonrails.org');">Ruby on Rails</a>. Když jsem viděl, jak rychle jsme dokázali vytvořit nový projekt a udržovat klienty spokojené tím, že nemusí na výsledky čekat hodiny či dny, ale vteřiny či minuty, bylo rozhodnuto. <strong>Efektivita vývoje je dle našich interních měření asi 10x větší.</strong> Vrátili jsme se na začátek. Jen místo PHP teď jedeme v Ruby :).</p>
<p>Ale o tom zase v příštím článku.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.hradil.org/java-vs-ruby-on-rails-cesta-tam-a-zase-zpatky/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>

