<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Keep Learning</title>
	
	<link>http://blog.lucashungaro.com</link>
	<description>Conhecimento nunca é o bastante</description>
	<lastBuildDate>Tue, 10 Apr 2012 17:18:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/LearningOnRails" /><feedburner:info uri="learningonrails" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Capistrano and whenever: updating the crontab of the runner user</title>
		<link>http://feedproxy.google.com/~r/LearningOnRails/~3/MvZNctwt4Fw/</link>
		<comments>http://blog.lucashungaro.com/2012/04/10/capistrano-and-whenever-updating-the-crontab-of-the-runner-user/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 17:15:06 +0000</pubDate>
		<dc:creator>Lucas Húngaro</dc:creator>
				<category><![CDATA[Deploy]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.lucashungaro.com/?p=432</guid>
		<description><![CDATA[When deploying Rails applications with Capistrano it&#8217;s a common practice to use two separated users: a deployer (the user who actually does the deploy process, copying files and all that) and a runner (the user that runs the application on the server). If you need cronjobs you probably use the whenever gem. It&#8217;s an awesome [...]]]></description>
			<content:encoded><![CDATA[<p>When deploying Rails applications with <a href="https://github.com/capistrano/capistrano" title="Capistrano">Capistrano</a> it&#8217;s a common practice to use two separated users: a deployer (the user who actually does the deploy process, copying files and all that) and a runner (the user that runs the application on the server).</p>
<p>If you need cronjobs you probably use the <a href="https://github.com/javan/whenever" title="whenever">whenever</a> gem. It&#8217;s an awesome tool to configure your scheduled jobs with a nice and easy DSL. It also has built-in integration with Capistrano, but there&#8217;s a caveat: it will update the crontab of the <strong>deployer</strong>, not the <strong>runner</strong>&#8216;s one.</p>
<p>To solve that issue, I&#8217;ve dropped the &#8220;automatic&#8221; integration (just a simple require &#8220;whenever/capistrano&#8221;) and used a hook to invoke whenever passing a user option to specify which user&#8217;s crontab to update. Here&#8217;s the relevant code:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">after <span style="color:#996600;">&quot;deploy:update_code&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  run <span style="color:#996600;">&quot;cd #{release_path} &amp;&amp; #{try_sudo} GEM_HOME=/opt/local/ruby/gems RAILS_ENV=production bundle exec whenever --clear-crontab #{application} --user #{runner}&quot;</span>
  run <span style="color:#996600;">&quot;cd #{release_path} &amp;&amp; #{try_sudo} GEM_HOME=/opt/local/ruby/gems RAILS_ENV=production bundle exec whenever --update-crontab #{application} --user #{runner}&quot;</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>The code above sets some env vars for sanity sake and runs whenever specifying the runner user as the crontab owner.</p>
<p>There&#8217;s another small tweak you&#8217;ll need. On your schedule.rb file, add the following code on the very first line:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">env <span style="color:#996600;">&quot;PATH&quot;</span>, ENV<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#996600;">&quot;PATH&quot;</span><span style="color:#006600; font-weight:bold;">&#93;</span>
every <span style="color:#006666;">10</span>.<span style="color:#9900CC;">minutes</span> <span style="color:#9966CC; font-weight:bold;">do</span>
  <span style="color:#008000; font-style:italic;"># ...</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>This will avoid nasty path-related errors (the cronjobs won&#8217;t find the gem&#8217;s bins and all that). And… that&#8217;s it! Have fun! <img src='http://blog.lucashungaro.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<img src="http://feeds.feedburner.com/~r/LearningOnRails/~4/MvZNctwt4Fw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.lucashungaro.com/2012/04/10/capistrano-and-whenever-updating-the-crontab-of-the-runner-user/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.lucashungaro.com/2012/04/10/capistrano-and-whenever-updating-the-crontab-of-the-runner-user/</feedburner:origLink></item>
		<item>
		<title>Compilando uma versão local do Rails Guides</title>
		<link>http://feedproxy.google.com/~r/LearningOnRails/~3/ybKTEZABElA/</link>
		<comments>http://blog.lucashungaro.com/2012/03/06/compilando-uma-versao-local-do-rails-guides/#comments</comments>
		<pubDate>Tue, 06 Mar 2012 03:48:41 +0000</pubDate>
		<dc:creator>Lucas Húngaro</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Tutoriais]]></category>

		<guid isPermaLink="false">http://blog.lucashungaro.com/?p=429</guid>
		<description><![CDATA[Para compilar uma versão local do Rails Guides, você pode fazer o seguinte processo: 1) Descubra qual o seu &#8220;gem path&#8221;, o local onde suas gems estão instaladas. No meu caso, o Rails está instalado diretamente no sistema e não utilizo rvm ou rbenv. Para encontrar essa informação, utilizei o comando &#8220;gem env&#8221; diretamente no [...]]]></description>
			<content:encoded><![CDATA[<p>Para compilar uma versão local do Rails Guides, você pode fazer o seguinte processo:</p>
<p>1) Descubra qual o seu &#8220;gem path&#8221;, o local onde suas gems estão instaladas. No meu caso, o Rails está instalado diretamente no sistema e não utilizo rvm ou rbenv. Para encontrar essa informação, utilizei o comando &#8220;gem env&#8221; diretamente no terminal. Meu path é &#8220;/usr/local/lib/ruby/gems/1.9.1/gems/&#8221;.</p>
<p>2) Acesse o diretório da gem railties. Essa gem é como um &#8220;rails-core&#8221;, sendo o núcleo e o &#8220;hub&#8221; em que todas as outras gems que compõe o framework (e também extensões de terceiros) se registram para serem carregadas:</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">lucashungaro<span style="color: #000000; font-weight: bold;">@</span>IronMan:<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>ruby<span style="color: #000000; font-weight: bold;">/</span>gems<span style="color: #000000; font-weight: bold;">/</span>1.9.1<span style="color: #000000; font-weight: bold;">/</span>gems
$ <span style="color: #7a0874; font-weight: bold;">cd</span> railties-3.2.2<span style="color: #000000; font-weight: bold;">/</span>guides
&nbsp;
lucashungaro<span style="color: #000000; font-weight: bold;">@</span>IronMan:<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>ruby<span style="color: #000000; font-weight: bold;">/</span>gems<span style="color: #000000; font-weight: bold;">/</span>1.9.1<span style="color: #000000; font-weight: bold;">/</span>gems<span style="color: #000000; font-weight: bold;">/</span>railties-3.2.2<span style="color: #000000; font-weight: bold;">/</span>guides <span style="color: #7a0874; font-weight: bold;">&#40;</span>master<span style="color: #7a0874; font-weight: bold;">&#41;</span>
$ gem <span style="color: #c20cb9; font-weight: bold;">install</span> RedCloth
&nbsp;
lucashungaro<span style="color: #000000; font-weight: bold;">@</span>IronMan:<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>ruby<span style="color: #000000; font-weight: bold;">/</span>gems<span style="color: #000000; font-weight: bold;">/</span>1.9.1<span style="color: #000000; font-weight: bold;">/</span>gems<span style="color: #000000; font-weight: bold;">/</span>railties-3.2.2<span style="color: #000000; font-weight: bold;">/</span>guides <span style="color: #7a0874; font-weight: bold;">&#40;</span>master<span style="color: #7a0874; font-weight: bold;">&#41;</span>
$ ruby rails_guides.rb
&nbsp;
lucashungaro<span style="color: #000000; font-weight: bold;">@</span>IronMan:<span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>local<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>ruby<span style="color: #000000; font-weight: bold;">/</span>gems<span style="color: #000000; font-weight: bold;">/</span>1.9.1<span style="color: #000000; font-weight: bold;">/</span>gems<span style="color: #000000; font-weight: bold;">/</span>railties-3.2.2<span style="color: #000000; font-weight: bold;">/</span>guides <span style="color: #7a0874; font-weight: bold;">&#40;</span>master<span style="color: #7a0874; font-weight: bold;">&#41;</span>
$ <span style="color: #c20cb9; font-weight: bold;">mv</span> output ~<span style="color: #000000; font-weight: bold;">/</span>projects<span style="color: #000000; font-weight: bold;">/</span>documentation<span style="color: #000000; font-weight: bold;">/</span>rails_guides_3.2.2</pre></div></div>

<p>Isso irá compilar os guias no diretório local &#8220;output&#8221;, o qual movemos para uma localização mais familiar. Não encontrei uma forma de mudar o diretório com argumentos na linha de comando. Você pode fazer isso se chamar o gerador via código, no entanto. O script aceita outras opções via linha de comando, como a opção de gerar guias para o Edge Rails ou versão Kindle, entre outras.</p>
<p>3) Ao término do processo, teremos os guias compilados em HTML no diretório indicado. Para acessá-los você pode criar um bookmark em seu browser ou utilizar um SSB. Prefiro a segunda maneira e, para isso, utilizo o <a href="http://fluidapp.com/">Fluid</a> (para encontrar alguns ótimos ícones visite <a href="http://www.flickr.com/groups/fluid_icons/">esse grupo no Flickr</a>. Basta criar uma nova aplicação e apontar para o diretório em que geramos os guias, iniciando pelo arquivo index.html.</p>
<div class="wp-caption aligncenter" style="width: 500px"><a href="http://blog.lucashungaro.com/wp-content/uploads/2012/03/guides.png"><img src="http://blog.lucashungaro.com/wp-content/uploads/2012/03/guides.png" title="Rails Guides com Fluid" width="490" height="328" class="size-full" /></a><p class="wp-caption-text">Rails Guides com Fluid</p></div>
<img src="http://feeds.feedburner.com/~r/LearningOnRails/~4/ybKTEZABElA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.lucashungaro.com/2012/03/06/compilando-uma-versao-local-do-rails-guides/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.lucashungaro.com/2012/03/06/compilando-uma-versao-local-do-rails-guides/</feedburner:origLink></item>
		<item>
		<title>Modularity on Rails</title>
		<link>http://feedproxy.google.com/~r/LearningOnRails/~3/IAteC3Muc7w/</link>
		<comments>http://blog.lucashungaro.com/2012/03/01/modularity-on-rails/#comments</comments>
		<pubDate>Fri, 02 Mar 2012 01:06:06 +0000</pubDate>
		<dc:creator>Lucas Húngaro</dc:creator>
				<category><![CDATA[Opinião]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://blog.lucashungaro.com/?p=424</guid>
		<description><![CDATA[Following my last article I&#8217;d like to elaborate on my opinions. First, let&#8217;s review some things: Yes, I know you can deactivate a lot of the bundled stuff in Rails; that doesn&#8217;t solve any of the issues. Yes, I&#8217;m aware of Railties; It&#8217;s nice, well built, a good step forward; still doesn&#8217;t solve any of [...]]]></description>
			<content:encoded><![CDATA[<p>Following my last article I&#8217;d like to elaborate on my opinions. </p>
<p>First, let&#8217;s review some things:</p>
<ul>
<li>Yes, I know you <a href="https://gist.github.com/1942658">can deactivate a lot of the bundled stuff in Rails</a>; that doesn&#8217;t solve any of the issues.</li>
<li>Yes, I&#8217;m aware of Railties; It&#8217;s nice, well built, a good step forward; still doesn&#8217;t solve any of the isses.</li>
<li>Most of the people who reacted badly to my article (and <a href="http://twitter.com/merbist">@merbist</a>&#8216;s one) pointed out that, to use and understand Rails&#8217; &#8220;modularity&#8221; you&#8217;re supposed to <a href="http://www.amazon.com/Crafting-Rails-Applications-Development-Programmers/dp/1934356735/ref=sr_1_1?ie=UTF8&#038;qid=1330648115&#038;sr=8-1">buy a book</a>; I don&#8217;t think it should be necessary (nothing against the book, it&#8217;s very good)</li>
<p>The issues I pointed out converge to one thing: modularity <strong>isn&#8217;t</strong> configurability. Yeah, I can edit my default generated Rails app and remove all sorts of things, including using some hackish code to remove middlewares from its stack. This isn&#8217;t modularity on the application-level.</p>
<p>I know that Rails&#8217;s <strong>internals</strong> are more modular on Rails 3 than they&#8217;ve ever been. I&#8217;ve saw Jose Valim&#8217;s <a href="http://en.oreilly.com/rails2011/public/schedule/detail/19579"> talk about how they&#8217;ve applied SOLID principles to achieve that</a>, it&#8217;s really nice (read the slides if you can, it pays off). I&#8217;m not talking about that. I&#8217;d like to emphasize that I&#8217;m talking about modularity at the application level, not at internal code level.</p>
<p>Here&#8217;s an example (hypothetical context, of course):</p>

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ rails new my_app <span style="color: #666666; font-style: italic;"># generates a lean app (not a Sinatra-style app, a Rails app without the unneeded stuff)</span>
&nbsp;
... <span style="color: #666666; font-style: italic;"># days after</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Hmmm, I need to send e-mails!</span>
$ <span style="color: #7a0874; font-weight: bold;">cd</span> my_app
$ rails add actionmailer <span style="color: #666666; font-style: italic;"># adds and installs actionmailer, generates the boilerplate needed</span>
&nbsp;
<span style="color: #666666; font-style: italic;"># Hmmm, I need to speed up my assets load time!</span>
$ rails add rails-assets-pipeline</pre></div></div>

<p><strong>Modular</strong>. <strong>Apps</strong>. Things I can incrementally build upon. Now, mailer should probably be there by default, but you get the idea.</p>
<p>These gems would be separated from Rails core. I really don&#8217;t care if a &#8220;full&#8221; Rails app ends up installing 100 gems as long as I&#8217;m in control of that and can start with way less.</p>
<p>What&#8217;s the advantages?</p>
<ul>
<li>Easier to learn: beginners will have a better experience since they can learn the framework gradually;</li>
<li>Still powerful: that doesn&#8217;t force you to dumb it down, as many suggest. Modular apps suit the needs of novices and experienced developers as well;</li>
<li>Goodbye clutter and unneeded code: the framework will only load the code I need. Boot time will be decreased as well as memory consumption. Yes, I know that if you deactivate something today, most of the code won&#8217;t be loaded, which gets us to&#8230;</li>
<li>Less code to understand: it will be easier to contribute to the framework as it will have way less code and I can gradually dig in. I can contribute with the core without stumbling into the assets pipeline, for example.</li>
</ul>
<p>Well, I could elaborate more on that, but it&#8217;s the main idea. Rails&#8217; internals are way better, yes, and that&#8217;s awesome. But the framework still lags behind on many things I think should receive priority instead of adding built-in support for SASS, CoffeeScript and things like that. I&#8217;m currently taking a look at Rails&#8217; codebase to see how I can fit these ideas in. I hope to have some pull requests ready soon. If you&#8217;re interested in helping, please contact me.</p>
<img src="http://feeds.feedburner.com/~r/LearningOnRails/~4/IAteC3Muc7w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.lucashungaro.com/2012/03/01/modularity-on-rails/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		<feedburner:origLink>http://blog.lucashungaro.com/2012/03/01/modularity-on-rails/</feedburner:origLink></item>
		<item>
		<title>Rails has entered the framework death spiral</title>
		<link>http://feedproxy.google.com/~r/LearningOnRails/~3/7xPiyvXg9a8/</link>
		<comments>http://blog.lucashungaro.com/2012/03/01/rails-has-entered-the-framework-death-spiral/#comments</comments>
		<pubDate>Thu, 01 Mar 2012 04:44:52 +0000</pubDate>
		<dc:creator>Lucas Húngaro</dc:creator>
				<category><![CDATA[Opinião]]></category>
		<category><![CDATA[Rails]]></category>

		<guid isPermaLink="false">http://blog.lucashungaro.com/?p=423</guid>
		<description><![CDATA[I usually write here in Brazilian Portuguese but this post is written in English in the hope of getting some useful attention and discussion going on (yes, wishful thinking). Before we start this, let&#8217;s make some things clear. When I criticize Rails there&#8217;s two common reactions: The Lovers: &#8220;OMG, DHH and the Core Team are [...]]]></description>
			<content:encoded><![CDATA[<p>I usually write here in Brazilian Portuguese but this post is written in English in the hope of getting some useful attention and discussion going on (yes, wishful thinking).</p>
<p>Before we start this, let&#8217;s make some things clear. When I criticize Rails there&#8217;s two common reactions:</p>
<p>  <strong>The Lovers</strong>:</p>
<ul>
<li>&#8220;OMG, DHH and the Core Team are awesome, they know what&#8217;s better for you, stop crying!&#8221;</li>
<li>&#8220;Well, stop using Rails and create something better!&#8221;</li>
<li>&#8220;You should not criticize the tool that pays your bills!&#8221;</li>
</ul>
<p>  <strong>The Haters</strong>:</p>
<ul>
<li>&#8220;Yes! Yes! Let&#8217;s burn these motherfuckers!&#8221;</li>
</ul>
<p>Let me be totally clear here: Rails is very useful and I like it a lot (although I used to like it way more). <a href="http://caremad.com">Otherwise I would just dismiss it and don&#8217;t even bother trying to get some attention to the issues I&#8217;ll describe</a>. I respect the work and effort of so many people that keep the framework going fixing bugs and adding features. You should too, it&#8217;s not a walk in the park and very few people actually get some time to do this kind of work. A special mention goes to Aaron Patterson (<a href="http://twitter.com/tenderlove">@tenderlove</a>), a guy who relentlessly keeps cleaning up the mess that Rails&#8217; codebase has become while still keeping his humility (sadly, a rare trait in our community).</p>
<p>Some days ago, when talking with a friend, he said &#8220;Rails has entered the framework death spiral &#8211; it&#8217;s now adding features for feature-sake&#8221;. I agree. The &#8220;Rails is opinionated software&#8221; idea is clearly lost as it&#8217;s trying to embrace everything and has turned into a playground for some people (not the entire team, to be clear) instead of a framework that shapes the way web applications are created (that paradigm is shifting and meanwhile Rails is messing around with CoffeeScript and SASS).</p>
<p>One example of this &#8220;playground theory&#8221;? Releasing a piece of crap like the assets pipeline, clearly rushed and so fucked up that it makes me think if it&#8217;s the worse thing I ever had to use to build software, occupying a honorable spot besides the Struts framework, ASP and JavaServer Faces.</p>
<p>The main problem, in my humble opinion, is: Rails has turned into bloatware. I see the problem from two angles: as a potential contributor and as a user of the framework.</p>
<p><strong>As a contributor</strong></p>
<p>Rails has so many things included by default now that the code is really big. I tried to understand it some time ago and got quickly frustrated by the massive amount of coupled code and features that distract you from the main workflow of the framework. Yes, I could probably just get some ticket and solve a bug, but I like to understand the whole before going around throwing code like crazy to get some commits in. OSS activists will probably bash me for this, calling me lazy, but it&#8217;s the way I work, sorry.</p>
<p>The solution? Well, my suggestion is this: the rails gem should contain only the core, the request processing cycle and hooks for the other parts to hang in (ORMs, template engines, other gems in general). It already has this in some form, a framework called Railties, but all the things that hook into it are still in the same codebase, divided in a few other gems. </p>
<p>The asset pipeline is a main offender here and the easiest example to bring to the surface. This thing should *really* be into its own gem and out of Rails. It could be included in Rails&#8217; default Gemfile, I don&#8217;t care, but please do not throw more code into the mess. I won&#8217;t even start the discussion about the quality of the pipeline per se, but I digress. If you want the default approach, the one the Core Team chose, just generate a full app and install de default gems. Otherwise we could have a lean application generator that remove all the uneeded dependencies without hacks. Better yet if that one could be the default.</p>
<p>If my memory isn&#8217;t failing me, I believe Merb did things this way. Besides lessening the burden on contributors it should force people to write decoupled code, something the Rails Core Team has been improving on for some time now, by the way.</p>
<p>Yes, I know Rails included extra things like ActionMailer and ActiveRecord from the beginning and they&#8217;re independent gems. As I said before, I&#8217;m fine with default choices, but I also think that Rails&#8217; starting point should be a lean and simple mini-stack that could be easily incremented as the user needs it to be.</p>
<p><strong>As a user</strong></p>
<p>People who are experienced with Rails tend to forget that beginners do exist. Most of the so called &#8220;Railers&#8221; I know see themselves as a kind of superior being surfing the waves of awesomeness, forgetting that legacy must be supported and new people will try Rails. Funny thing is that the developers that use Rails as a mere tool (what it is) see this issue clearly, while people that see it as a religious cult dismiss it.</p>
<p>The first issue is legacy. Rails completely ignore this (as is common with frameworks in so called &#8220;non-enterprise&#8221; ecosystems) and makes no effort to support people that work with legacy code. The community itself fails hard at this, as we don&#8217;t even talk about that as we should. Think about how rare it is to see a talk about legacy applications on conferences in contrast to the plethora of talks about new features/libraries or how you should be writing your code. We fail hard here.</p>
<p>The second issue is that, as of today, Rails is incredibly hard for beginners to learn and use effectively. It&#8217;s slow, has a freaking unbelievable amount of dependencies right of the bat (this can be normal down the road, not by default), it&#8217;s cumbersome to set up (don&#8217;t you love some gem version hell?), it&#8217;s not quick to get up and running anymore. I usually joke that the &#8220;15 minutes blog&#8221; today should be called &#8220;the 1 hour and 30 minutes blog&#8221;. That&#8217;s not to mention the big disparity between the official literature and documentation (&#8220;the DHH way&#8221;) and the way real Rails apps are developed.</p>
<p><strong>EDIT</strong>: to be fair, I installed the latest Rails and generated a new app. No version hell this time, hurray! The last three times I did it, it was a nightmare. Things are still slow though. You can generage your application with &#8220;rails new my_app &#8211;skip-sprockets &#8211;skip-test-unit&#8221; to drop the generation time from ~2 minutes to about ~30 seconds. Other flags like &#8211;skip-active-record and &#8211;skip-javascript are available to bypass some default dependencies.</p>
<p>It&#8217;s hard for people who already knows Rails to imagine how it is to begin with the framework today. I&#8217;ve seen beginners trying it and it was ugly. Think about how many unrelated things someone has to go through to understand a simple &#8220;Hello World&#8221; in a default Rails application today.</p>
<p>What got me interested in Rails was the &#8220;batteries included&#8221; approach, yes. But there was a thin line and, to me, that line has been crossed. Rails went past the line of &#8220;including everything you need for a quick start&#8221; to &#8220;including everything the Core Team thinks you need to build a gigantic web application following every techniques they find appropriate&#8221;. Yes, I know it&#8217;s best practice to minify my JavaScript but I&#8217;m a grow up, let me do it the way I want without clogging up the framework with a lot of useless code (yes, I can deactivate it, but it&#8217;s still useless since I won&#8217;t use it and it will slow my boot time and bloat the framework code, hence the idea of splitting Rails into more gems and do not install them by default nor include them in the same codebase).</p>
<p><strong>Conclusion</strong></p>
<p>The Rails framework should really get trimmed down. Non-fundamental trinket should be separated and, maybe, we could have two application generators: a &#8220;lean&#8221; (maybe just ActionPack and Railties, something like that) one and a &#8220;full&#8221; one. That way it would be a lot easier to grasp the framework code and contribute while allowing newcomers to taste the goodies gradually, learning instead of being drowned into a lot of concerns that really doesn&#8217;t relate to the core of developing a well built application.</p>
<p><strong>EDIT</strong>: Yes, the title of the article is harsh and I recognize it does not reflect what I wanted to suggest here. It was wrong and tabloid style. It was chosen out of frustration, which shouldn&#8217;t be a reason to do it. The intention of the article is to spark a good discussion, not to be alarmist and accusatory, which the title makes it sound like.</p>
<img src="http://feeds.feedburner.com/~r/LearningOnRails/~4/7xPiyvXg9a8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.lucashungaro.com/2012/03/01/rails-has-entered-the-framework-death-spiral/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://blog.lucashungaro.com/2012/03/01/rails-has-entered-the-framework-death-spiral/</feedburner:origLink></item>
		<item>
		<title>iPhone/iPad: minhas aplicações favoritas</title>
		<link>http://feedproxy.google.com/~r/LearningOnRails/~3/4xuNa5_rEMg/</link>
		<comments>http://blog.lucashungaro.com/2011/09/03/iphoneipad-minhas-aplicacoes-favoritas/#comments</comments>
		<pubDate>Sat, 03 Sep 2011 19:34:50 +0000</pubDate>
		<dc:creator>Lucas Húngaro</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Dicas]]></category>
		<category><![CDATA[Entretenimento]]></category>

		<guid isPermaLink="false">http://blog.lucashungaro.com/?p=421</guid>
		<description><![CDATA[Simples e rápido, minhas aplicações favoritas para iOS: Camera+: aplicativo para tirar fotos com opções adicionais (como controle de exposição separado do foco) e efeitos de pós-processamento. Hipstamatic: provavelmente a app que lançou a moda de efeitos vintage em fotos. A mais utilizada hoje é o Instagram, mas ainda prefiro o Hipstamatic. 1Password: pra quem [...]]]></description>
			<content:encoded><![CDATA[<p>Simples e rápido, minhas aplicações favoritas para iOS:</p>
<ul>
<li><strong>Camera+</strong>: aplicativo para tirar fotos com opções adicionais (como controle de exposição separado do foco) e efeitos de pós-processamento.</li>
<li><strong>Hipstamatic</strong>: provavelmente a app que lançou a moda de efeitos vintage em fotos. A mais utilizada hoje é o Instagram, mas ainda prefiro o Hipstamatic.</li>
<li><strong>1Password</strong>: pra quem utiliza a versão desktop, é uma grande mão na roda pra lembrar senhas quando o celular é tudo que temos à mão.</li>
<li><strong>Dropbox</strong>: ótimo pra visualizar documentos e fotos.</li>
<li><strong>Convertbot</strong>: sou fanboy da Tapbots e uso todas as aplicações dos caras. O Convertbot é um conversor de unidades com muitas opções disponíveis e uma UI fantástica.</li>
<li><strong>Pastebot</strong>: múltiplas áreas de transferência no iPhone, com direito à operações sobre o conteúdo copiado (como efeitos sobre imagens ou tradução de textos). Além disso, com o Pastebot Sync, é possível copiar e colar conteúdos entre Mac e iPhone e vice-versa.</li>
<li><strong>Tweetbot</strong>: cliente de Twitter da Tapbots. UI sensacional, gestures, filtros, possibilidade de usar listas como timeline principal e várias outras opções.</li>
<li><strong>Weightbot</strong>: aplicação para acompanhamento de peso, com estabelecimento de metas, cálculo de IMC e gráficos de projeções (pra você ver se está no ritmo certo pra chegar lá).</li>
<li><strong>Shazam</strong>: está num café e começa a tocar uma música boa, mas você não sabe o nome e/ou artista? Use o Shazam pra identificá-la. Uso bastante com trilhas sonoras de filmes também. <img src='http://blog.lucashungaro.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </li>
<li><strong>Kindle</strong>: leitor de e-books, se integra muito bem com o Kindle for Mac.</li>
<li><strong>Reeder</strong>: ótimo leitor de feeds.</li>
</ul>
<p>Hora dos jogos:</p>
<ul>
<li><strong>Angry Birds e Angry Birds Seasons</strong>: clássico. Ótimo passatempo pra longas esperas.</li>
<li><strong>Cut the Rope e Cut the Rope: experiments</strong>: ótimo jogo que combina elementos de física e habilidade de raciocínio pra resolver os problemas.</li>
<li><strong>Contre Jour</strong>: uma mistura de Angry Birds, Cut the Rope, Portal e outros jogos, com uma trilha sonora e visuais muito bons.</li>
<li><strong>Rage HD</strong>: prévia do próximo jogo para consoles da id Software, um shooter muito bem feito.</li>
<li><strong>Infinity Blade</strong>: provavelmente o jogo com gráficos mais poderosos no iOS, leva o device (e a bateria) ao limite. O jogo em si não é uma obra-prima, mas vale pelos gráficos.</li>
<li><strong>Death Rally</strong>: corrida + destruição, power ups, jogo em estilo bem clássico com ótimos gráficos e controles.</li>
<li><strong>Fruit Ninja</strong>: mais um jogo clássico e ótimo pra passar o tempo.</li>
<li><strong>Civilization Revolutions</strong>: pra quem é fã da franquia, uma versão simplificada do Civ, dá pra fazer um jogo completo em pouco mais de uma hora.</li>
</ul>
<p>É isso! <img src='http://blog.lucashungaro.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<img src="http://feeds.feedburner.com/~r/LearningOnRails/~4/4xuNa5_rEMg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.lucashungaro.com/2011/09/03/iphoneipad-minhas-aplicacoes-favoritas/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.lucashungaro.com/2011/09/03/iphoneipad-minhas-aplicacoes-favoritas/</feedburner:origLink></item>
		<item>
		<title>Gems “locais”, irb e Bundler</title>
		<link>http://feedproxy.google.com/~r/LearningOnRails/~3/PeKrYuAwOGY/</link>
		<comments>http://blog.lucashungaro.com/2011/07/23/gems-locais-irb-e-bundler/#comments</comments>
		<pubDate>Sat, 23 Jul 2011 18:40:56 +0000</pubDate>
		<dc:creator>Lucas Húngaro</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Dicas]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.lucashungaro.com/?p=419</guid>
		<description><![CDATA[Gosto de algumas gems como o wirble, que adicionam algumas funcionalidades ao irb (e, por consequência, ao console do Rails). O problema é que, em projetos que utilizam o Bundler, fica complicado adicionar esse tipo de gem ao Gemfile, pois elas não são realmente dependências do projeto e nem todos gostariam de utilizá-las. Como programadores [...]]]></description>
			<content:encoded><![CDATA[<p>Gosto de algumas gems como o <a href="https://rubygems.org/gems/wirble">wirble</a>, que adicionam algumas funcionalidades ao irb (e, por consequência, ao console do Rails). O problema é que, em projetos que utilizam o Bundler, fica complicado adicionar esse tipo de gem ao Gemfile, pois elas não são realmente dependências do projeto e nem todos gostariam de utilizá-las.</p>
<p>Como programadores costumam ser bem radicais (ainda mais com essa mania de ser &#8220;opinionado&#8221;), isso sempre gera discussões e atritos. Eu já penso que é mais fácil simplesmente buscar uma solução, e eis aqui uma: <a href="https://gist.github.com/1096494">https://gist.github.com/1096494</a>.</p>
<p>Colocando esse snippet no seu arquivo .irbrc, ao abrir o irb (ou console do Rails), todas as gems do gemset global do RVM serão colocadas no load path, podendo assim serem requeridas na sequência. Eu não costumo usar gemsets por projeto (uso apenas o Bundler, da maneira explicada <a href="http://ryan.mcgeary.org/2011/02/09/vendor-everything-still-applies/">nesse post</a>), mas deixo o gemset global com algumas gems para esse fim. Meu arquivo .irbrc <a href="https://github.com/lucashungaro/dotfiles/blob/master/irbrc">está disponível no GitHub</a>.</p>
<p>Essa solução não é lá muito elegante, mas funciona muito bem para gems utilizadas no irb. Há algum tempo propus uma solução na lista do Bundler e recebi algumas sugestões, porém nenhuma me agradou (como, por exemplo, obrigar todo mundo que não quer as gems a usar a flag &#8211;without a cada bundle install). A discussão <a href="http://groups.google.com/group/ruby-bundler/browse_thread/thread/f05d8613fc434c37">pode ser vista aqui</a>. Até cheguei a fazer um fork do Bundler para implementar algum tipo de metadado para controlar isso, mas o código é bem complicado e acoplado, então deixei pra lá. <img src='http://blog.lucashungaro.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<img src="http://feeds.feedburner.com/~r/LearningOnRails/~4/PeKrYuAwOGY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.lucashungaro.com/2011/07/23/gems-locais-irb-e-bundler/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://blog.lucashungaro.com/2011/07/23/gems-locais-irb-e-bundler/</feedburner:origLink></item>
		<item>
		<title>SOLID Ruby: Liskov Substitution Principle e Interface Segregation Principle</title>
		<link>http://feedproxy.google.com/~r/LearningOnRails/~3/N8i0FghOiVo/</link>
		<comments>http://blog.lucashungaro.com/2011/05/18/solid-ruby-liskov-substitution-principle-e-interface-segregation-principle/#comments</comments>
		<pubDate>Wed, 18 May 2011 22:38:49 +0000</pubDate>
		<dc:creator>Lucas Húngaro</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Test-Driven Development]]></category>

		<guid isPermaLink="false">http://blog.lucashungaro.com/?p=416</guid>
		<description><![CDATA[Para fechar os cinco princípios do SOLID, vamos falar sobre os dois princípios restantes: Liskov Substitution Principle (LSP) e Interface Segregation Principle (ISP). Como já foi falado anteriormente, esses princípios foram formulados com linguagens estáticas em mente e, por essa razão, precisam ser &#8220;adaptados&#8221; para que sejam aplicados em linguagens dinâmicas. Note que, em suas [...]]]></description>
			<content:encoded><![CDATA[<p>Para fechar os cinco princípios do SOLID, vamos falar sobre os dois princípios restantes: <a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle">Liskov Substitution Principle</a> (LSP) e <a href="http://en.wikipedia.org/wiki/Interface_segregation_principle">Interface Segregation Principle</a> (ISP).</p>
<p>Como já foi falado anteriormente, esses princípios foram formulados com linguagens estáticas em mente e, por essa razão, precisam ser &#8220;adaptados&#8221; para que sejam aplicados em linguagens dinâmicas. Note que, em suas formas originais, esses princípios em geral recorrem a técnicas como herança para contornar as &#8220;amarras&#8221; do sistema estático de tipos.</p>
<p>No caso do LSP temos mais um exemplo disso. Em sua forma original ele é definido da seguinte forma:</p>
<blockquote><p>If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2, then S is a subtype of T.</p></blockquote>
<p>O que foi &#8220;traduzido&#8221; para o OOP da seguinte forma:</p>
<blockquote><p>Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.</p></blockquote>
<p>Em Ruby isso não é muito problemático pois, como sabemos, não estamos presos à tipos. O importante, como já vimos com o OCP, é manter a mesma interface, de forma que se precisarmos modificar alguma entidade, as demais entidades que dela dependem não precisem ser modificadas.</p>
<p>Além da interface, também precisamos prestar atenção ao comportamento. Modificações no comportamento podem fazer com que clientes da entidade sofram consequências inesperadas.</p>
<p>Já o ISP é definido da seguinte forma:</p>
<blockquote><p>Clients should not be forced to depend upon interfaces that they do not use.</p></blockquote>
<p>Isso quer dizer que um cliente (entidade que depende de alguma outra) não deve depender de interfaces não utilizadas por ele pois, em caso de modificação nessa interface, mesmo que o cliente em questão não a utilize, também terá que ser modificado.</p>
<p>Em linguagens estáticas há uma série de técnicas e artifícios para atingir isso. Em Ruby, o Duck Typing nos entrega esse princípio &#8220;de graça&#8221;, já que cada entidade depende apenas da interface que utiliza, independente do restante (e de tipos). Apesar disso, devemos sempre buscar entidades com interfaces coesas e bem delimitadas, evitando que sejam muito extensas e genéricas (o SRP se aplica aqui também). Aplicar o design pattern <a href="http://en.wikipedia.org/wiki/Adapter_pattern">Adapter</a> é uma boa forma de respeitar isso.</p>
<p>Bem, é fácil perceber que os últimos três princípios discutidos (OCP, LSP e ISP) lidam diretamente com formas de garantir interfaces estáveis para atingirmos o nosso objetivo de evitar que mudanças no código gerem um &#8220;efeito dominó&#8221; e façam com que tenhamos que alterar várias partes do software.</p>
<p>Mas, já que não temos estruturas como Interfaces e classes abstratas para garantir que estamos respeitando a interface definida, como garantir a aplicação desses princípios? Bom, há algumas formas para fazer isso. Você pode &#8220;emular&#8221; uma interface da seguinte forma:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> MyInterface
  <span style="color:#9966CC; font-weight:bold;">def</span> method_1
    <span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#996600;">&quot;abstract method called&quot;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> method_2
    <span style="color:#CC0066; font-weight:bold;">raise</span> <span style="color:#996600;">&quot;abstract method called&quot;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># and so on...</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> MyClass <span style="color:#006600; font-weight:bold;">&lt;</span> MyInterface
  <span style="color:#9966CC; font-weight:bold;">def</span> method_1
    <span style="color:#008000; font-style:italic;"># do something</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> method_2
    <span style="color:#008000; font-style:italic;"># do something</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Obs: também pode ser feito através de módulos e mixins ao invés de herança.</p>
<p>Isso funciona, mas não é muito o estilo Ruby, certo? A maneira que prefiro fazer é através de specs. Sempre que vou criar um wrapper/adapter ou qualquer estrutura que precise de uma interface estável mesmo quando o código encapsulado for modificado, crio um grupo de &#8220;specs de interface&#8221; e uso ela para toda estrutura que precise implementar a mesma.</p>
<p>Por exemplo, poderíamos escrever um cliente para o Twitter e escrever nosso código de modo que a gem que consome a API do serviço possa ser trocada sem maiores consequências:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;">&nbsp;
<span style="color:#008000; font-style:italic;"># app/adapters/twitter_gem_adapter.rb</span>
<span style="color:#9966CC; font-weight:bold;">class</span> TwitterGemAdapter
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">timeline</span><span style="color:#006600; font-weight:bold;">&#40;</span>page=<span style="color:#006666;">1</span>, per_page=<span style="color:#006666;">5</span>, since_id = <span style="color:#0000FF; font-weight:bold;">nil</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    options = <span style="color:#006600; font-weight:bold;">&#123;</span>:page <span style="color:#006600; font-weight:bold;">=&gt;</span> page, <span style="color:#ff3333; font-weight:bold;">:count</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> per_page<span style="color:#006600; font-weight:bold;">&#125;</span>
    options<span style="color:#006600; font-weight:bold;">&#91;</span><span style="color:#ff3333; font-weight:bold;">:since_id</span><span style="color:#006600; font-weight:bold;">&#93;</span> = since_id <span style="color:#9966CC; font-weight:bold;">if</span> since_id
&nbsp;
    Twitter.<span style="color:#9900CC;">home_timeline</span><span style="color:#006600; font-weight:bold;">&#40;</span>options<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">update</span><span style="color:#006600; font-weight:bold;">&#40;</span>text<span style="color:#006600; font-weight:bold;">&#41;</span>
    Twitter.<span style="color:#9900CC;">update</span><span style="color:#006600; font-weight:bold;">&#40;</span>text<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">reply</span><span style="color:#006600; font-weight:bold;">&#40;</span>in_reply_to_status_id, text<span style="color:#006600; font-weight:bold;">&#41;</span>
    Twitter.<span style="color:#9900CC;">update</span><span style="color:#006600; font-weight:bold;">&#40;</span>text, <span style="color:#ff3333; font-weight:bold;">:in_reply_to_status_id</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> in_reply_to_status_id<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">retweet</span><span style="color:#006600; font-weight:bold;">&#40;</span>tweet_id<span style="color:#006600; font-weight:bold;">&#41;</span>
    Twitter.<span style="color:#9900CC;">retweet</span><span style="color:#006600; font-weight:bold;">&#40;</span>tweet_id<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">favorite</span><span style="color:#006600; font-weight:bold;">&#40;</span>tweet_id<span style="color:#006600; font-weight:bold;">&#41;</span>
    Twitter.<span style="color:#9900CC;">favorite_create</span><span style="color:#006600; font-weight:bold;">&#40;</span>tweet_id<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># spec/support/shared_examples/twitter_adapter_examples.rb</span>
<span style="color:#9966CC; font-weight:bold;">module</span> TwitterAdapterExamples
  shared_examples_for <span style="color:#996600;">&quot;any adapter for a twitter api gem&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    it <span style="color:#006600; font-weight:bold;">&#123;</span> should respond_to<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:timeline</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#125;</span>
    it <span style="color:#006600; font-weight:bold;">&#123;</span> should respond_to<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:update</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#125;</span>
    it <span style="color:#006600; font-weight:bold;">&#123;</span> should respond_to<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:reply</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#125;</span>
    it <span style="color:#006600; font-weight:bold;">&#123;</span> should respond_to<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:retweet</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#125;</span>
    it <span style="color:#006600; font-weight:bold;">&#123;</span> should respond_to<span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#ff3333; font-weight:bold;">:favorite</span><span style="color:#006600; font-weight:bold;">&#41;</span><span style="color:#006600; font-weight:bold;">&#125;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># spec/adapters/twitter_gem_adapter_spec.rb</span>
describe TwitterGemAdapter <span style="color:#9966CC; font-weight:bold;">do</span>
  context <span style="color:#996600;">&quot;API contract&quot;</span> <span style="color:#9966CC; font-weight:bold;">do</span>
    subject <span style="color:#006600; font-weight:bold;">&#123;</span> TwitterGemAdapter <span style="color:#006600; font-weight:bold;">&#125;</span>
&nbsp;
    it_behaves_like <span style="color:#996600;">&quot;any adapter for a twitter api gem&quot;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># other specs ...</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Aqui utilizamos a feature de &#8220;exemplos compartilhados&#8221; do RSpec, mas isso pode ser feito facilmente em outros frameworks. O importante é que, através dessas specs, garantimos que qualquer adapter implemente a mesma interface. Nesse caso cuidamos apenas disso, mas qualquer comportamento comum também pode ser especificado da mesma forma.</p>
<p>Material recomendado:</p>
<ul>
<li><a href="http://blog.objectmentor.com/articles/2008/09/06/the-liskov-substitution-principle-for-duck-typed-languages">The Liskov Substitution Principle for &#8220;Duck-Typed&#8221; Languages</a></li>
<li><a href="http://confreaks.net/videos/185-rubyconf2009-solid-ruby">SOLID Ruby, by Jim Weirich &#8211; RubyConf 2009</a></li>
<li><a href="http://confreaks.net/videos/240-goruco2009-solid-object-oriented-design">SOLID Object-Oriented Design, by Sandi Metz, GoRuCo 2009</a></li>
</ul>
<img src="http://feeds.feedburner.com/~r/LearningOnRails/~4/N8i0FghOiVo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.lucashungaro.com/2011/05/18/solid-ruby-liskov-substitution-principle-e-interface-segregation-principle/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.lucashungaro.com/2011/05/18/solid-ruby-liskov-substitution-principle-e-interface-segregation-principle/</feedburner:origLink></item>
		<item>
		<title>SOLID Ruby: Open-Closed Principle</title>
		<link>http://feedproxy.google.com/~r/LearningOnRails/~3/4xLCVJFtEtk/</link>
		<comments>http://blog.lucashungaro.com/2011/05/11/solid-ruby-open-closed-principle/#comments</comments>
		<pubDate>Wed, 11 May 2011 17:43:22 +0000</pubDate>
		<dc:creator>Lucas Húngaro</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.lucashungaro.com/?p=413</guid>
		<description><![CDATA[Muitos dos princípios da programação orientada a objetos foram criados com linguagens estáticas em mente. Esse é o caso do Open-Closed Principle, enunciado da seguinte maneira: Software entities (classes, modules, functions, etc) should be open for extension, but closed for modification. Originalmente, a ideia é que, uma fez finalizada, uma entidade só poderia ser modificada [...]]]></description>
			<content:encoded><![CDATA[<p>Muitos dos princípios da programação orientada a objetos foram criados com linguagens estáticas em mente. Esse é o caso do <a href="http://en.wikipedia.org/wiki/Open/closed_principle">Open-Closed Principle</a>, enunciado da seguinte maneira:</p>
<blockquote><p>Software entities (classes, modules, functions, etc) should be open for extension, but closed for modification.</p></blockquote>
<p>Originalmente, a ideia é que, uma fez finalizada, uma entidade só poderia ser modificada para correções. Qualquer nova &#8220;feature&#8221; deveria ser implementada em uma nova entidade, que aproveitaria o código da primeira principalmente através de herança. Isso resulta em reaproveitamento da implementação, mas não garante a consistência da interface.</p>
<p>Um pouco depois, com a introdução e popularização de classes abstratas e recursos de linguagem como Interfaces, o princípio evoluiu e passou a ser aplicado em conjunto com o DIP, fazendo com que o código sempre dependesse de interfaces ao invés de implementações. Com isso, era possível reaproveitar uma interface (closed) e modificar a implementação (open).</p>
<p>Mas e nas linguagens como Ruby, em que abrir uma classe é tão simples como definí-la e pode ser feito a qualquer momento? Será que esse princípio se aplica? Isso sempre é tema de muita discussão e aqui vai minha visão sobre isso.</p>
<p>Bem, com Ruby temos algumas formas de modificar uma classe, como herança, mixins, reabrir a classe ou usar metaprogramação. Perceba que, exceto pela herança, as outras maneiras infringem a ideia original do princípio. Mas, como já vimos, o próprio princípio evoluiu para abraçar mudanças nas linguagens e paradigmas. </p>
<p>O importante, principalmente em linguagens com Duck Typing (que, como já vimos, não dão a mínima para tipos), é que a interface seja fechada. Não importa o modo que você escolher para fazer as modificações, desde que a &#8220;superfície de contato&#8221; entre as entidades permaneça estável.</p>
<p>No exemplo do post anterior poderíamos modificar as classes que passamos como dependências via parâmetro e utilizá-las sem problemas, desde que a interface permanecesse a mesma. Uma vantagem adicional da tipagem dinâmica é que nesse caso podemos utilizar também herança (modificando o &#8220;tipo&#8221;) sem precisar modificar o código cliente, que só se importa com a interface.</p>
<p>Dessa forma, podemos modificar um pouco o enunciado do OCP para adaptá-lo à nossa linguagem preferida:</p>
<blockquote><p>Software entities (classes, modules, functions, etc) should be open for extension, but closed for interface modification.</p></blockquote>
<p>Recomendo esse vídeo-podcast sobre o assunto: <a href="http://www.heartmindcode.com/blog/2011/03/monkeypatching-and-the-open-closed-principle/">Monkeypatching and the Open-Closed Principle</a></p>
<img src="http://feeds.feedburner.com/~r/LearningOnRails/~4/4xLCVJFtEtk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.lucashungaro.com/2011/05/11/solid-ruby-open-closed-principle/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://blog.lucashungaro.com/2011/05/11/solid-ruby-open-closed-principle/</feedburner:origLink></item>
		<item>
		<title>SOLID Ruby: Dependency Inversion Principle</title>
		<link>http://feedproxy.google.com/~r/LearningOnRails/~3/3m-1IF6LYPU/</link>
		<comments>http://blog.lucashungaro.com/2011/05/09/solid-ruby-dependency-inversion-principle/#comments</comments>
		<pubDate>Tue, 10 May 2011 02:57:16 +0000</pubDate>
		<dc:creator>Lucas Húngaro</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Test-Driven Development]]></category>

		<guid isPermaLink="false">http://blog.lucashungaro.com/?p=410</guid>
		<description><![CDATA[Continuando os artigos sobre SOLID, vamos falar um pouco sobre o Dependency Inversion Principle. Em resumo, esse princípio diz que os componentes devem depender de abstrações ao invés de implementações. Bom, isso faz muito sentido em linguagens estáticas como Java, onde há estruturas como Interfaces, classes abstratas e outras parafernalhas. No final, na minha modesta [...]]]></description>
			<content:encoded><![CDATA[<p>Continuando os artigos sobre SOLID, vamos falar um pouco sobre o <a href="http://en.wikipedia.org/wiki/Dependency_inversion_principle">Dependency Inversion Principle</a>. Em resumo, esse princípio diz que os componentes devem depender de abstrações ao invés de implementações.</p>
<p>Bom, isso faz muito sentido em linguagens estáticas como Java, onde há estruturas como Interfaces, classes abstratas e outras parafernalhas. No final, na minha modesta opinião, o código torna-se um espetáculo bizarro de indireção e pode mais confundir do que ajudar se você não for cuidadoso. Mas e nas linguagens dinâmicas?</p>
<p>É comum ouvir que, quando você utiliza uma linguagem que contém Duck Typing (a característica que mais gosto no Ruby), você obtém os benefícios do DIP &#8220;de graça&#8221;. Isso não é bem verdade. Você os obtém de graça somente se <em>pedir com jeitinho</em>. <img src='http://blog.lucashungaro.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </p>
<p>O que quero dizer com isso?</p>
<p>Vamos ao exemplo do artigo anterior em sua última versão:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Game <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  belongs_to <span style="color:#ff3333; font-weight:bold;">:category</span>
  validates_presence_of <span style="color:#ff3333; font-weight:bold;">:title</span>, <span style="color:#ff3333; font-weight:bold;">:category_id</span>, <span style="color:#ff3333; font-weight:bold;">:description</span>,
                        <span style="color:#ff3333; font-weight:bold;">:price</span>, <span style="color:#ff3333; font-weight:bold;">:platform</span>, <span style="color:#ff3333; font-weight:bold;">:year</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> GamePriceService
  attr_accessor <span style="color:#ff3333; font-weight:bold;">:game</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># we could use a config file</span>
  BASE_URL = <span style="color:#996600;">&quot;http://thegamedatabase.com/api/game&quot;</span>
  API_KEY = <span style="color:#996600;">&quot;ek2o1je&quot;</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">game</span> = game
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> get_price
    data = <span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;#{BASE_URL}/#{game.name}/price?api_key=#{API_KEY}&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    JsonParserLib.<span style="color:#9900CC;">parse</span><span style="color:#006600; font-weight:bold;">&#40;</span>data<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> GamePrinter
  attr_accessor <span style="color:#ff3333; font-weight:bold;">:game</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">game</span> = game
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#CC0066; font-weight:bold;">print</span>
    price_service = GamePriceService.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#006600; font-weight:bold;">&lt;&lt;-</span>EOF
      <span style="color:#008000; font-style:italic;">#{game.name}, #{game.platform}, #{game.year} </span>
      current value is <span style="color:#008000; font-style:italic;">#{price_service.get_price[:value]}</span>
    EOF
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Esse código possui algumas <strong>dependências rígidas</strong>. Chamamos as classes GamePriceService e JsonParserLib explicitamente dentro de GamePrinter#print e GamePriceService#get_price, respectivamente. Note que, apesar do Duck Typing nos permitir utilizar componentes com uma determinada interface independente de tipo, fizemos com que nossas classes fiquem amarradas à alguns tipos através dessas dependências.</p>
<p>Uma forma de se aproveitar dos benefícios do Duck Typing e, assim, conseguir &#8220;de graça&#8221; as vantagens do DIP, é tornar nossas dependências transparentes. Enquanto linguagens estáticas costumam se utilizar (embora isso não seja obrigatório) de complexas bibliotecas de injeção de dependência para fazer isso (ah, meus tempos de Java e Spring <img src='http://blog.lucashungaro.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> ), em Ruby isso é tão simples quanto passar um parâmetro:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Game <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  belongs_to <span style="color:#ff3333; font-weight:bold;">:category</span>
  validates_presence_of <span style="color:#ff3333; font-weight:bold;">:title</span>, <span style="color:#ff3333; font-weight:bold;">:category_id</span>, <span style="color:#ff3333; font-weight:bold;">:description</span>,
                        <span style="color:#ff3333; font-weight:bold;">:price</span>, <span style="color:#ff3333; font-weight:bold;">:platform</span>, <span style="color:#ff3333; font-weight:bold;">:year</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> GamePriceService
  attr_accessor <span style="color:#ff3333; font-weight:bold;">:game</span>, <span style="color:#ff3333; font-weight:bold;">:json_parser</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># we could use a config file</span>
  BASE_URL = <span style="color:#996600;">&quot;http://thegamedatabase.com/api/game&quot;</span>
  API_KEY = <span style="color:#996600;">&quot;ek2o1je&quot;</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>game, json_parser = JsonParserLib<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">game</span> = game
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">json_parser</span> = json_parser
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> get_price
    data = <span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;#{BASE_URL}/#{game.name}/price?api_key=#{API_KEY}&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    json_parser.<span style="color:#9900CC;">parse</span><span style="color:#006600; font-weight:bold;">&#40;</span>data<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> GamePrinter
  attr_accessor <span style="color:#ff3333; font-weight:bold;">:game</span>, <span style="color:#ff3333; font-weight:bold;">:game_webservice</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>game, game_webservice = GamePriceService<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">game</span> = game
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">game_webservice</span> = game_webservice
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#CC0066; font-weight:bold;">print</span>
    price_service = game_webservice.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#006600; font-weight:bold;">&lt;&lt;-</span>EOF
      <span style="color:#008000; font-style:italic;">#{game.name}, #{game.platform}, #{game.year} </span>
      current value is <span style="color:#008000; font-style:italic;">#{price_service.get_price[:value]}</span>
    EOF
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># Usage example:</span>
game = Game.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>some_game_data<span style="color:#006600; font-weight:bold;">&#41;</span>
webservice = GamePriceService.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
game.<span style="color:#9900CC;">price</span> = webservice.<span style="color:#9900CC;">get_price</span>
&nbsp;
GamePrinter.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#CC0066; font-weight:bold;">print</span></pre></div></div>

<p>Aqui escolhemos passar essas dependências através dos construtores das classes. Dessa forma, ficamos livres da dependência de tipo e passamos a depender apenas de uma interface. Basta que a classe passada no construtor responda aos métodos que utilizamos e não teremos problema. Outra forma seria passar as dependências apenas para os métodos que as utilizam:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Game <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  belongs_to <span style="color:#ff3333; font-weight:bold;">:category</span>
  validates_presence_of <span style="color:#ff3333; font-weight:bold;">:title</span>, <span style="color:#ff3333; font-weight:bold;">:category_id</span>, <span style="color:#ff3333; font-weight:bold;">:description</span>,
                        <span style="color:#ff3333; font-weight:bold;">:price</span>, <span style="color:#ff3333; font-weight:bold;">:platform</span>, <span style="color:#ff3333; font-weight:bold;">:year</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> GamePriceService
  attr_accessor <span style="color:#ff3333; font-weight:bold;">:game</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># we could use a config file</span>
  BASE_URL = <span style="color:#996600;">&quot;http://thegamedatabase.com/api/game&quot;</span>
  API_KEY = <span style="color:#996600;">&quot;ek2o1je&quot;</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">game</span> = game
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> get_price<span style="color:#006600; font-weight:bold;">&#40;</span>json_parser = JsonParserLib<span style="color:#006600; font-weight:bold;">&#41;</span>
    data = <span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;#{BASE_URL}/#{game.name}/price?api_key=#{API_KEY}&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    json_parser.<span style="color:#9900CC;">parse</span><span style="color:#006600; font-weight:bold;">&#40;</span>data<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> GamePrinter
  attr_accessor <span style="color:#ff3333; font-weight:bold;">:game</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">game</span> = game
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#CC0066; font-weight:bold;">print</span><span style="color:#006600; font-weight:bold;">&#40;</span>game_webservice = GamePriceService<span style="color:#006600; font-weight:bold;">&#41;</span>
    price_service = game_webservice.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#006600; font-weight:bold;">&lt;&lt;-</span>EOF
      <span style="color:#008000; font-style:italic;">#{game.name}, #{game.platform}, #{game.year} </span>
      current value is <span style="color:#008000; font-style:italic;">#{price_service.get_price[:value]}</span>
    EOF
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#008000; font-style:italic;"># Usage example:</span>
game = Game.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>some_game_data<span style="color:#006600; font-weight:bold;">&#41;</span>
webservice = GamePriceService.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
game.<span style="color:#9900CC;">price</span> = webservice.<span style="color:#9900CC;">get_price</span>
&nbsp;
GamePrinter.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>.<span style="color:#CC0066; font-weight:bold;">print</span></pre></div></div>

<p>É uma maneira melhor para evitarmos construtores muito complexos quando esse for o caso. Uma vantagem adicional é obtida através da utilização de valores padrão para os parâmetros. Desta forma, a não ser que queiramos utilizar alguma dependência não-padrão, as dependências ficam totalmente transparentes.</p>
<p>Mais uma vantagem é no momento de escrever testes. Passando dependências dessa maneira, é muito fácil criar objetos dublês e utilizá-los para facilitar o processo (tornar a execução mais rápida, evitar o uso de webservices reais etc). Um exemplos simples e eficiente pode ser <a href="http://www.slideshare.net/lucashungaro/ruby-confbr">visto aqui</a>. (slides 34, 35 e 36)</p>
<p>Em geral, se você não conseguir substituir uma dependência por um dublê em suas especificações, seu código está muito rígido e pode se beneficiar da aplicação desse princípio.</p>
<p>Leitura adicional:</p>
<p>  <a href="http://patmaddox.com/blog/2008/1/27/make-your-dependencies-translucent-with-default-parameters.html">Make Your Dependencies Translucent with Default Parameters</a></p>
<img src="http://feeds.feedburner.com/~r/LearningOnRails/~4/3m-1IF6LYPU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.lucashungaro.com/2011/05/09/solid-ruby-dependency-inversion-principle/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		<feedburner:origLink>http://blog.lucashungaro.com/2011/05/09/solid-ruby-dependency-inversion-principle/</feedburner:origLink></item>
		<item>
		<title>SOLID Ruby: Single Responsibility Principle</title>
		<link>http://feedproxy.google.com/~r/LearningOnRails/~3/_AoBYQgg70w/</link>
		<comments>http://blog.lucashungaro.com/2011/05/04/solid-ruby-single-responsibility-principle/#comments</comments>
		<pubDate>Wed, 04 May 2011 05:34:38 +0000</pubDate>
		<dc:creator>Lucas Húngaro</dc:creator>
				<category><![CDATA[Desenvolvimento]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://blog.lucashungaro.com/?p=409</guid>
		<description><![CDATA[Utilizamos BDD e técnicas do programação orientada a objetos não apenas para obter código mais limpo e bonito. Na verdade, essas são consequências do principal objetivo: criar código que tenha baixo custo de manutenção, isto é, não demande muito tempo e pessoas para correções e melhorias. Um conjunto de técnicas que podemos utilizar para atingir [...]]]></description>
			<content:encoded><![CDATA[<p>Utilizamos BDD e técnicas do programação orientada a objetos não apenas para obter código mais limpo e bonito. Na verdade, essas são consequências do principal objetivo: criar código que tenha baixo custo de manutenção, isto é, não demande muito tempo e pessoas para correções e melhorias.</p>
<p>Um conjunto de técnicas que podemos utilizar para atingir esse objetivo é chamada de <a href="http://en.wikipedia.org/wiki/Solid_(object-oriented_design)">SOLID</a>, um acrônimo que representa cinco técnicas:</p>
<ul>
<li>Single Responsibility Principle</li>
<li>Open-Closed Principle</li>
<li>Liskov Substitution Principle</li>
<li>Interface Segregation Principle</li>
<li>Dependency Inversion Principle</li>
</ul>
<p>O objetivo desses princípios é fazer com que alterações necessárias sejam feitas no menor número possível de locais no código. Em outras palavras, é diminuir o custo dessas mudanças através de um design que reduz os efeitos colaterais das modificações.</p>
<p>Nesse artigo vou mostrar um pouco sobre a aplicação do <a href="http://en.wikipedia.org/wiki/Single_responsibility_principle">Single Responsibility Principle</a> em Ruby.</p>
<p>Esse princípio nos diz que uma classe deve ter apenas uma responsabilidade e deve executá-la por completo (não devem haver outras classes que executem partes dela). É uma forma de conseguir alta <a href="http://en.wikipedia.org/wiki/Cohesion_(computer_science)">coesão</a>, uma qualidade desejável em código orientado a objetos. Uma classe coesa executa completamente uma responsabilidade, ou seja, essa responsabilidade não fica fragmentada e espalhada entre diferentes entidades no domínio.</p>
<p>Uma forma de pensar sobre o que é uma responsabilidade para facilitar a absorção do conceito é que esta representa <em>uma razão para mudar</em>. Então podemos definir o princípio como: uma classe tem uma e apenas uma razão para mudar.</p>
<p>Vamos a um exemplo de um modelo ActiveRecord que viola esse princípio (alerta para pseudo-código que nem deve funcionar, é apenas um exemplo):</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Game <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  belongs_to <span style="color:#ff3333; font-weight:bold;">:category</span>
  validates_presence_of <span style="color:#ff3333; font-weight:bold;">:title</span>, <span style="color:#ff3333; font-weight:bold;">:category_id</span>, <span style="color:#ff3333; font-weight:bold;">:description</span>,
                        <span style="color:#ff3333; font-weight:bold;">:price</span>, <span style="color:#ff3333; font-weight:bold;">:platform</span>, <span style="color:#ff3333; font-weight:bold;">:year</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> get_official_price
    <span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;http://thegamedatabase.com/api/game/#{name}/price?api_key=ek2o1je&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#CC0066; font-weight:bold;">print</span>
    <span style="color:#006600; font-weight:bold;">&lt;&lt;-</span>EOF
      <span style="color:#008000; font-style:italic;">#{name}, #{platform}, #{year} </span>
      current value is <span style="color:#008000; font-style:italic;">#{get_official_price}</span>
    EOF
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Esse modelo tem como sua responsabilidade principal cuidar da lógica de negócio ligada à entidade Game. Porém, como podemos ver aqui, ele também está responsável por consultar um webservice para obter a cotação do jogo e por formatar sua exibição. Essa implementação possui baixa coesão pois essa classe possui mais de um motivo para mudar. Ela será alterada se os requisitos de validação de dados mudarem, se algum detalhe da chamada do webservice mudar ou se precisarmos exibir seus dados numa formatação diferente.</p>
<p>Uma forma de resolver isso seria desmembrar essa classe tendo esse resultado:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> Game <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Base</span>
  belongs_to <span style="color:#ff3333; font-weight:bold;">:category</span>
  validates_presence_of <span style="color:#ff3333; font-weight:bold;">:title</span>, <span style="color:#ff3333; font-weight:bold;">:category_id</span>, <span style="color:#ff3333; font-weight:bold;">:description</span>,
                        <span style="color:#ff3333; font-weight:bold;">:price</span>, <span style="color:#ff3333; font-weight:bold;">:platform</span>, <span style="color:#ff3333; font-weight:bold;">:year</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> GamePriceService
  attr_accessor <span style="color:#ff3333; font-weight:bold;">:game</span>
&nbsp;
  <span style="color:#008000; font-style:italic;"># we could use a config file</span>
  BASE_URL = <span style="color:#996600;">&quot;http://thegamedatabase.com/api/game&quot;</span>
  API_KEY = <span style="color:#996600;">&quot;ek2o1je&quot;</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">game</span> = game
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> get_price
    data = <span style="color:#CC0066; font-weight:bold;">open</span><span style="color:#006600; font-weight:bold;">&#40;</span><span style="color:#996600;">&quot;#{BASE_URL}/#{game.name}/price?api_key=#{API_KEY}&quot;</span><span style="color:#006600; font-weight:bold;">&#41;</span>
    JsonParserLib.<span style="color:#9900CC;">parse</span><span style="color:#006600; font-weight:bold;">&#40;</span>data<span style="color:#006600; font-weight:bold;">&#41;</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
<span style="color:#9966CC; font-weight:bold;">class</span> GamePrinter
  attr_accessor <span style="color:#ff3333; font-weight:bold;">:game</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> initialize<span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">game</span> = game
  <span style="color:#9966CC; font-weight:bold;">end</span>
&nbsp;
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#CC0066; font-weight:bold;">print</span>
    price_service = GamePriceService.<span style="color:#9900CC;">new</span><span style="color:#006600; font-weight:bold;">&#40;</span>game<span style="color:#006600; font-weight:bold;">&#41;</span>
    <span style="color:#006600; font-weight:bold;">&lt;&lt;-</span>EOF
      <span style="color:#008000; font-style:italic;">#{game.name}, #{game.platform}, #{game.year} </span>
      current value is <span style="color:#008000; font-style:italic;">#{price_service.get_price[:value]}</span>
    EOF
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Assim aumentamos bastante a coesão de nosso sofware. Cada classe possui apenas uma razão para mudar e atende ao SRP.</p>
<p>Um exemplo mais real pode ser visto no modelo <a href="https://github.com/spree/spree/blob/master/core/app/models/creditcard.rb">Creditcard</a> do <a href="http://spreecommerce.com/">Spree</a>. Note que, entre outras coisas, o modelo também é responsável pelos processos de compra e autorização do cartão (métodos purchase e authorize). Note como esse métodos implementam parte do processo e delegam outras partes para outros componentes quando a responsabilidade deveria ser 100% realizada em outra parte. Isso cria baixa coesão (múltiplas responsabilidades por classe) e alto acoplamento (uma responsabilidade dividida por várias classes interdependentes).</p>
<p>Como um exercício a parte podemos pensar sobre até que ponto modelos do ActiveRecord quebram o SRP por serem responsáveis por persistência e lógica de negócios (que inclui validação de dados). Há muitos desenvolvedores dos dois lados nessa questão. Acredito que há pequenas violações mas de uma forma não prejudicial, já que a persistência é implementada por uma classe especializada e apenas herdada em nossos modelos, de forma que essa é delegada ao framework (que cuida de possíveis modificações necessárias à persistência).</p>
<p>É preciso ter em mente que ser muito extremista com esses princípios também pode levar à problemas e a um excesso de preciosismo que torna-se prejudicial.</p>
<p>Bom, a partir daqui vamos para outros artigos onde serão explorados os outros princípios. O pseudo-código utilizado no exemplo acima ainda tem algumas coisas a ganhar através da aplicação de outros princípios.</p>
<p>Leitura recomendada:</p>
<ul>
<li><a href="http://en.wikipedia.org/wiki/Cohesion_(computer_science)">Cohesion</a></li>
<li><a href="http://en.wikipedia.org/wiki/Coupling_(computer_science)">Coupling</a></li>
<li><a href="http://en.wikipedia.org/wiki/Separation_of_concerns">Separation of concerns</a></li>
</ul>
<img src="http://feeds.feedburner.com/~r/LearningOnRails/~4/_AoBYQgg70w" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://blog.lucashungaro.com/2011/05/04/solid-ruby-single-responsibility-principle/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://blog.lucashungaro.com/2011/05/04/solid-ruby-single-responsibility-principle/</feedburner:origLink></item>
	</channel>
</rss>

