<?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>CODETUNES</title>
	
	<link>http://codetunes.com</link>
	<description>This is a post on CODETUNES, a blog by MONTERAIL, an offshore Ruby on Rails development agency.</description>
	<lastBuildDate>Thu, 18 Apr 2013 13:39:00 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/CodeTunes" /><feedburner:info uri="codetunes" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><image><link>http://codetunes.com</link><url>http://codetunes.com/wp-content/uploads/2011/07/tee_small.png</url><title>Monterail.com, an offshore webdevelopment agency.</title></image><item>
		<title>Why we love paying for Trello</title>
		<link>http://feedproxy.google.com/~r/CodeTunes/~3/84AJoGSOMnA/why-we-love-paying-for-trello</link>
		<comments>http://codetunes.com/2013/why-we-love-paying-for-trello#comments</comments>
		<pubDate>Thu, 18 Apr 2013 12:00:01 +0000</pubDate>
		<dc:creator>Bartosz Pietrzak</dc:creator>
				<category><![CDATA[Business]]></category>

		<guid isPermaLink="false">http://codetunes.com/?p=1263</guid>
		<description><![CDATA[Trello recently launched an early access of „Business Class” (if you don&#8217;t have it yet, you can apply here). The wording is perfect &#8211; little wink to the airline industry seems far better than „premium”, „paid ”or „pro plan”. We use Trello on a daily basis throughout every section of the company &#8211; from IT [...]]]></description>
				<content:encoded><![CDATA[<p><a href="http://trello.com">Trello</a> recently launched an early access of „<a href="http://d.pr/i/oAqN">Business Class</a>” (if you don&#8217;t have it yet, you can <a href="https://trello.com/c/2A9OEGta">apply here</a>).</p>
<p>The wording is perfect &#8211; little wink to the airline industry seems far better than „premium”, „paid ”or „pro plan”.</p>
<p><a href="http://codetunes.com/2013/we-use-trello">We use Trello</a> on a daily basis throughout every section of the company &#8211; from IT management, administration and accounting to keeping track of our digital library and book requests. Yet there was a little fear in the back of my head: we rely on it so much but we don&#8217;t pay for it.</p>
<p><span id="more-1263"></span></p>
<p>Agreeing fully with „<a href="http://blog.pinboard.in/2011/12/don_t_be_a_free_user/">Don&#8217;t be a free user</a>”, the news about Trello giving its users a way to pay for the software was something I wanted to share with the team instantly. And so I did.</p>
<p>Dominik replied: what does it mean for us, non-admins?<br />
My reply was simple: it&#8217;s paid and it won&#8217;t disappear overnight (or at least leave us without data, as <a href="https://news.ycombinator.com/item?id=5570266">pointed on HN</a>).</p>
<p>We don&#8217;t need the pro features. We simply appreciate the safety and want to support the product.</p>
<img src="http://feeds.feedburner.com/~r/CodeTunes/~4/84AJoGSOMnA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://codetunes.com/2013/why-we-love-paying-for-trello/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://codetunes.com/2013/why-we-love-paying-for-trello?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=why-we-love-paying-for-trello</feedburner:origLink></item>
		<item>
		<title>From Monterail with Love #4</title>
		<link>http://feedproxy.google.com/~r/CodeTunes/~3/Y7YcQ_f8TCw/from-monterail-with-love-4</link>
		<comments>http://codetunes.com/2013/from-monterail-with-love-4#comments</comments>
		<pubDate>Wed, 20 Mar 2013 10:57:37 +0000</pubDate>
		<dc:creator>Jan Dudulski</dc:creator>
				<category><![CDATA[From Monterail with Love]]></category>

		<guid isPermaLink="false">http://codetunes.com/?p=1209</guid>
		<description><![CDATA[This time we’re going to give you some cool demos presenting the power of HTML5 and JavaScript, Vim and single page apps-related articles, and some good Git practices. Git features Comparing to its predecessor, Subversion, Git stays young and fresh. More importantly, it’s a much more complex tool. Chances are that you’re still looking for good [...]]]></description>
				<content:encoded><![CDATA[<p>This time we’re going to give you some cool demos presenting the power of HTML5 and JavaScript, Vim and single page apps-related articles, and some good Git practices.<span id="more-1209"></span></p>
<h2>Git features</h2>
<p>Comparing to its predecessor, Subversion, Git stays young and fresh. More importantly, it’s a much more complex tool. Chances are that you’re still looking for good practices or better understanding of a few concepts.</p>
<ul>
<li><a href="http://sethrobertson.github.com/GitBestPractices/">Git Best Practices</a> by Seth Robertson is a long list of… best practices of using <b class="mono">git</b> — recommended if you still feel a little uncomfortable working with it.</li>
<li><a href="http://mislav.uniqpath.com/2013/02/merge-vs-rebase/">Merge vs. Rebase</a> by Mislav Marohnić will help you understand the difference between these two, and provide you with tips on each.</li>
<li><a href="http://ejohn.org/blog/keeping-passwords-in-source-control/">Keeping Passwords in Source Control</a> by the JavaScript guru and creator of jQuery, John Resig, comprehensivley describes how to store passwords inside source revision control like a Git repository.</li>
<li>Did you know that GitHub exposed public <b class="mono">ssh</b> keys for its users? <a href="http://thechangelog.com/github-exposes-public-ssh-keys-for-its-users/">Hat tip from Adam Stackoviak</a>. We think it’s better to use GitHub API for such things, but it’s worth knowing there’s an alternative way.</li>
</ul>
<h2>Adjust your Vim</h2>
<p>Probably only pure <em>vimists</em> can take pleasure in using Vim without any plugins or <b class="mono">.vimrc</b> customizations. Here are some hints on adjusting Vim to your needs:</p>
<ul>
<li><a href="http://dougireton.com/blog/2013/02/23/layout-your-vimrc-like-a-boss/">Lay Out Your <b class="mono">.vimrc</b> Like a Boss</a>, because growing <b class="mono">.vimrc</b> can easily turn into mess. Doug Ireton proposes a nice and clean way of organizing your config.</li>
<li><a href="http://statico.github.com/vim.html">Vim After 11 Years</a> — Ian Langworth shares his experience: what he likes, what he learned, and how he extends his Vim. It’s such a broad topic that there’s even a sequel to the article, <a href="http://statico.github.com/vim2.html">Everything I Missed in “Vim After 11 Years.”</a></li>
<li><a href="http://usevim.com/2013/02/20/configuration/">Stop the Vim Configuration Madness</a> by Alex Young leaves you with a valuable warning that there is a thin border between improvement and incomprehension of Vim philosophy.</li>
<li><a href="http://code.hootsuite.com/vimshell/">VimShell</a> is a nicely looking shell solution with the power of <b class="mono">vim</b>. If you love Vim, this project is worth checking.</li>
</ul>
<h2>The undiscovered land of SPA</h2>
<p>We’ve got tons of frameworks, ideas and hot discussions on available paths to follow. SPA is a still fresh and hot topic with lots of white gaps on its map.</p>
<ul>
<li>Tomasz Nazar of Gameboxed shares his experience on <a href="http://aspectized.com/2012/10/this-is-how-we-do-single-page-apps/">how they do single page apps</a>. Worth reading, since these guys basically write only SPAs.</li>
<li><a href="http://briantford.com/blog/huuuuuge-angular-apps.html">Building <em>Huuuuuge</em> Apps with</a> <a href="http://angularjs.org/">AngularJS</a> by Brian Ford — if you’re a fan of the framework like our <a href="http://codetunes.com/author/tymon">Tymon</a> is, you should read these tips on building a complex Angular-based applications.</li>
<li><a href="https://gist.github.com/lefnire/4454814">Rant: Backbone, Angular, Meteor, Derby</a> — Tyler Renelle pays tribute to Backbone for making a revolution in the JavaScript world, but the world goes forward and — as he says — today you should choose <em>something better.</em></li>
<li><a href="http://blog.arkency.com/2013/02/introducing-hexagonal-dot-js/">Introducing Hexagonal.js</a> — our <a href="http://drug.org.pl/">local community</a> works hard on different approaches to SPAs. Jan Filipowski presents basic ideas and how you can contribute to the project.</li>
<li><a href="http://viget.com/extend/preventing-backbone.sync-firestorms">Preventing <b class="mono">Backbone.sync</b> Firestorms</a> &#8211; if you use Backbone.js, chances are that you’ve met the issue of firing too many events. Nate Hunzaker suggests how to deal with such.</li>
</ul>
<h2>Power of HTML5</h2>
<p>One way of learning something new is to read others’ code. Here are some amazing demos and articles:</p>
<ul>
<li><a href="http://www.html5rocks.com/en/tutorials/casestudies/oz/">Find Your Way to Oz</a> — watch this and you’ll start wondering about beautiful adventure games in your browser. Just awesome.</li>
<li><a href="http://www.html5rocks.com/en/tutorials/casestudies/100000stars/">10000 Stars</a> will take you on a trip around the stars and planets right in the browser. Feel like Neil Armstrong!</li>
<li><a href="http://www.html5rocks.com/en/tutorials/pointerlock/intro/">Pointer Lock and First Person Shooter Controls </a> — if you plan to write <a href="http://en.wikipedia.org/wiki/First-person_shooter">FPS game</a> in a browser, this introduction to Pointer Lock API could be a good start.</li>
<li><a href="http://blog.keithclark.co.uk/creating-3d-worlds-with-html-and-css/">Creating 3D worlds with HTML and CSS</a> — another cool example how to start with FPS games and 3D world in a browser.</li>
</ul>
<p>See you next time!</p>
<img src="http://feeds.feedburner.com/~r/CodeTunes/~4/Y7YcQ_f8TCw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://codetunes.com/2013/from-monterail-with-love-4/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://codetunes.com/2013/from-monterail-with-love-4?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=from-monterail-with-love-4</feedburner:origLink></item>
		<item>
		<title>Let your ideas grow</title>
		<link>http://feedproxy.google.com/~r/CodeTunes/~3/w1rqxcdJnsM/let-your-ideas-grow</link>
		<comments>http://codetunes.com/2013/let-your-ideas-grow#comments</comments>
		<pubDate>Fri, 08 Mar 2013 11:03:57 +0000</pubDate>
		<dc:creator>Bartosz Pietrzak</dc:creator>
				<category><![CDATA[Business]]></category>

		<guid isPermaLink="false">http://codetunes.com/?p=836</guid>
		<description><![CDATA[Making complex ideas real can be tough for various reasons. It&#8217;s safe to say that most of them aren&#8217;t getting out of our heads &#8211; assuming that just speaking about them doesn&#8217;t count. Simple actions can lead to greater outcomes and I&#8217;m going to share a bit of my experiments in that matter. To give [...]]]></description>
				<content:encoded><![CDATA[<p>Making complex ideas real can be tough for various reasons. It&#8217;s safe to say that most of them aren&#8217;t getting out of our heads &#8211; assuming that just speaking about them doesn&#8217;t count. Simple actions can lead to greater outcomes and I&#8217;m going to share a bit of my experiments in that matter.<span id="more-836"></span></p>
<p>To give you some context: at the moment we&#8217;re focusing on designing our organisation. In the first three years of running the company we&#8217;ve experienced some growth – not very rapid, but enough to put us into a little chaos after getting from 3 to 15+ people. 2013 is the year of getting steady and making ground for more growth.</p>
<h1>Make the robots do the lazy work</h1>
<p>We have four people that are included in our sales process. Utilising a CRM – <a href="http://highrisehq.com">Highrise</a> being our choice &#8211; was a necessity.</p>
<p>The problem? Nobody was using it.</p>
<p>It seemed redundant and the friction of the system outweighed it&#8217;s advantages. To make the process as smooth as possible, we improved our contact form a bit so that every message is automatically creating a contact in Highrise. The process got a little less annoying.</p>
<h1>Measure</h1>
<p>We&#8217;ve been forecasting our incomes using a spreadsheet. It turned out to be too simple in terms of the data and too complex when it came to putting the numbers in. Not to mention that the data was mostly duplicated from our accounting software.</p>
<p>But hey, <strong>we&#8217;re a bunch of coders</strong>. We can build the tools we need. (It was one of the rare moments during which I felt real power coming from our profession).</p>
<p>I quickly prototyped two simple tools  - one called <a href="http://www.imdb.com/character/ch0111793/">Norman</a>, used to gather the data and expose it to the second one &#8211; Norman&#8217;s Dashboard, as seen below.</p>
<h1>Measure. Measure. Measure.</h1>
<p>Here&#8217;s what the dashboard looks like:</p>
<p><a href="http://codetunes.com/2013/let-your-ideas-grow/screen-shot-2013-01-25-at-11-44-14-pm" rel="attachment wp-att-838"><img class="aligncenter size-full wp-image-838" alt="Norman's Dashboard" src="http://codetunes.com/wp-content/uploads/2013/01/Screen-Shot-2013-01-25-at-11.44.14-PM.png" width="1359" height="810" /></a></p>
<p>The data is updated in real time. If somebody updates his timesheet in <a href="http://www.getharvest.com">Harvest</a>, we see the numbers go up. If somebody puts a new invoice into Norman, the dashboard updates the income and profit forecasts in seconds. (The tool we used for the dashboard is <a href="http://shopify.github.com/dashing/">Dashing</a> &#8211; huge kudos to Shopify&#8217;s team for making it open-source)!</p>
<p>Income forecasting and the timesheet reports are only a proof of concept &#8211; we have huge plans for the dashboard: notifying about new leads that we haven&#8217;t responded to yet, displaying numbers from Google Analytics and KPIs (that we&#8217;re going to most likely measure in the app).</p>
<h1>Positive side effect</h1>
<p>We&#8217;re getting more conscious about what happens in our company.</p>
<p>Ultimately, a quick glance at the dashboard will give us an overview of the whole organisation. Most importantly, our thinking process is getting more and more data-driven.</p>
<p>Measuring a new part of the company doesn&#8217;t mean that we&#8217;re going to get our hands dirty working in a spreadsheet &#8211; it means that we have to code it once and then just look at the beautiful representation of the data.</p>
<h1>Take the risk</h1>
<p>Our data-driven automatization revolution started by one small thing &#8211; automating a simple part of the sales process. Seeing how this improved our daily work made us see new ways of doing things: we started to wonder if something can be automated out of the box. We spent a few hours on improving the sales process but we got a lot more from it: the first-hand knowledge that it&#8217;s worth it.</p>
<p>There were no more „okay, this seems like a good idea, let&#8217;s put it in the never-ending backlog of low priority tasks” discussions. We transitioned to „yeah, let&#8217;s do it!” &#8211; driven by the confidence from previous experiences &#8211; even as small as the one described above.</p>
<p>Start simple. Do small stuff. Experiment. Sometimes it&#8217;s not worth putting stuff into context and weighing the ups and downs: just do it. Trust your guts – the outcome can positively surprise you.</p>
<img src="http://feeds.feedburner.com/~r/CodeTunes/~4/w1rqxcdJnsM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://codetunes.com/2013/let-your-ideas-grow/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://codetunes.com/2013/let-your-ideas-grow?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=let-your-ideas-grow</feedburner:origLink></item>
		<item>
		<title>We use Trello.</title>
		<link>http://feedproxy.google.com/~r/CodeTunes/~3/etZ_Z4B9xIY/we-use-trello</link>
		<comments>http://codetunes.com/2013/we-use-trello#comments</comments>
		<pubDate>Wed, 27 Feb 2013 10:13:36 +0000</pubDate>
		<dc:creator>Szymon Boniecki</dc:creator>
				<category><![CDATA[Communication]]></category>
		<category><![CDATA[Project management]]></category>
		<category><![CDATA[project management]]></category>
		<category><![CDATA[trello]]></category>
		<category><![CDATA[workflow]]></category>

		<guid isPermaLink="false">http://codetunes.com/?p=1031</guid>
		<description><![CDATA[It is said that anyone ever involved in setting up a process of managing software development had an idea of coming up with his own custom tool and workflow. Specifically in web software development. We’ve all been there. We’ve gone through all existing tools and, this way or another, found our best shot. Heard of [...]]]></description>
				<content:encoded><![CDATA[<p>It is said that anyone ever involved in setting up a process of managing software development had an idea of coming up with his own custom tool and workflow. Specifically in web software development.</p>
<p>We’ve all been there. We’ve gone through all existing tools and, this way or another, found our best shot. Heard of kanban? It’s as <a href="https://www.youtube.com/watch?v=5cNJNKkCQ2E">easy as 1–2–3</a> to tear it into pieces, take what fits, and call yourself agile. Daily inertia inside a busy software <del>house</del> <em>hive</em> has proved it all right.<span id="more-1031"></span></p>
<p>In our line of business, we work on various projects simultaneously and have to stay <em>ABC</em> at all times, therefore well-optimized workflow is a must. It’s also a moral boost and sanity check for developers. Top-down and bottom-up — both have to meet.</p>
<p>Because there is as much to it as a human factor is concerned as it is to a business requirement. And yet, maturity of the workflow defines the team. We almost take it personally. We’re still in the process of getting the most out of ourselves. And we’ve come to a milestone where we are happy.</p>
<p><strong>We use <a href="http://trello.com">Trello</a> for project management</strong>. We’ve developed a management workflow that is spread across different boards and more or less kanban-like. Sounds familiar?</p>
<h2>Lords of the boards</h2>
<p>Lots of inspiration for our workflow comes from the approach <a href="http://community.uservoice.com/blog/trello-google-docs-product-management/">described by the makers of UserVoice</a>. As it did for their team, the openness of Trello allowed us to figure what was best for us. At the same time, it still allows for some small organic changes throughout different projects — small enough for anyone within the team to immediately grasp what is happening in the project even if he’s never worked on it.</p>
<p>That is why it’s more like a template that proves best.</p>
<h3>Product/planning board</h3>
<p><a href="http://codetunes.s3.amazonaws.com/posts/szymon-trello-planning.png"><img class="size-full wp-image-1057" style="max-width: 548px;" alt="Product planning board example" src="http://codetunes.s3.amazonaws.com/posts/szymon-trello-planning.png" /></a> Product planning board example</p>
<p>This is the place where stories are gathered and requirements get written down. A meeting point for product owner and project manager. The board features the following columns:</p>
<ul>
<li><em>Ideas and feature requests</em>,</li>
<li><em>Story is considered useful, required specs are being created</em>,</li>
<li><em>Specs are approved, designs are being prepared, estimates required</em>,</li>
<li><em>Finished user-stories</em>,</li>
<li><em>User-stories for a next sprint</em>.</li>
</ul>
<h3>Development board</h3>
<p><a href="http://codetunes.s3.amazonaws.com/posts/szymon-trello-development.png"><img class="size-full wp-image-1058 " style="max-width: 449px;" alt="Development board example" src="http://codetunes.s3.amazonaws.com/posts/szymon-trello-development.png" /></a></p>
<p>The board is specifically created for developers with clear order of priorities:</p>
<ul>
<li><em>To do</em> — tasks in current sprint ordered by priority.</li>
<li><em>In progress</em> — when I start working on something I move my card here. Only one card assigned to one person. <em>Does this ring a bell?</em></li>
<li><em>Ready to test</em> — a story that has been delivered to staging server.</li>
<li><em>Tested</em> and ready to be deployed to live — party that is at the end of the pipeline moves the card here (the QA process).</li>
<li><em>Live</em> <b class="mono">v[x] [date]</b> — for each live release with a date attached. We keep up to 3 versions, the rest is archived.</li>
</ul>
<h2>How it works</h2>
<p><strong>All stakeholders have access to all boards</strong>: The client, project managers, developers, designers. This has obvious advantages. First and foremost — cards can be moved freely across boards, and the whole history is visible to everyone. Turns out that a requirement isn’t specified precisely enough to be implemented? Take the card back from the development board to the planning board for more feedback. Having two transparent boards also gets some burden off the client’s head — he does not necessarily have to be involved in development process, however he can check the progress of each story any time.</p>
<p><strong>Cards represent stories.</strong> Simple. We’re not nazi in this regard, but whenever possible it’s best to create cards as stories. If a story turns out to be too big — split it into multiple cards.</p>
<p><strong>Describe stories by checklists.</strong> Each card has a checklist that represents specific tasks to be accomplished to finish the story. Each item on the checklist mentions the person responsible for each part of the story. We found it is sometimes a good idea to group the checklists e.g. into front-end tasks and back-end tasks, especially if there are lots of them.</p>
<p><strong>Cards are attached to people involved in the task.</strong> Remember to keep those people actively involved in the card who assigned to it. If someone finished his part, he detaches himself from the card.</p>
<p><strong>Mention!</strong> There is never too much to stress that mentioning is powerful both on system as well as on human level. Calling someone directly means they will get a notification. You need a specific person to pay attention at some specific point. Finger pointing when things are on the move, not after a failure.</p>
<h1>Where the wild things are</h1>
<p>The above are the foundations. There are more quirks.</p>
<p>For example, we came up with a “Release tasks” label. It should be applied on a card that needs some extra work to be done during the release, like “execute a server script.” The release checklist should be created next to it with all the activities to be performed listed.</p>
<p>You can get creative. Give it some thought. Describe your internal processes and apply that in Trello. You can use labels and titles of the cards as metadata carriers. They are ambiguous enough to always feel natural. In the end this is what matters the most: <em>to keep it real.</em></p>
<hr />
<p>Hopefully, some of these can be helpful to anyone out there struggling with the development process. Some of these may as well become outdated in a year from now. And that’d be fine — it would mean we’ve evolved again. And you could expect to hear from us about what we’ve learned on our way, too.</p>
<img src="http://feeds.feedburner.com/~r/CodeTunes/~4/etZ_Z4B9xIY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://codetunes.com/2013/we-use-trello/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://codetunes.com/2013/we-use-trello?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=we-use-trello</feedburner:origLink></item>
		<item>
		<title>From Monterail with Love #3</title>
		<link>http://feedproxy.google.com/~r/CodeTunes/~3/BCPeboXy2Vk/from-monterail-with-love-3</link>
		<comments>http://codetunes.com/2013/from-monterail-with-love-3#comments</comments>
		<pubDate>Mon, 18 Feb 2013 12:00:27 +0000</pubDate>
		<dc:creator>Jan Dudulski</dc:creator>
				<category><![CDATA[From Monterail with Love]]></category>

		<guid isPermaLink="false">http://codetunes.com/?p=901</guid>
		<description><![CDATA[It’s another Monday, so we figured it might be the right time for the new issue of From Monterail with Love. We’re announcing something special this time: If you like the series, subscribe to our newsletter so you’ll have a similar digest delivered right to your mailbox once a month. But for today, we’ve got [...]]]></description>
				<content:encoded><![CDATA[<p>It’s another Monday, so we figured it might be the right time for the new issue of <a href="http://codetunes.com/category/from-monterail-with-love">From Monterail with Love</a>. We’re announcing something special this time:</p>
<p><strong>If you like the series, <a href="http://monterail.us6.list-manage.com/subscribe?u=b21c3f3b68d1f1446328361c5&#038;id=f72107da82">subscribe to our newsletter</a> so you’ll have a similar digest delivered right to your mailbox once a month.</strong><span id="more-901"></span></p>
<p>But for today, we’ve got some free e-books, and a couple of security and tests-related links. <em>Enjoy.</em></p>
<h2>Something to read</h2>
<p>If you are a regular developer, chances are that occasionally you need to transform yourself into a sever admin. To make this less painful, I recommend diving into <a href="http://debian-handbook.info/get/now/">The Debian’s Administrator Handbook</a>.</p>
<p>Building a single page app is still a hot topic. Mikito Takada recently wrote a <a href="http://singlepageappbook.com/">fresh e-book</a> on the topic that’s available for free. Should you be interested in developing such app with Backbone, go through <a href="http://addyosmani.github.com/backbone-fundamentals/">Developing Backbone.js Applications</a> by Addy Osmani as well.</p>
<p>An interesting piece revolves around Mozilla’s infant project—it’s on <a href="http://www.rust-lang.org/">Rust</a>, but <a href="http://www.rustforrubyists.com/">from a Rubyist’s perspective</a>, written by Steve Klabnik.</p>
<p>Next up, the <a href="http://domenlightenment.com/">DOM Enlightenment</a>. Our JavaScript developers—myself included—wish we had found this book during our learning phase years ago. It really makes it easier to understand how DOM and JavaScript play together.</p>
<p>Another pieces that we collected for front-end guys and designers: <a href="http://www.awwwards.com/web-design-and-mobile-trends-for-2013-ebook-download-it-for-free.html">Web Design and Mobile Trends for 2013</a>.</p>
<h2>Security is hard</h2>
<p>The last weeks were <a href="http://i.imgur.com/tij2x.jpg">full of new security fixes for Rails</a>. I think it would be good to know <a href="http://rubysource.com/anatomy-of-an-exploit-an-in-depth-look-at-the-rails-yaml-vulnerability/">why all that happened</a>. Read about <a href="http://tenderlovemaking.com/2013/02/06/yaml-f7u12.html">problems with YAML</a> and secure your app from… <a href="http://blog.presidentbeef.com/blog/2013/02/08/avoid-sql-injection-in-rails/"><em>your own</em> mistakes</a>.</p>
<p>It’s also worth knowing why security is such a difficult topic: <a href="http://homakov.blogspot.com/2013/02/rethinking-cookies-originonly.html">where most problems lie</a> or how to secure less known holes like <a href="http://blog.phusion.nl/2013/01/04/securing-the-rails-session-secret/">Rails session secret</a>.</p>
<p>When talking about errors, consider including <a href="http://railscasts.com/episodes/402-better-errors-railspanel" class="mono">better_errors</a> in your project’s <b class="mono">Gemfile</b>. Apart from its output being much nicer than the default, the gem comes with some additional features.</p>
<h2>Improve your tests</h2>
<p>First of all, make them <a href="http://uxebu.com/blog/2013/01/08/make-tests-read-like-a-book/">more pleasant for your eyes to read</a>, and <a href="http://www.elabs.se/blog/51-simple-tricks-to-clean-up-your-capybara-tests">easier to parse</a> for the mind.</p>
<p>After that, consider the following <a href="http://blog.8thlight.com/eric-meyer/2013/01/13/migrating_from_rspec_dynamic_mocks_to_surrogate_part1.html">improvements for Mocks</a> thanks to Surrogate (<a href="http://blog.8thlight.com/eric-meyer/2013/01/13/migrating_from_rspec_dynamic_mocks_to_surrogate_part2.html" title="The second part">#2</a>), which gives you more feedback when your application happens to fail.</p>
<p>At last, but not least, make sure you <a href="http://solnic.eu/2013/01/23/mutation-testing-with-mutant.html">test everything</a>. And I really mean <em>everything.</em></p>
<img src="http://feeds.feedburner.com/~r/CodeTunes/~4/BCPeboXy2Vk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://codetunes.com/2013/from-monterail-with-love-3/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://codetunes.com/2013/from-monterail-with-love-3?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=from-monterail-with-love-3</feedburner:origLink></item>
		<item>
		<title>wroc_love.rb strikes again</title>
		<link>http://feedproxy.google.com/~r/CodeTunes/~3/RY0tMhe7mdE/wroc_love_rb-2013</link>
		<comments>http://codetunes.com/2013/wroc_love_rb-2013#comments</comments>
		<pubDate>Wed, 13 Feb 2013 11:11:45 +0000</pubDate>
		<dc:creator>Jan Dudulski</dc:creator>
				<category><![CDATA[Conferences]]></category>
		<category><![CDATA[ruby conference]]></category>
		<category><![CDATA[wroclaw]]></category>
		<category><![CDATA[wroc_love.rb]]></category>

		<guid isPermaLink="false">http://codetunes.com/?p=1003</guid>
		<description><![CDATA[Do you remember the beauty march in Wrocław last year? The amazing event happened and we’re proudly announcing that its sequel is coming in less than a month: the “fresh Ruby-oriented conference in Wrocław, Poland” will take place on March 1–3rd, 2013. Just check the list of the speakers, and be sure that the last [...]]]></description>
				<content:encoded><![CDATA[<p>Do you remember the <a href="http://codetunes.com/2011/wroc_love_rb">beauty march</a> in Wrocław last year? The amazing event happened and we’re proudly announcing that its sequel is coming in less than a month: the “fresh Ruby-oriented conference in Wrocław, Poland” will take place on March 1–3rd, 2013.</p>
<div class="wp-caption aligncenter" style="width: 598px"><a href="http://wrocloverb.com"><img src="http://codetunes.s3.amazonaws.com/posts/janek-wrocloverb-flyer.png" alt="wroc_love.rb 2013" width="588" height="191" class="size-full" /></a><p class="wp-caption-text">Visit this year’s website.</p></div>
<p>Just check the list of <a href="http://wrocloverb.com/">the speakers</a>, and be sure that <a href="http://www.flickr.com/search/?q=wroc_love">the last year</a> was just a warm-up. New conventions, talks fully loaded with <em>meat</em>, and long run of before and after parties. A lot of important mind-changes that will result in hot discussions will strike again, with fresh additions and surprises.</p>
<div id="attachment_1006" class="wp-caption aligncenter" style="width: 522px"><a href="http://www.flickr.com/photos/jandudulski/6980343959/in/set-72157629579370101/lightbox/"><img src="http://codetunes.s3.amazonaws.com/posts/janek-wrocloverb-photo.jpg" alt="wroc_love.rb 2012" width="512" height="340" class="size-full wp-image-1006" /></a><p class="wp-caption-text">Last year’s discussions were intense and very informative.</p></div>
<p>Find, talk and grab a beer with us during the conference! <em>If you’re reading this blog, then you definitely should.</em></p>
<p>You can follow <a href="http://wrocloverb.com" class="mono">wroc_love.rb</a> on <a href="https://twitter.com/wrocloverb">Twitter</a> and <a href="https://www.facebook.com/wroclove.rb">Facebook</a>. Keep an eye on <a href="http://blog.wrocloverb.com/">the blog</a> for the next batch of tickets if you still don’t have one.</p>
<img src="http://feeds.feedburner.com/~r/CodeTunes/~4/RY0tMhe7mdE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://codetunes.com/2013/wroc_love_rb-2013/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://codetunes.com/2013/wroc_love_rb-2013?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=wroc_love_rb-2013</feedburner:origLink></item>
		<item>
		<title>Robust dashboard application with Faye</title>
		<link>http://feedproxy.google.com/~r/CodeTunes/~3/C67cRvTkLc8/robust-dashboard-application-with-faye</link>
		<comments>http://codetunes.com/2013/robust-dashboard-application-with-faye#comments</comments>
		<pubDate>Mon, 11 Feb 2013 14:10:43 +0000</pubDate>
		<dc:creator>Tymon Tobolski</dc:creator>
				<category><![CDATA[Front-end]]></category>
		<category><![CDATA[Libraries]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Software Engineering]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[faye]]></category>
		<category><![CDATA[redis]]></category>
		<category><![CDATA[sidekiq]]></category>

		<guid isPermaLink="false">http://codetunes.com/?p=704</guid>
		<description><![CDATA[There’s a dashboard in one of our applications that shows data from various external services. The more data we were adding to this dashboard, the worse its performance and user experience was getting until the site eventually became unusable. It got to the point where its user had to wait 10 seconds or even more [...]]]></description>
				<content:encoded><![CDATA[<p>There’s a dashboard in one of our applications that shows data from various external services. The more data we were adding to this dashboard, the worse its performance and user experience was getting until the site eventually became unusable. It got to the point where its user had to wait 10 seconds or even more for the content to show up. Unfortunately, caching didn’t help much.</p>
<p>Here’s the story of what we did to reduce the load time.<span id="more-704"></span></p>
<div id="attachment_706" class="wp-caption aligncenter" style="width: 508px"><img src="http://codetunes.com/wp-content/uploads/2013/01/dashboard.png" alt="The mockup of the dashboard" width="498" height="489" class="size-full wp-image-706" /><p class="wp-caption-text">The dashboard</p></div>
<h2>Humble beginnings</h2>
<p>The first version of the dashboard was dead simple: call remote APIs during the request and render the results. It quickly turned out it won’t work—a few of API calls took quite a lot of time to respond, and making them in parallel via Rails’ action is difficult and error-prone.</p>
<p>Obviously, if you have to wait such long time for the homepage to load, it’s very poor user experience. You might even wonder that something’s wrong.</p>
<p>The second take was much better. If the homepage is requested, let’s return its layout only and then use AJAX to fetch data. Unfortunately, due to browser limitations and the amount of containers to fill with the data (usually 7), it was still insufficient: long-running spinners and AJAX calls’ timeouts.</p>
<h2>Faye to the rescue!</h2>
<p>Another idea was to use <a href="http://faye.jcoglan.com/">Faye</a> for pushing data into the browser, so that there would be no more timeouts during HTTP requests.</p>
<p>Right after the loaded homepage layout, the browser subscribed to specific Faye channel and triggered the processing of API calls. When one of the them succeeded, its results were pushed to the browser.</p>
<p>The solution was quite satisfying, yet we wondered if we could have done it even better.</p>
<p><img src="http://codetunes.s3.amazonaws.com/posts/tymon-faye-timeline1.png" alt="Timeline 1" class="aligncenter size-full wp-image-707" style="width: 100%; max-width: 619px" /></p>
<p><em>Why?</em> Look at the timeline, there’s still the unnecessary delay—API jobs could have been started much sooner. Due to Faye channels architecture, the client receives only the messages that were sent after having subscribed to the channel.</p>
<p><img src="http://codetunes.s3.amazonaws.com/posts/tymon-faye-timeline2.png" alt="Timeline 2" class="aligncenter size-full wp-image-708" style="width: 100%; max-width: 619px" /></p>
<p>As you can see, the earlier the jobs are started, the earlier they finish and they could be able to push the results before the client subscribes to the channel which would result in message loss. In this case, <b class="mono">API Job #2 Faye push</b> happens before <b class="mono">Faye subscribe</b>.</p>
<p>If only there was a way to save those message somehow when the client is not yet connected and send them when it’s connected…</p>
<h2>Redis Faye back-end</h2>
<p>Turns out it’s possible using a bit modified <a href="https://github.com/faye/faye-redis-ruby">Redis back-end for Faye</a>. Consider the following code:</p>
<pre class="highlight"><code><span class="k">module</span> <span class="nn">Faye</span>
  <span class="k">class</span> <span class="nc">PersistentRedis</span> <span class="o">&lt;</span> <span class="ss">Faye</span><span class="p">:</span><span class="ss">:Redis</span>
    <span class="no">DEFAULT_EXPIRE</span> <span class="o">=</span> <span class="mi">60</span> <span class="c1"># default expiration timeout for awaiting messages</span>

    <span class="k">def</span> <span class="nf">subscribe</span><span class="p">(</span><span class="n">client_id</span><span class="p">,</span> <span class="n">channel</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">callback</span><span class="p">)</span>
      <span class="k">super</span>
      <span class="n">publish_awaiting_messages</span><span class="p">(</span><span class="n">channel</span><span class="p">)</span>
    <span class="k">end</span>

    <span class="k">def</span> <span class="nf">publish_awaiting_messages</span><span class="p">(</span><span class="n">channel</span><span class="p">)</span>
      <span class="c1"># fetch awaiting messages from redis and publish them</span>
      <span class="vi">@redis</span><span class="o">.</span><span class="n">lpop</span><span class="p">(</span><span class="vi">@ns</span> <span class="o">+</span> <span class="s2">&quot;/channels</span><span class="si">#{</span><span class="n">channel</span><span class="si">}</span><span class="s2">/awaiting_messages&quot;</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">json_message</span><span class="o">|</span>
        <span class="k">if</span> <span class="n">json_message</span>
          <span class="n">message</span> <span class="o">=</span> <span class="ss">Yajl</span><span class="p">:</span><span class="ss">:Parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">json_message</span><span class="p">)</span>
          <span class="n">publish</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="o">[</span><span class="n">message</span><span class="o">[</span><span class="s2">&quot;channel&quot;</span><span class="o">]]</span><span class="p">)</span>
          <span class="n">publish_awaiting_messages</span><span class="p">(</span><span class="n">channel</span><span class="p">)</span>
        <span class="k">end</span>
      <span class="k">end</span>
    <span class="k">end</span>

    <span class="k">def</span> <span class="nf">publish</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">channels</span><span class="p">)</span>
      <span class="n">init</span>
      <span class="vi">@server</span><span class="o">.</span><span class="n">debug</span> <span class="s1">&#39;Publishing message ?&#39;</span><span class="p">,</span> <span class="n">message</span>

      <span class="n">json_message</span> <span class="o">=</span> <span class="ss">Yajl</span><span class="p">:</span><span class="ss">:Encoder</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
      <span class="n">channels</span>     <span class="o">=</span> <span class="no">Channel</span><span class="o">.</span><span class="n">expand</span><span class="p">(</span><span class="n">message</span><span class="o">[</span><span class="s1">&#39;channel&#39;</span><span class="o">]</span><span class="p">)</span>
      <span class="n">keys</span>         <span class="o">=</span> <span class="n">channels</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span> <span class="vi">@ns</span> <span class="o">+</span> <span class="s2">&quot;/channels</span><span class="si">#{</span><span class="n">c</span><span class="si">}</span><span class="s2">&quot;</span> <span class="p">}</span>

      <span class="vi">@redis</span><span class="o">.</span><span class="n">sunion</span><span class="p">(</span><span class="o">*</span><span class="n">keys</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">clients</span><span class="o">|</span>
        <span class="k">if</span> <span class="n">clients</span><span class="o">.</span><span class="n">empty?</span>
          <span class="n">key</span> <span class="o">=</span> <span class="vi">@ns</span> <span class="o">+</span> <span class="s2">&quot;/channels</span><span class="si">#{</span><span class="n">message</span><span class="o">[</span><span class="s2">&quot;channel&quot;</span><span class="o">]</span><span class="si">}</span><span class="s2">/awaiting_messages&quot;</span>
          <span class="c1"># store message in redis</span>
          <span class="vi">@redis</span><span class="o">.</span><span class="n">rpush</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">json_message</span><span class="p">)</span>
          <span class="c1"># set expiration time</span>
          <span class="vi">@redis</span><span class="o">.</span><span class="n">expire</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="vi">@options</span><span class="o">[</span><span class="ss">:expire</span><span class="o">]</span> <span class="o">||</span> <span class="no">DEFAULT_EXPIRE</span><span class="p">)</span>
        <span class="k">else</span>
          <span class="n">clients</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">client_id</span><span class="o">|</span>
            <span class="vi">@server</span><span class="o">.</span><span class="n">debug</span> <span class="s1">&#39;Queueing for client ?: ?&#39;</span><span class="p">,</span> <span class="n">client_id</span><span class="p">,</span> <span class="n">message</span>
            <span class="vi">@redis</span><span class="o">.</span><span class="n">rpush</span><span class="p">(</span><span class="vi">@ns</span> <span class="o">+</span> <span class="s2">&quot;/clients/</span><span class="si">#{</span><span class="n">client_id</span><span class="si">}</span><span class="s2">/messages&quot;</span><span class="p">,</span> <span class="n">json_message</span><span class="p">)</span>
            <span class="vi">@redis</span><span class="o">.</span><span class="n">publish</span><span class="p">(</span><span class="vi">@ns</span> <span class="o">+</span> <span class="s1">&#39;/notifications&#39;</span><span class="p">,</span> <span class="n">client_id</span><span class="p">)</span>
          <span class="k">end</span>
        <span class="k">end</span>
      <span class="k">end</span>

      <span class="vi">@server</span><span class="o">.</span><span class="n">trigger</span><span class="p">(</span><span class="ss">:publish</span><span class="p">,</span> <span class="n">message</span><span class="o">[</span><span class="s1">&#39;clientId&#39;</span><span class="o">]</span><span class="p">,</span> <span class="n">message</span><span class="o">[</span><span class="s1">&#39;channel&#39;</span><span class="o">]</span><span class="p">,</span> <span class="n">message</span><span class="o">[</span><span class="s1">&#39;data&#39;</span><span class="o">]</span><span class="p">)</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="c1"># Faye::Logging.log_level = :info</span>
<span class="n">faye_server</span> <span class="o">=</span> <span class="ss">Faye</span><span class="p">:</span><span class="ss">:RackAdapter</span><span class="o">.</span><span class="n">new</span><span class="p">(</span>
  <span class="ss">:mount</span> <span class="o">=&gt;</span> <span class="s1">&#39;/faye&#39;</span><span class="p">,</span>
  <span class="ss">:timeout</span> <span class="o">=&gt;</span> <span class="mi">30</span><span class="p">,</span>
  <span class="ss">:engine</span> <span class="o">=&gt;</span> <span class="p">{</span>
    <span class="ss">:type</span>  <span class="o">=&gt;</span> <span class="ss">Faye</span><span class="p">:</span><span class="ss">:PersistentRedis</span><span class="p">,</span>
    <span class="ss">:namespace</span> <span class="o">=&gt;</span> <span class="s2">&quot;faye&quot;</span><span class="p">,</span>
    <span class="ss">:expire</span> <span class="o">=&gt;</span> <span class="mi">60</span> <span class="c1"># one minute</span>
  <span class="p">}</span>
<span class="p">)</span></code></pre>
<p>A part of <code>publish</code> checks if there any clients subscribed to the channel—if not, the message is stored in the list:</p>
<pre><code>/channels/$channel/awaiting_messages</code></pre>
<p>When the clients eventually subscribes, the stored messages are removed from the list and pushed.</p>
<p>Importantly, there is a possibility that the client never subscribes to the channel. To prevent storing the ever-increasing amount of messages in Redis, expiration time is set to one minute on the same key.</p>
<h2>The final solution</h2>
<p>The full resultant stack consists of Rails, <a href="http://mperham.github.com/sidekiq/">Sidekiq</a>, and the modified <a href="http://faye.jcoglan.com/">Faye</a> server.</p>
<p>When the first request takes place, API jobs are queued in Sidekiq. Then the finished jobs are pushed to Faye and saved in Redis when needed. The browser loads the layout and subscribes to Faye channel that retrieves both the messages that were already stored and those new ones that are being created.</p>
<img src="http://feeds.feedburner.com/~r/CodeTunes/~4/C67cRvTkLc8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://codetunes.com/2013/robust-dashboard-application-with-faye/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://codetunes.com/2013/robust-dashboard-application-with-faye?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=robust-dashboard-application-with-faye</feedburner:origLink></item>
		<item>
		<title>The One Year Tale</title>
		<link>http://feedproxy.google.com/~r/CodeTunes/~3/kJ74ZCyffyM/the-one-year-tale</link>
		<comments>http://codetunes.com/2013/the-one-year-tale#comments</comments>
		<pubDate>Fri, 01 Feb 2013 14:59:33 +0000</pubDate>
		<dc:creator>Jan Dudulski</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[community]]></category>
		<category><![CDATA[newbie]]></category>

		<guid isPermaLink="false">http://codetunes.com/?p=853</guid>
		<description><![CDATA[It seems like it happened yesterday. I arrived at the flat in a crumbling tenement located in the Old Town of Wrocław and my journey into the Ruby world began. The community was already large and very active, so I wouldn’t call myself Columb, but—at least—I can tell you about my first year experience and [...]]]></description>
				<content:encoded><![CDATA[<p>It seems like it happened yesterday. I arrived at the flat in a crumbling tenement located in the Old Town of Wrocław and my journey into the Ruby world began. The community was already large and very active, so I wouldn’t call myself Columb, but—at least—I can tell you about my first year experience and share both bright and dark sides of the story.</p>
<p><span id="more-853"></span></p>
<h2>Background</h2>
<p>I didn’t join the awesome <a href="http://monterail.com/team">Monterail guys</a> as a complete novice. I was working in the industry since 2007, mostly as a PHP programmer. As the world was moving forward, I felt like PHP kept standing in the same place, and <em>to stand still is to move back.</em></p>
<p>While I was looking to switch, I glanced off at Python which I was already familiar with. <a href="https://github.com/ghandal">My colleague</a> convinced me that I should check the programming language called Ruby, which was similar at first sight. So I put all one’s eggs in one basket, bought <a href="http://pragprog.com/book/ruby3/programming-ruby-1-9">Programming in Ruby 1.9</a> and… actually fell in love with it.</p>
<h2>Jumping on the bandwagon</h2>
<p>I learned a little about Ruby itself, Rails and a few other popular gems.</p>
<p>After two or three months of working at Monterail, I felt like a fish in the water. I spent a lot of time on reading before, so I already knew about <a href="http://words.steveklabnik.com/rails-has-two-default-stacks">the two paths for everything</a> (even developed some preferences) and was able to omit <a href="http://rob.yurkowski.net/post/17610425880/rails-is-definitely-not-for-beginners">the biggest headache</a> during the real work.</p>
<p>To make things more complicated, Rails 3 was still quite fresh subject at the time. It was quite controversial because of its asset pipeline or including CoffeeScript by default. Blogs were flooded with laments that Rails wasn’t for beginners anymore.</p>
<p>From my point of view, diving right into the version 3 was an advantage. Improved structure and modularity, <a href="http://gembundler.com">Bundler</a>, and all that hot additions weren’t really invasive, even though they were problematic for many. I could feel the difference when I was fixing something in an old project based on Rails 2—it even felt like hitting the wall in couple of places.</p>
<h2>The community</h2>
<p>I don’t need to tell you about differences between Ruby and PHP language, but I’ll compare their communities.</p>
<p>The most impressive thing to me was thinking about an architecture and patterns: DCI, Service Layer, Active Record madness, modularity, the rules of writing clean code… I’ve read about dozens of articles on the topics—all of them came from the Ruby community. It really impress me that whole community loves to learn new things and evolve constantly. On the other hand, things that the PHP world offered were just tips and tricks or practical advices for specific cases and tools.</p>
<p>Open Source is another big subject. PHP gave birth to many well-known free products: <a href="https://www.phpbb.com">phpBB</a>, <a href="http://wordpress.org">WordPress</a>, <a href="http://www.joomla.org">Joomla</a>… Comparing them and the rest of open source PHP projects to Ruby’s, they might look like a midget. Thanks to <a href="https://github.com/">GitHub</a>, sharing source code became really easy; the Ruby community spread over it and the boom started. In result, <em>we</em> have better tools, better code, better skills, and—of course—the boost over our competitors that write in PHP.</p>
<p>When talking about sharing skills, I can’t just not mention <a title="Ruby User Groups" href="http://rubyusergroups.org/">RUGs</a> and conferences. I’ve known about just one PHP conference and I’ve never heard about any local user groups. Wrocław has the awesome <a title="Dolnośląski Ruby User Group" href="http://drug.org.pl/">DRUG</a> and we know many other RUGs in Poland. Yet, I’ve visited three Ruby conferences so far: <a href="http://rupy.eu/">RuPy</a>, <a class="mono" href="http://wrocloverb.com/">wroc_love.rb</a>, and <a href="http://euruko.org/">EuRuKo</a>), but you can find them everywhere, every month!</p>
<p>Did I mentioned testing? <em>Well…</em> let’s not hit somebody when he’s down.</p>
<p><strong>The future</strong></p>
<p>I’m looking forward to the following months: Rails 4, <b class="mono">wroc_love.rb</b> 2013, DataMapper 2, discussions about concurrency, single page apps or making model layer thin. Even if I quit this community one day, I would always think fondly about Ruby, Rails, and whole community just for fun, some fresh air and to push me forward.</p>
<p><em>Thank you,</em> Monterail’s founding fathers, for making me the part of the team and making me work in this awesome community.</p>
<img src="http://feeds.feedburner.com/~r/CodeTunes/~4/kJ74ZCyffyM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://codetunes.com/2013/the-one-year-tale/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://codetunes.com/2013/the-one-year-tale?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=the-one-year-tale</feedburner:origLink></item>
		<item>
		<title>Validate gem checksums on Capistrano deployment</title>
		<link>http://feedproxy.google.com/~r/CodeTunes/~3/A_T7-bsFIr0/validate-gem-checksums-on-capistrano-deployment</link>
		<comments>http://codetunes.com/2013/validate-gem-checksums-on-capistrano-deployment#comments</comments>
		<pubDate>Thu, 31 Jan 2013 16:03:56 +0000</pubDate>
		<dc:creator>Michał Szajbe</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[capistrano]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[rubygems]]></category>

		<guid isPermaLink="false">http://codetunes.com/?p=843</guid>
		<description><![CDATA[RubyGems.org has been compromised. The exploit could potentially tamper with some gems, therefore all of them are assumed to be unsafe to use at the moment. Which means that any deployment involving downloads of any gems from RubyGems.org should be carried out with extreme caution. All downloaded gems have to be verified in order to [...]]]></description>
				<content:encoded><![CDATA[<p><a href="https://rubygems.org">RubyGems.org</a> <a href="http://news.ycombinator.com/item?id=5139583">has been compromised</a>.</p>
<p>The exploit could potentially tamper with some gems, therefore all of them are assumed to be unsafe to use at the moment. Which means that any deployment involving downloads of any gems from RubyGems.org should be carried out with extreme caution. All downloaded gems have to be verified in order to remain on <em>the safe side.</em></p>
<p><span id="more-843"></span></p>
<p>The Ruby community reacted quickly— it’s now possible to compare checksums of downloaded gems with the checksums of their known-to-be-safe versions hosted on mirroring sites.</p>
<p>We use <a href="https://github.com/capistrano/capistrano">Capistrano</a> for deployment, so we created a recipe to automate the verification process. It internally uses the <a class="mono" href="https://gist.github.com/4682614">validate_gem_checksums</a> script (originally posted by <a href="https://gist.github.com/4678189">James Tucker</a>, then adjusted to our needs). It validates gems’ checksums after <code>bundle install</code> and aborts the deployment in case of any mismatch between the checksums.</p>
<pre><code>namespace :bundler do
  task :setup, :roles =&gt; :app, :except =&gt; { :no_release =&gt; true }  do
    run "mkdir -p #{shared_path}/.bundle"
  end

  task :create_symlink, :roles =&gt; :app, :except =&gt; { :no_release =&gt; true } do
    run "if [ -d #{release_path}/.bundle ]; then mv #{release_path}/.bundle #{release_path}/.bundle.old; fi"
    run "if [ -f #{shared_path}/.bundle ]; then ln -nfs #{shared_path}/.bundle #{release_path}/.bundle; fi"
  end

  task :bundle_new_release, :roles =&gt; :app, :except =&gt; { :no_release =&gt; true } do
    bundler.create_symlink
    run "cd #{release_path} &amp;&amp; bundle install --path #{shared_path}/bundle --without development cucumber test"
  end

  task :validate_gem_checksums, :roles =&gt; :app, :except =&gt; { :no_release =&gt; true } do
    run "curl -s https://gist.github.com/raw/4682614 -o /tmp/validate_gem_checksums.sh"
    run "bash /tmp/validate_gem_checksums.sh #{shared_path}/bundle/ruby/**/cache"
  end
end

after "deploy:setup" do
  bundler.setup
end

after "deploy:update_code" do
  bundler.bundle_new_release
  bundler.validate_gem_checksums
end</code></pre>
<p>The usage of this validation script is quite straightforward:</p>
<pre><code>bash /tmp/validate_gem_checksums.sh gem_cache_path</code></pre>
<p>You need to pass the path to the cache directory of your gems, which is <b class="mono">bundle/ruby/**/cache</b> in our case. Yours may differ, so adjust accordingly.</p>
<p>Please note that it downloads the validation script from Gist every time it’s executed. For safety reasons, you should fork it and use own version.</p>
<img src="http://feeds.feedburner.com/~r/CodeTunes/~4/A_T7-bsFIr0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://codetunes.com/2013/validate-gem-checksums-on-capistrano-deployment/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://codetunes.com/2013/validate-gem-checksums-on-capistrano-deployment?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=validate-gem-checksums-on-capistrano-deployment</feedburner:origLink></item>
		<item>
		<title>On social media buttons</title>
		<link>http://feedproxy.google.com/~r/CodeTunes/~3/fnb1B9CS_Rc/on-social-media-buttons</link>
		<comments>http://codetunes.com/2013/on-social-media-buttons#comments</comments>
		<pubDate>Fri, 18 Jan 2013 11:39:35 +0000</pubDate>
		<dc:creator>Dominik Porada</dc:creator>
				<category><![CDATA[Codetunes]]></category>
		<category><![CDATA[Thinking]]></category>
		<category><![CDATA[codetunes redesign]]></category>
		<category><![CDATA[social media]]></category>
		<category><![CDATA[ux]]></category>

		<guid isPermaLink="false">http://codetunes.com/?p=719</guid>
		<description><![CDATA[We recently launched the redesign of our blog, but Codetunes is still work in progress. This is a post kicking off the unordered series of articles outlining some of the decisions we’ve made during this ongoing process. The story It’s amusing how seemingly trivial things can lead to the most exhaustive discussions and disagreements. Just [...]]]></description>
				<content:encoded><![CDATA[<p>We recently launched the redesign of our blog, but <a href="http://codetunes.com/">Codetunes</a> is still work in progress. This is a post kicking off the <a href="http://codetunes.com/tag/codetunes-redesign">unordered series of articles</a> outlining some of the decisions we’ve made during this ongoing process.<span id="more-719"></span></p>
<h2>The story</h2>
<p>It’s amusing how seemingly trivial things can lead to the most exhaustive discussions and disagreements.</p>
<p>Just before pushing the new theme for the blog, we had a debate on the notorious social media buttons and whether or not we should include them on post pages. Half of the participants, under the shield of <a href="http://informationarchitects.net/blog/sweep-the-sleaze/" title="Sweep the Sleaze">Oliver Reichenstein’s loud article</a>, defended their ambivalence towards <b class="mono">Like</b>, <b class="mono">Tweet</b>, and <b class="mono">+1</b> plague on the Web before the other half that was represented by actual users of the widgets—people who show their appreciation that way.</p>
<p>Our blog stats were somewhere in-between.</p>
<h2>The solution</h2>
<p>We eventually decided to create our own inconspicuous heart-shaped widget and hide all the social stuff at first. If a reader would like to express her enjoyment of the content in a way other than linking to Codetunes, she could still do it.</p>
<div id="attachment_723" class="wp-caption aligncenter" style="width: 310px"><img src="http://codetunes.com/wp-content/uploads/2013/01/Love-It-1.png" alt="Custom “Love it” widget" width="300" height="90" class="size-full wp-image-723" /><p class="wp-caption-text">Custom “Love it” widget inspired by <a href="http://www.behance.net/gallery/Codetunescom-Responsive-Design/6169493#appreciation-sticker">Behance’s “Appreciate this” sticker</a>.</p></div>
<p>After the user action, we have more ground to assume that the reader might be willing to also use one of the social media buttons, so the third-party widgets appear next to the heart.</p>
<div id="attachment_724" class="wp-caption aligncenter" style="width: 310px"><img src="http://codetunes.com/wp-content/uploads/2013/01/Love-It-2.png" alt="Custom “Love it” widget" width="300" height="90" class="size-full wp-image-724" /><p class="wp-caption-text">“Love it” after user’s action.</p></div>
<p>And all that is served with the juicy animation. <em>I dare you to try it.</em></p>
<h2>The response</h2>
<p>Looking at our stats and adoption of the gizmo, we’re happy to report that the feedback has been veritably positive. We’ve noticed a slight bump in usage of the actual social media buttons too!</p>
<h2>The lesson</h2>
<p>If you can afford the time, just <em>analyze.</em> Even the smallest issues.</p>
<p>Remember that designing user experiences means making trade-offs and that you can’t blindly follow any advice without thinking it through. Not every pro tip is suitable for your project. It’s because, when doing stuff on the Web, the answer for “should we do <b class="mono">X</b>?” is almost always the same. <em>It depends.</em></p>
<img src="http://feeds.feedburner.com/~r/CodeTunes/~4/fnb1B9CS_Rc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://codetunes.com/2013/on-social-media-buttons/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://codetunes.com/2013/on-social-media-buttons?utm_source=rss&amp;utm_medium=rss&amp;utm_campaign=on-social-media-buttons</feedburner:origLink></item>
	</channel>
</rss><!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using disk: basic
Database Caching using disk: basic
Object Caching 286/538 objects using disk: basic

 Served from: codetunes.com.mh1.monterail.eu @ 2013-05-20 20:56:43 by W3 Total Cache -->
