tag:blogger.com,1999:blog-78218566522575547792024-02-22T03:15:45.465+01:00Andrzej on SoftwareThoughts on softwareAndrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.comBlogger128125tag:blogger.com,1999:blog-7821856652257554779.post-75277582726971791262017-01-04T18:48:00.001+01:002017-01-04T18:48:07.373+01:00What would be the franchise for the app you're developing?I live between the two worlds - business and programming.<br />
<br />
What I learn in one of the worlds can sometimes be inspiring to the second one. This is what happened with the last book I read. I've just finished reading a book called <a href="https://www.amazon.com/Myth-Revisited-Small-Businesses-About/dp/0887307280">"The E-myth Revisited: Why Most Small Businesses Don't Work and What to Do About It"</a>.<br />
<br />
In short, the book is about approaching your business as a franchise model. In this approach you're not only interested in building a single company, you're interested in creating a factory of businesses. More like McDonald's than a single shop. In this way of thinking, you're business becomes The Franchise Prototype.<br />
<br />
While I'm still not yet sure if that's the way I'd like to run a business (it does smell a bit like corpo-stuff which I prefer to avoid), it did make me think about writing software.<br />
<br />
When we're meant to work on a project, our focus is on the project. We want to get it done, the best way we can. We focus on the project and we try to avoid over-generalization, over-architectures and stuff.<br />
<br />
<b>What if instead of focusing on building the single project, you would focus on building a franchise of such apps?</b> How would that change your approach? Would you do things differently?<br />
<br />
In fact, that's what DHH did. He was meant to build a project management web app. What he actually built was Ruby on Rails, a framework for building web applications. Basecamp was just one instance of this framework (and it still is 10 years after that!).<br />
<br />
What Domain-Driven Design taught me is the importance of tackling the business complexity by focusing on the right language - both in the communication with the business/clients/users and within the codebase.<br />
<br />
<b>What DHH did was actually creating the right language which is shared among web developers</b> - controllers, actions, views, models, database, schema, migrations, resources. Everything else was a result of choosing the right language, a language which is shared by everyone.<br />
<br />
In the business apps we work on, the target is not exactly developers (as in DHH case), it's the business and their customers. But developers are also part of the equation, they write the code using the language. If we do the job right, use the right business language in our code, then we might be able to build a factory of apps for this specific businesses, not just a single app. If we build the right abstractions, the creating new apps/features for the same business is similar to opening a new franchise instance - all easy, according to existing processes.<br />
<br />
When you look at any franchise documents (as a developer you probably haven't had many chances), you'll see that those documents, those processes are organised around certain contexts - marketing, sales, finances, accounting, invoicing, recruitment. That's exactly what we call Bounded Contexts in DDD. A right definition of bounded contexts helps us create a consistent and repeatable description of the business we work for.<br />
<br />
<b>What are the bounded contexts for the Rails as a franchise?</b> Well it's right there at the facade of the codebase: <a href="https://github.com/rails/rails">https://github.com/rails/rails</a><br />
<br />
At the moment of writing it, we've got:<br />
<br />
<ul>
<li>actioncable</li>
<li>actionmailer</li>
<li>actionpack</li>
<li>actionview</li>
<li>activejob</li>
<li>activemodel</li>
<li>activerecord</li>
<li>activesupport</li>
</ul>
<div>
An instance of a Rails franchise is your specific Rails app, where you fill some blanks to make the app making value for someone.</div>
<div>
<br /></div>
<div>
What franchise would you be able to build if you focus on it instead of focusing on the specific app?</div>
<div>
<br /></div>
<div>
<br /></div>
<br />
----<br />
<br />
Psst, there are still free slots for our <a href="http://blog.arkency.com/ddd-training/">Rails/DDD workshops</a> in Wrocław, Poland, 12-13 January, 2017.<br />
<br />
<br />
<br />
<br />
<br />
<br />Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0tag:blogger.com,1999:blog-7821856652257554779.post-19635510918980726092015-12-19T21:55:00.000+01:002015-12-19T21:55:40.344+01:00The perfect blogging platform for developers - what is it?<div class="ace-line gutter-author-p-39419 emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid47" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 9px 54px; transition: opacity 100ms ease-out;">
I've been using many blogging platforms so far and each of them is dev-friendly at something while suck at something else. This post is here to help me visualise the perfect combination.</div>
<div class="ace-line longKeep gutter-noauthor" id="magicdomid1371" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(255, 255, 255); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<br style="margin: 0px; padding: 0px;" /></div>
<div class="ace-line gutter-author-p-39419 emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1621" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">Before I go into features, I want a tool which is simple and without any pain, without anything to learn and remember. It must be optimized for the develoer workflow - creating new drafts should be easy, publishing should be easy. It should be code-oriented.</span></div>
<div class="ace-line longKeep gutter-noauthor" id="magicdomid258" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(255, 255, 255); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<br style="margin: 0px; padding: 0px;" /></div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1361" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">I want to be able to </span><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">easily embed my just made screenshots</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> (with shift-cmd-ctrl-4), as it's possible at Blogger, without any effort - just cmd-v to paste it (wysiwyg)</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1362" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">I like the simplicity of </span><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">markdown</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> and want to be able to use it sometimes, as in nanoc/GH pages</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1363" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">I want to have the post </span><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">look pretty without any additional effort</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> - medium has it OOTB, custom blogs have it after all the styles applied </span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1364" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">medium has a cool </span><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">title inventor</b></span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1365" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">I want to </span><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">add fixes quickly and see them live</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> immedietally (like in Blogger, unlike the statically generated blogs)</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1366" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">none of the platform satisfies me with the </span><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">pre-blog phase - drafts, notes gathering</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> etc</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1093" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent2 list-bullet2" style="list-style: circle; margin: 0px 0px 0px 3em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">nanoc forces me to come up with some title and it generates the date</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1165" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent2 list-bullet2" style="list-style: circle; margin: 0px 0px 0px 3em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">no special support for drafts in nanoc, but we can fake it</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1367" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">publish schedule</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> is sometimes cool</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1248" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent2 list-bullet2" style="list-style: circle; margin: 0px 0px 0px 3em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">Blogger has it OOTB</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1368" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">I love to use iaWriter-like tools, so </span><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">desktop apps</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> when work on longer posts</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1357" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent2 list-bullet2" style="list-style: circle; margin: 0px 0px 0px 3em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">markdown makes it easy</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1799" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;">Some kind of </span><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">Slack integration</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> would be cool (Slack driven posts)</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1800" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">team collaboration</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> is important - allow others to fix typos, edit anything</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid1893" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">IDE integration</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> is crucial - I want to move some code snippets easily as new drafts/posts</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid2098" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">embedding code</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> should just work with synta</span><span class="author-p-39423" style="cursor: auto; margin: 0px; padding: 0px;">x</span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> coloring</span></li>
</ul>
</div>
<div class="ace-line gutter-author-p-39419 line-list-type-bullet emptyGutter" data-author-initials="AK" data-author-link="/ep/profile/GyqPUeeVllT" data-author-name="Andrzej K" id="magicdomid2096" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(127, 192, 219); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<ul class="listtype-bullet listindent1 list-bullet1" style="list-style-image: initial; list-style-position: initial; margin: 0px 0px 0px 1.5em; padding: 0px;">
<li style="margin: 0px; padding: 0px;"><span class="author-p-39419 b" style="cursor: auto; margin: 0px; padding: 0px;"><b style="margin: 0px; padding: 0px;">auto-promotion of blogposts</b></span><span class="author-p-39419" style="cursor: auto; margin: 0px; padding: 0px;"> would be cool, like with Medium - they distribute your posts magically bringing you some traffic</span></li>
</ul>
<div>
<br /></div>
<div>
<br /></div>
<div>
------</div>
<div>
<br /></div>
<div>
Even though, there's no perfect blogging platform, yet - there are still techniques which can help you blog more in less time. </div>
<div>
<br /></div>
<div>
During a limited time, you can buy my <a href="http://blog.arkency.com/blogging/">"Blogging for busy programmers"</a> book with a 30% discount (coupon: <span style="background-color: #f9f9f9; color: #2c2d30; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 15px;">HOLIDAYSALE2015 )</span></div>
</div>
<div class="ace-line longKeep gutter-noauthor" id="magicdomid1795" style="-webkit-transition: opacity 100ms ease-out; background-color: white; border-left-color: rgb(255, 255, 255); border-left-style: solid; border-left-width: 4px; color: #3b3a3c; font-family: ProximaNova-Light, nova, arial, sans-serif; font-size: 17px; line-height: 1.5em; margin: 0px; opacity: 1; padding: 0px 60px 0px 54px; transition: opacity 100ms ease-out;">
<br style="margin: 0px; padding: 0px;" /></div>
Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com3tag:blogger.com,1999:blog-7821856652257554779.post-64468018472412492282015-12-19T18:40:00.000+01:002015-12-19T18:51:25.918+01:00mutant and minitest within a Rails application2015 was the year of mutation testing for me. Luckily, thanks to the effort of Markus Schirp, the Ruby community has the <a href="https://github.com/mbj/mutant">mutant</a> tool.<br />
<br />
In short - mutant is totally "production"-ready and may help you code with more confidence, by testing your tests.<br />
<br />
What mutant does is it parses your code, builds the Abstrax Syntax Tree and then it makes some mutation, like changing true to false. After that it runs the tests. If the tests still pass, then you have an alive mutant and it's bad.<br />
<br />
When it comes to details, mutant supports rspec. Rspec is usually the testing framework of choice for many Ruby devs (or maybe Rails devs?). While I see the value of RSpec, I'm also sceptical about the additional layers of abstractions.<br />
<br />
In short - I'm not a fan of rspec. However, I'm a fan of mutant and that was a more important thing to me than using minitest. At Arkency, we've even had situations that projects switched from minitest to rspec, "because mutant".<br />
<br />
As for December 2015, there's a pull request which has the minitest integration. It's not released yet, though. So, if you want to use it, you need to use this particular branch.<br />
<br />
<a href="https://github.com/mbj/mutant/pull/445">https://github.com/mbj/mutant/pull/445</a><br />
<br />
How do you make it work with a minitest-based Rails app?<br />
<br />
Add this to the Gemfile:<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-family: 'Menlo'; font-size: 9.0pt;"><span style="background-color: #344134;">gem</span> <span style="color: #6a8759;">'mutant'</span><span style="color: #cc7832;">, </span><span style="color: #6e9cbe;">git: </span><span style="color: #52a12e; font-weight: bold;">"git://github.com/mbj/mutant.git"</span><span style="color: #cc7832;">, </span><span style="color: #6e9cbe;">branch:</span><span style="color: #ffc66d; font-style: italic;"> </span><span style="color: #52a12e; font-weight: bold;">"feature/minitest-integration"</span></pre>
<br />
Now if you try to run mutant with a controller test (as an example) by:<br />
<br />
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
RAILS_ENV=test bundle exec mutant -r ./config/environment -I test --use minitest FuckupsController#index</div>
<br />
, you will probably see this error:<br />
<br />
<pre class="special_formatting" style="background-color: #fbfaf8; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; border-top-left-radius: 4px; border-top-right-radius: 4px; border: 1px solid rgba(0, 0, 0, 0.14902); box-sizing: border-box; color: #333333; font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; font-size: 0.75rem; line-height: 1.15rem; margin-bottom: 0.2rem; margin-top: 0.5rem; padding: 0.5rem; white-space: pre-wrap; word-break: normal; word-wrap: break-word;">undefined method `cover_expression' for FuckupsControllerTest:Class (NoMethodError)</pre>
<br />
(and yes, I do have a project with a controller called FuckupsController)<br />
<br />
The thing with the minitest integration is that you need to be more explicit with what the test is actually testing. This helps mutant to understand what it needs to run.<br />
<br />
I had to add this to the top of the FuckupsControllerTest:<br />
<br />
<pre style="background-color: #2b2b2b; color: #a9b7c6; font-family: 'Menlo'; font-size: 9.0pt;"><span style="color: #cc7832; font-weight: bold;">class </span><span style="color: #9876aa; font-style: italic;">FuckupsControllerTest </span><span style="color: #cc7833;">< </span><span style="color: #da4939;">ActionController</span>::<span style="color: #da4939;">TestCase</span><span style="color: #da4939;">
</span><span style="color: #da4939;"> </span><span style="color: #cc7832; font-weight: bold;">def self</span>.<span style="color: #ffc66d;">cover</span>(<span style="color: #9876aa; font-style: italic;">expression</span>)
<span style="color: #d0d0ff;">@expression </span><span style="color: #cc7833;">= </span><span style="color: #9876aa; font-style: italic;">expression</span><span style="color: #9876aa; font-style: italic;"> </span><span style="color: #cc7832; font-weight: bold;">end</span><span style="color: #cc7832; font-weight: bold;">
</span><span style="color: #cc7832; font-weight: bold;"> def self</span>.<span style="color: #ffc66d;">cover_expression</span><span style="color: #ffc66d;"> </span><span style="color: #cc7832; font-weight: bold;">unless </span><span style="color: #d0d0ff;">@expression</span><span style="color: #d0d0ff;"> </span>fail <span style="color: #52a12e; font-weight: bold;">"Cover expression for </span>#{<span style="color: #cc7832; font-weight: bold;">self</span>}<span style="color: #52a12e; font-weight: bold;"> is not specified"</span><span style="color: #52a12e; font-weight: bold;"> </span><span style="color: #cc7832; font-weight: bold;">end</span><span style="color: #cc7832; font-weight: bold;">
</span><span style="color: #cc7832; font-weight: bold;"> </span><span style="color: #d0d0ff;">@expression</span><span style="color: #d0d0ff;"> </span><span style="color: #cc7832; font-weight: bold;">end</span><span style="color: #cc7832; font-weight: bold;">
</span><span style="color: #cc7832; font-weight: bold;"> </span>cover <span style="color: #6a8759;">'FuckupsController'</span></pre>
<br />
In the later steps, I'll move it to some base class and make all the tests inherit from that. In that case, you just need to be explicit with the "cover 'Foo'" thing.<br />
<br />
Now, when I run the same command:<br />
<br />
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
RAILS_ENV=test bundle exec mutant -r ./config/environment -I test --use minitest FuckupsController#index</div>
<br />
I get a nice report like:<br />
<br />
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Mutant configuration:</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Matcher: #<mutant::matcher::config index="" match_expressions:="" uckupscontroller=""></mutant::matcher::config></div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Integration: Mutant::Integration::Minitest</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Expect Coverage: 100.00%</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Jobs: 4</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Includes: ["test"]</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Requires: ["./config/environment"]</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Subjects: 1</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Mutations: 60</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Kills: 60</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Alive: 0</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Runtime: 11.03s</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Killtime: 24.06s</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Overhead: -54.17%</div>
<div style="background-color: black; color: #34bd26; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Coverage: 100.00%</div>
<div style="background-color: black; color: #34bd26; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Expected: 100.00%</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Active subjects: 0</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Mutant configuration:</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Matcher: #<mutant::matcher::config index="" match_expressions:="" uckupscontroller=""></mutant::matcher::config></div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Integration: Mutant::Integration::Minitest</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Expect Coverage: 100.00%</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Jobs: 4</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Includes: ["test"]</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Requires: ["./config/environment"]</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Subjects: 1</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Mutations: 60</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Kills: 60</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Alive: 0</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Runtime: 11.03s</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Killtime: 24.06s</div>
<div style="background-color: black; color: #29f914; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Overhead: -54.17%</div>
<div style="background-color: black; color: #34bd26; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Coverage: 100.00%</div>
<br />
<div style="background-color: black; color: #34bd26; font-family: 'Andale Mono'; font-size: 16px; line-height: normal;">
Expected: 100.00%</div>
<br />
<br />
In short it says, that the FuckupsController#index action is 100% mutation-covered.<br />
<br />
The minitest integration is not officially released for good reasons. Not many projects were tested with it. You can contribute by trying it on any of your minitest code and see if it works.<br />
All feedback welcome at <a href="https://github.com/mbj/mutant/pull/445">https://github.com/mbj/mutant/pull/445</a> ot feel free to ask/comment here and I'll pass it along to the mutant team.<br />
<br />
----<br />
<br />
PS. We now have sale on our Arkency books - <a href="http://blog.arkency.com/products/">http://blog.arkency.com/products/</a> - get a 30% discount with the <span style="background-color: #f9f9f9; color: #2c2d30; font-family: , "applelogo" , sans-serif; font-size: 15px;">HOLIDAYSALE2015 coupon. One of the books is about refactoring Rails controllers which is a perfect fit for the mutation testing idea.</span><br />
<br />Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0tag:blogger.com,1999:blog-7821856652257554779.post-25008985196036182922015-10-27T14:19:00.000+01:002015-10-27T14:19:02.254+01:00Applying chess lessons to programmingChess has always been an important part of my life. I started playing when I was 5 (which means it's now 30 years of my chess "career"), but I got the chess club quite late - when I was 13.<br />
<br />
The nice thing with chess is that there's no age limit and ageing is not as big of a problem as in other disciplines. I have a neighbour who is 75 and he's still chess-beating me from time to time!<br />
<br />
I see many similarities between chess and programming.<br />
<br />
Recently, I've been working on improving my chess to reach the next levels. At the moment I have the title of master candidate (ELO = 2140). My goal is to get to the international master level in the next 5 years.<br />
<br />
This year, I started trainings with a professional chess trainer. I have just finished another session. Part of the lesson was very inspiring to me. It was about things that could be also applicable to programming and our "careers".<br />
<br />
Let me share some of this with you:<br />
<blockquote class="tr_bq">
<b>It's you who must control the current chess position and not the other way round. You need to be 100% sure that you know what this position is about. There's no place for "maybe".</b></blockquote>
When I heard that I immediately knew that was similar to my views about programming, especially about any kind of refactoring. There's no place for "maybe". You need to control the codebase, not the other way rounds. There's no place for "let's run it and see what happens". It's all about confidence.<br />
<br />
The next quotes are more about the chess training, but also relate to the moment of playing the game:<br />
<blockquote class="tr_bq">
<b>Don't move the pieces on the board until you have all prepared in your mind. </b></blockquote>
<br />
<blockquote class="tr_bq">
<b>You need to see the final position after each variation - you need to see what is your goal. There's no places for surprises.</b></blockquote>
<br />
<blockquote class="tr_bq">
<b>Be honest with yourself - do you know everything? Do you know what's your target position? Work on it for as long as needed to be certain.</b></blockquote>
<br />
In refactoring, there are some moments when you can just be creative and move code around to see where it "fits". However, most of the time, you need to know where you're going. Why are you moving the codebase from point A to point B? What is the Z point? If you're planning a bigger change - you need to envision what's the shape of the code, after all the changes.<br />
<br />
Motivation is a huge part of chess. The same with programming:<br />
<br />
<blockquote class="tr_bq">
<b>Simplifying it a bit - there are two ways of motivating yourself - 1. "I'm the winner", 2. "I just need to make the next good move". It's best to balance those two ways. If you're relying more on the first one - you risk losing the fun and enjoyment. If you're more into 2 then you risk not improving yourself, not having goals.</b></blockquote>
<br />
<blockquote class="tr_bq">
<b>Whatever is the result of the game, you need to enjoy the process of playing. Excitement is a big part of improvement. There's no place for stress.</b></blockquote>
<blockquote class="tr_bq">
</blockquote>
My chess work this year reminded me about some things that could be of use in programming:<br />
<br />
<br />
<ul>
<li>Programming is a long-term discipline. It's never too late to improve. </li>
<li>Having a trainer/mentor/coach is super-important. They can help you track your goals, spot your weaknesses, focus on your strengths</li>
<li>Set your short-term goals - what do I want to improve at *this week*?</li>
<li>Set your long-term goals - where do I want to be in 5 years from now?</li>
</ul>
<br />
<ul>
<li>The better you are, the more you enjoy what you do.</li>
<li>The more confidence you acquire, the faster you are.</li>
<li>Frameworks/technologies/libraries/languages - they come and go, as with some chess openings. No need to focus too much on them.</li>
<li>Choose some other programmers who you want to follow, whose style fits where you want to be. I will never be Kasparov or Tal or Shirov, but they are my goals when it comes to the style of playing. The same with programming - I will never be Martin Fowler, Greg Young, Uncle Bob - but they represent the style I want to be better at.</li>
</ul>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>In other news</b></div>
<div>
<b><br /></b></div>
<ul>
<li>We've updated <a href="http://blog.arkency.com/developers-oriented-project-management/">Developers Oriented Project Management</a> (our book about working remotely, asynchronously and without project managers) with 40 Slack protips and 2 bonus chapters. I am sure you will find them useful.</li>
<li><a href="http://blog.arkency.com/responsible-rails/">Responsible Rails</a> got one new story. Robert wrote how Resque and Ruby together trolled us, leading to orphaned temporary files on utility servers. As usually there is also an advice how to avoid that kind of problems in the future by using certain coding patterns.</li>
<li>I've been using mutation testing recently to cover an existing Rails application with tests. Expect more on this topic soon! Mutation testing is one of my long-term programming improvements.</li>
</ul>
Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com5tag:blogger.com,1999:blog-7821856652257554779.post-36778905346485619122015-09-17T16:17:00.001+02:002015-09-21T12:37:07.473+02:00Start from the middle<br />
<div>
The order in which requirements are implemented can have a huge impact on the success of the project. I often recommend a radical approach of <b>starting from the middle </b>to address this issue.</div>
<div>
<br /></div>
<div>
What does it mean?</div>
<div>
<br /></div>
<div>
It can work on different levels. It works on the whole project, but it can also work on a single feature. </div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>Don't focus on providing the data</b></div>
<div>
<br /></div>
<div>
Assume all the data involved in the feature already exists. Don't focus on the way the data is provided. Don't implement the importing feature at the beginning. Focus on what is possible to do with the data in the context of the project (or feature).</div>
<div>
<br /></div>
<div>
Let's say you implement a system which shows the project and its tasks (a project management tool). Starting from the middle would mean focusing on: </div>
<div>
<ul>
<li>how the project/task views looks like, maybe hardcode the HTML/CSS</li>
<li>what you can do with the tasks</li>
<ul>
<li>prioritise</li>
<li>assign to people</li>
<ul>
<li>all the consequences of assigning a task (emails, notifications)</li>
</ul>
<li>complete the task</li>
</ul>
</ul>
<div>
<br /></div>
<div>
Consequently, you're NOT focusing on:</div>
<div>
<br /></div>
<div>
<ul>
<li>how the people are imported to the system (do they need to register? are they imported?)</li>
<li>how the projects are created</li>
<ul>
<li>it's not a common task to start projects</li>
</ul>
<li>authentication</li>
<li>persistence</li>
</ul>
<div>
You try to <b>focus on the actions that are in everyday use of this project</b> (potentially).</div>
</div>
<div>
<br /></div>
<div>
<b>What if you really need to use the real data?</b></div>
<div>
<br /></div>
<div>
This obviously depends on the context of the system. Given the above example, you probably have 2 or 3 initial users of the system. Ask them to provide the data in any way they like. It might be Excel, Google Doc, just an email, whatever. You can quickly insert the data to the system, using the console/database.</div>
<div>
<br /></div>
<div>
Thanks to that you will see what kind of data those people *actually* use. Do they have 100 projects or just 3 of them? Do they have 5 employees or 500? This will guide you how to implement the importing, later on.</div>
<div>
<br /></div>
<div>
Most importantly, you don't waste time on implementing the less crucial parts of the app. Most likely, the importing is not your business advantage.</div>
<div>
<br /></div>
<div>
In the first days, you don't even need the proper persistence - focus on manipulating the existing data, but it doesn't need to be persisted (in the first days).</div>
<div>
<br /></div>
<div>
You don't need the proper authentication, yet. Everybody knows you're able to implement authentication, once it's actually the most important part. Focus on the risky parts, not on the ones, you know how to do.</div>
<div>
<br /></div>
<div>
<b>Technical decisions</b></div>
<div>
<br /></div>
<div>
In Rails, we often don't know, what the app is about, but we know it's going to be Rails, Devise, RSpec, Postgres.</div>
<div>
<br /></div>
<div>
In Java, it's the same, Spring + JPA/Hibernate + Oracle, before we know anything here.</div>
<div>
<br /></div>
<div>
If it's a web app, consider starting with the frontend app, but don't go into Angulars/Embers or any other heavy framework. Make it a lightweight HTML + some simple views. They can be jQuery-based or React. You will change it later.</div>
<div>
<br /></div>
<div>
Starting from the middle is not only a prototyping tool. Starting from the middle is a business thinking tool. </div>
<div>
<br /></div>
<div>
What in our app/feature is the most important/risky part?</div>
<div>
<br /></div>
<div>
How can we fake the other parts? How can we defer some of the less important decisions?</div>
<div>
<br /></div>
<div>
<b>Defer</b></div>
<div>
<br /></div>
<div>
BTW, one practical tip - when a software project starts, many people care a lot about many things, especially the technical decisions. You may spend days debating rspec vs minitest or rails-api vs sinatra. Somehow, those are the most important decisions at the beginning. Everything changes after 2-3 months. Suddenly, introducing minitest is not a big deal. It's no longer so important that one part of our app will be React-based and not Angular. It still matters, but the discussions are not so heated. </div>
<div>
Use it to your advantage - suggest deferring decisions "until the next week/month". Try to move the discussion to the core of the requirements, at this stage of work.</div>
<div>
<br /></div>
<div>
Let's say, you're adding an analytical feature to the app. You want to collect a lot of data about the users behaviour and then implement a dashboard which show nice things.</div>
<div>
<br /></div>
<div>
Collecting analytical data is not really risky (maybe the performance part). Focus on what kind of nice things you want to display. What should be highlighted in red? Do we needs some alerts here? You will quickly realise that those things can guide the collecting phase. It will be easier to decide on the ways the collecting needs to be done. Do we need to collect data in batches? How real-time does it need to be?</div>
<div>
<br /></div>
<div>
<b>Detecting actors early</b></div>
<div>
<br /></div>
<div>
What's most important, by focusing on how we want to use the data, we need to <b>start thinking in terms of actors</b>. Who is going to use the data? Do we have access to those people? The earlier we try to find them, the better. We try to localise the places, which are not under our (developers) control. Fix them first. Then you're on your own implementing the stuff that is fully under your control.</div>
<div>
<br /></div>
<div>
Sometimes, it's just a small gain. You start the feature by visualising the data. You send it to the people involved. They can start discussing it (often takes days). Meanwhile, you can work on the persistence or authentication foundations. When they're back with some ideas of changes, you will need to do them, but at least you were not fully blocked.</div>
<div>
<br /></div>
<div>
If you did it the other way round - spending 3 days on persistence/backend/authentication and then implementing the main screen - you would need to wait longer now. This is using concurrency to your advantage.</div>
<div>
<br /></div>
<div>
Another example - you have a working system. Now, it's time to make it a SaaS. You need to make it a multi-tenant app. This is a big deal. This is not a 3 days work. There's lots of things to consider. Starting from the middle would require thinking in terms of already existing data. Don't focus (yet) how to let new companies/tenants to register. Try to turn the existing system into a tenant system, from the middle. Does it mean, we need to assume we already have subdomains? How do we persist/isolate the tenants data? Try to hardcode other tenants data. This will all guide you how to turn the app into a SaaS in a safer way. </div>
<div>
<br /></div>
<div>
<b>Starting from the middle is pivot-friendly</b></div>
<div>
<br /></div>
<div>
If you work in a fast-changing environment there might be situations where a decision to drop the idea appears. You work on a feature X, you spend 1 week on it. Suddenly, the board decides that X is no longer important. We now need Y. If you started from the middle, there's no inconsistent features that you need to disable because they totally don't make sense. Yes, you still need to clean up the code, but at least there's no need to remove the import form, as there was no such thing yet.</div>
<div>
<br /></div>
<div>
I use this technique to blogging. I timebox 30 minutes and I start from the middle. What are the most important messages I want to send? Make them headers. Add 1-2 sentences to explain them. When the time is over, the blogpost is shippable. In fact, it's always shippable. If I have more time, I expand the explanation.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>When to stop working in the middle?</b></div>
<div>
<br /></div>
<div>
Once you have all the unknowns clear - then it's time to go back, to the beginning. We're now totally sure what our app is for. How it solves the users problems. We know the actors. We know the data specifics.</div>
<div>
<br /></div>
<div>
Now it's a good start to implement the missing infrastructure. </div>
<div>
<br /></div>
<div>
In one of my projects, we implemented the whole app as a Single Page App with no backend at all. We collaborated with the actors, the app was tested and validated. Once all the frontend was settled, we knew the data we needed. Implementing the backend took us only 2 days. It was crystal clear. We started with the client needs first, then we knew what we needed. If we started with the backend, we would be guessing about the needs.</div>
<div>
<br /></div>
<div>
This is a lot like TDD, but on a different level.</div>
<div>
<br /></div>
<div>
<b>Gradual migration of persistence</b></div>
<div>
<br /></div>
<div>
Let's say you start with a JavaScript frontend. You show "the middle" screens. You implement the most important actions (frontend-only). This is enough for the basic testing. </div>
<div>
<br /></div>
<div>
Now the users may want to actually "save" the data somehow, so that when they're back the next day, the data is still there.</div>
<div>
<br /></div>
<div>
You can implement it using the local storage. The simplest technique? Just dump all the data graph to the local storage after every change. It's not the proper way, but it solves the *current* problem.</div>
<div>
<br /></div>
<div>
Later on, the users may want to access the data from different devices. You now need to have some backend. You can even follow the same strategy and just dump the data to the backend as a json blob.</div>
<div>
<br /></div>
<div>
The next requirement is usually to be able to collaborate on this data with other users, so they can work on it at the same time. Now it might be time to be more granular with how the data is persisted. You can now extend the API with more endpoints for different actions.</div>
<div>
<br /></div>
<div>
Ultimately, you may need to make the collaboration smoother by pushing the data to the clients using WebSockets.</div>
<div>
<br /></div>
<div>
<b>Code is not a stone</b></div>
<div>
<br /></div>
<div>
Starting from the middle is a great exercise for continuous refactoring. All the code keeps changing and you're not afraid to do so. It becomes a natural habit. Your work become a sequence of small steps, gradual improvements.</div>
<div>
<br /></div>
<div>
<b>Outsourcing less important parts</b></div>
<div>
<b><br /></b></div>
<div>
Starting from the middle teaches about outsourcing some work to other tools or even other teams. Do we even need our own authentication? Is Twitter login enough? Do we need our own persistence? Do we need to implement the import forms? Maybe there's already a tool which the users can use to "click" all their data and then export it to xml? Maybe there are some standards in this industry?</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<b>Optimise for the developer brain</b></div>
</div>
<div>
<b><br /></b></div>
<div>
What I often see is a number of features in the "importing" process. Those are features that may be useful, but only at the beginning of the user lifecycle in the project. However, they complicate the UX forever. You have some checkboxes which make sense to be displayed on each line item, but it's only realistically use in the first days. Even if they're already implemented, I recommend considering to drop them. Code is maintenance cost. Even if the code is not changed that often it brings the mental overhead to load the codebase to the developer brain. </div>
<div>
<br /></div>
<div>
It may sound stupid to optimise the features for the developer brain. However, it's less stupid, when you think that it's the developer who is then able to come up with simpler/faster solutions, thanks to the fact that the whole thing is now simpler.</div>
<div>
<br /></div>
<div>
<b>Summary</b></div>
<div>
<b><br /></b></div>
<div>
Starting from the middle is like a framework of business thinking. It constantly challenges you on the best ways of using your time. </div>
<div>
<br /></div>
<div>
Are you working in the middle now? </div>
Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0tag:blogger.com,1999:blog-7821856652257554779.post-69362950475791131112015-09-17T11:51:00.000+02:002015-09-17T11:51:13.112+02:00DCI, DDD and the concept of rolesAll of the architectural approaches in software engineering aim to solve similar problems. One of the techniques that is often used is the concept of <b>roles</b>.<br />
<br />
When you do OOP, you may use interfaces (especially with statically typed languages). Interfaces help us thinking in roles - in this context this is the role the object plays.<br />
<br />
The DCI architecture is opposing the current class-oriented thinking. They aim to introduce the full OOP which is object based, not so class-based as we're used to now. To simplify things a bit, in DCI you should be able to implement an interface on an object basis, not on the class level.<br />
<br />
For example, if you have an ebook object, you might want to temporarily treat it as "a digital product" in the Shipping context (where it's delivered via email to the customer). Not all ebooks are being delivered at the same time, so there's no point in all of them (at the class level) having the shipping abilities. For the time, when it's important to ship the digital product, the ebook has a new role. When it's used in another context (listed in a catalog?) it doesn't have the role - it doesn't have some methods.<br />
<br />
That's the DCI conceptual way of using roles.<br />
<br />
Now, what is the DDD way?<br />
<br />
In DDD, we use the concept of <b>bounded contexts</b>. They represent the boundaries in which a different language is used. In a way, it's similar to DCI Contexts.<br />
<br />
In DDD, we would have the Catalog context and the Shipping context as well. Similarly we will have the concept of ebook and digital products. They are not called roles, here, though. Also, it's probably more of an implementation detail, but most DDD implementations would have different objects (different identities) for the ebook (as in Catalog) and for the digital product (as in Shipping).<br />
<br />
The ebook and the digital product represent the same thing and very likely they are aggregate roots in their bounded contexts. Keeping them as separate objects (often, with their own separate persistence) requires some synchronisation mechanism. If the ebook title changes, it may need to be changed in all contexts. In DDD, domain events are one way of ensuring the (often eventual) consistency.<br />
<br />
As you see, different kinds of architectures need to solve similar problems. Here, both DDD and DCI use the role-oriented thinking. The implementations are different, though.<br />
<br />
<br />
<br />
<br />Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0tag:blogger.com,1999:blog-7821856652257554779.post-47352116169082066532015-02-18T00:52:00.000+01:002015-02-18T00:52:09.678+01:00Starting my journey with VoltLet me start with a disclaimer that I'm new to the <a href="http://voltframework.com/">Volt</a> framework. I probably get some things wrong. Don't rely on my opinions here :) The reason I'm blogging about it is to document my learning process. Also, by blogging I hope that dear readers will catch my mistakes and correct them in the comments. Thanks to that I'll learn more and can share a better knowledge in the future blog posts :)<br />
<br />
I've played with Volt today. For those of you who don't know - Volt is a Ruby web framework. It's a bit unusual, as it's an isomorphic framework. The code is shared between the server and the client. It works in the browser thanks to the Opal - <span style="background-color: white; font-family: 'Open Sans', HelveticaNeue, sans-serif; font-size: 14px; line-height: 19.600000381469727px;">a ruby to javascript compiler</span> (source to source). In a way, it's similar to Meteor.<br />
<br />
<b>Opal</b><br />
<br />
I'm quite excited about Opal and the way it can influence the Ruby/Rails community. One year ago, I've recorded my suggestion/prediction that Opal can become the default JavaScript implementation in Rails apps. Here's the short (1 minutes) video of me science-fictioning about it, while walking in the forest near my home :)<br />
<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/Z4RJc77Ra8o" width="560"></iframe><br />
<br />
I'm not following the Opal progress very closely, but from seeing what's possible in Volt, I feel quite confident about my last-year prediction.<br />
<br />
I'll focus on Opal in another blog post. For now, let me come back to Volt.<br />
<br />
<b>The wow effect</b><br />
<b><br /></b>
I came to Rails very early, in 2004. It was due to the "wow effect". Being experienced with PHP, Java, ASP.NET it was amazing to see a result produced in such a short amount of time with so short codebase!<br />
<br />
Over time, I learnt a lot about JavaScript frontends. Here is a <a href="http://andrzejonsoftware.blogspot.com/2015/02/from-rails-to-javascript-frontends.html">12-blog-posts summary of my lessons</a>. I know what it takes to develop a nice Single Page Application (or however you prefer to call it).<br />
<br />
This is the Volt wow effect. I'm old enough not be excited too easily with new shiny toys, but Volt does impress me. In almost no time, you've got a rich frontend, which works as you'd expect from a good JavaScript application - fast, interactive. You get the backend basically for free. It all autosyncs with the backend without any effort from your side. What's more, a new Volt app comes with authentication built-in for free.<br />
<br />
Part of the wow effect is the fact that you don't need to run any database migrations to add new fields. It all relies on Mongo under the hood, so it's schema-less.<br />
<br />
One of my roles is to be a Ruby/Rails <a href="http://andrzejonsoftware.blogspot.com/2013/10/what-im-teaching-at-my-rails-class.html">teacher</a> / <a href="http://blog.arkency.com/coaching/">coach</a> and I know how important it is to have a great "wow effect" for the students.<br />
<br />
<b>The developer happiness</b><br />
<b><br /></b>
Another thing that brought me to Rails was its developer oriented approach. The small things like console, like migrations (at that time it was huge), like seeing everything immediately on the screen without restarting the server. It was all there. It was all prepared to be very productive for the developer.<br />
<br />
Volt is the same. There's lots of details that work very well. It's hard to mention them all. For me, it was great to see the browser with live reload out of the box. I change some Ruby code and it immediately pushes the code to the browser and the page is reloaded. I know there are more tools like that, but seeing it work with Ruby in the tool chain is just great.<br />
<br />
<b>The documentation</b><br />
<b><br /></b>
I followed the <a href="http://voltframework.com/docs">tutorial</a> (try it, you'll get a better picture of it in 15 minutes, than from reading this post ;) ) and browsed through the documentation. All very precise, very simple. I didn't find any inconsistency with the actual behaviour.<br />
<br />
<b>The codebase</b><br />
<b><br /></b>
I only scanned some parts of the code and it seems like very well written code. I was curious how the "reactive DOM" thing works here. It was easy to find <a href="https://github.com/voltrb/volt/blob/d5b1a07ac8fd57756462cf88256dd0f13bbb7da7/lib/volt/reactive/computation.rb">the right piece of code</a> and understand how the "watching" works. When I browse the Rails codebase, I often feel lost as it depends on a lot of metaprogramming. I didn't feel the same here (yet).<br />
<br />
BTW, yesterday I tried to run Opal with ReactJS but couldn't make it. There's probably no reason, why it wouldn't work, though, given more time. If you know anyone who did that successfully, I'd love to see the result :)<br />
<br />
<b>Components</b><br />
<br />
I'm not experienced enough to see all the details, but I love the focus on components, from the beginning. Often, in Rails apps we think that some pieces may be extracted as an engine/component/module/gem *one day* and it rarely happens. Here, we're encouraged to do it from the beginning. The Volt components can be packaged as gems, which is quite interesting.<br />
<br />
<b>The architecture of a Volt app</b><br />
<b><br /></b>
As much as I'm impressed by Volt being a great framework for scaffolding/prototyping (maybe even better than Rails one day?), I also have some doubts.<br />
A lot of my work in the last years was about decoupling legacy Rails applications. I wrote <a href="http://rails-refactoring.com/">a book about Refactoring Rails apps</a> and I keep collecting techniques which make it easier. Coupling is bad.<br />
<br />
Is sharing the code between server and client a coupling? The answer to this question will be very important for me.<br />
<br />
In a way, good decoupling may result in great reusability. There are applications, where the server role is simply to keep the data and to ensure basic authentication/authorisation rules. There are however also apps, where the server logic is much different from the client applications.<br />
<br />
Is reusability the goal in itself? I don't think so. It's more of a nice side effect of good separation of concerns.<br />
<br />
What's the Volt model of code reuse? At the moment, I'm not really prepared to answer this question easily. It seems to be, that at any moment, you can easily switch off the coupling, when required. That's a good sign. It's all Ruby under the hood, so we can do what we want.<br />
<br />
<b>Community</b><br />
<b><br /></b>
In case of frameworks, it's not always their authors vision, which drives how the apps are created. There's many good things in the Rails framework. Rails itself (nor the Rails core team) doesn't force you to write monolithic application - yet, that's what many people do. The main Volt author (Ryan Stout) seems to be very modularity-oriented. From what I see in the Gitter activities, this vision is shared by the early adopters. That's a good sign.<br />
<br />
<b>The future?</b><br />
<br />
<a href="http://blog.arkency.com/">Arkency (my company</a>) became experts in dealing with legacy Rails apps. We know how to decouple the app, step by step, in a safe manner. Are we going to become "legacy Volt apps experts" in 5 years from now? Time will tell... I have positive feelings about it. It's great to see new players in the Ruby community. There's no way it will become more popular than Rails, however competition is good. Volt is so different from Rails, that the Merb-case is not vere likely here ;)<br />
<br />
I'm not recommending starting serious apps with Volt (yet). However, the framework is mature enough to be tried. In only 15 minutes you can build the Todo app from the <a href="http://voltframework.com/docs">tutorial</a>. At least it will show you how the process of working can look, in the future and how different it is from your everyday flow.<br />
<br />
As for me, I'm off to start another side-project with Volt now. <a href="https://twitter.com/andrzejkrzywda">Follow me on Twitter</a> to see how it goes :)<br />
<br />
<br />
<br />
<br />Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com2tag:blogger.com,1999:blog-7821856652257554779.post-70719640524972416362015-02-11T02:56:00.000+01:002015-02-11T02:56:08.447+01:00From Rails to JavaScript frontendsI've collected a number of my blog posts, which together may help you in the transition from Rails to JavaScript (or CoffeeScript) frontends. Many of the posts are about the mental transition you need to make along the way, while other posts are more technical.<br />
<br />
I think it's best to read them in the order I put it here, as they present the road I took over the last 5 years.<br />
<br />
1. <a href="http://andrzejonsoftware.blogspot.com/2011/09/rails-is-not-mvc.html">Rails is not MVC</a><br />
<br />
2. <a href="http://andrzejonsoftware.blogspot.com/2012/06/frontend-is-separate-application.html">Frontend is a separate application</a><br />
<br />
3. <a href="http://andrzejonsoftware.blogspot.com/2012/06/from-backend-to-frontend-mental.html">From backend to frontend, a mental transition</a><br />
<br />
4. <a href="http://andrzejonsoftware.blogspot.com/2012/08/is-coffeescript-better-than-ruby.html">Is CoffeeScript better than Ruby?</a><br />
<br />
5. <a href="http://andrzejonsoftware.blogspot.com/2012/07/js-frontends-are-like-desktop-apps.html">JavaScript frontends are like desktop applications</a><br />
<br />
6. <a href="http://andrzejonsoftware.blogspot.com/2013/02/frontend-first.html">Frontend first</a><br />
<br />
7. <a href="http://andrzejonsoftware.blogspot.com/2013/02/non-framework-approach-to-javascript.html">Non-framework approach to JavaScript applications</a><br />
<br />
8. <a href="http://andrzejonsoftware.blogspot.com/2013/02/angular-or-ember-congratulations-youve.html">Angular or Ember? Congratulations, you've already won</a><br />
<br />
9. <a href="http://andrzejonsoftware.blogspot.com/2013/04/single-page-applications-fight-video.html">Single Page Applications - fight</a><br />
<br />
10. <a href="http://andrzejonsoftware.blogspot.com/2013/12/turn-rails-controller-into-single-page.html">Turn a Rails controller into a Single Page Application</a><br />
<br />
11. <a href="http://andrzejonsoftware.blogspot.com/2013/12/how-can-rails-react-to-rise-of.html">How can Rails react to the rise of JavaScript frameworks?</a><br />
<br />
12. <a href="http://andrzejonsoftware.blogspot.com/2015/02/which-javascript-framework-should-i-use.html">Which JavaScript framework should I choose? (video)</a><br />
<br />
If you enjoyed reading the blog posts, you may consider <a href="https://twitter.com/andrzejkrzywda">following me on Twitter</a>.<br />
<br />
<br />
<br />Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0tag:blogger.com,1999:blog-7821856652257554779.post-69585458707263599622015-02-11T02:43:00.001+01:002015-02-11T02:43:14.901+01:00Which JavaScript framework should I use? (video)Over the last 4-5 years, I keep being asked this question - Which JavaScript framework should I use?<br />
<br />
2.5 years ago, I had a talk at the RuPy conference, where I'm trying to answer this question. I realised, I've never posted the video to my blog. 2.5 years is like a century in the IT world. Everything has changed, right? I believe that my answer is still correct and all what I said is still true.<br />
<br />
Enjoy the 30 minutes of my lecture :)<br />
<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="380" src="https://www.youtube.com/embed/ENVPZ-UoQsg" width="550"></iframe>Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0tag:blogger.com,1999:blog-7821856652257554779.post-80708180680992426972015-02-03T17:21:00.000+01:002015-02-04T17:48:06.536+01:00Splitting a Rails controller<br />
Splitting a controller into separate files may be a good idea in certain cases.<br />
<br />
Let me start with the cases, when it's NOT a good idea. In case of a simple CRUD controller, this may be an overkill. The same applies to simple, scaffold-like controllers. <br />
<br />
Some controllers are more resource-oriented - those may benefit from keeping the actions together in one file. People often use filters for reusing certain rules of accessing the resources here.<br />
<br />
Other controllers may be more action-oriented (as opposed to resource-oriented). It's typical for the your-main-model-controllers. In those controllers, you will see more than the standard actions. They will contain interesting logic for 'update', 'create', 'destroy'. Those actions may have different logic. Often, they don't share that much.<br />
<br />
The action-oriented controllers may benefit from splitting them into several files. I call them SingleActionControllers.<br />
<br />
Please, note that the action-oriented controllers can contain a more complicated set of rules in the controller filters. Often, they create a full algebra of filters, where you need to find your way through the :except clauses and dependencies between filters. Refactoring those places requires a really precise way of working.<br />
<br />
Apart from the filters problem, extracting a SingleActionController is easy and consists of the following steps:<br />
<br />
<br />
1. A new route declaration above the previous (first wins)<br />
<div class="CodeRay">
<div class="code">
<pre>post <span style="background-color: hsla(0,100%,50%,0.05);"><span style="color: #771100;">'</span><span style="color: #dd2200;">products</span><span style="color: #771100;">'</span></span> => <span style="background-color: hsla(0,100%,50%,0.05);"><span style="color: #771100;">'</span><span style="color: #dd2200;">create_product#create</span><span style="color: #771100;">'</span></span> </pre>
<pre>resources <span style="color: #aa6600;">:products</span>, <span style="color: #660066;">except</span>: [<span style="color: #aa6600;">:create</span>]
</pre>
</div>
</div>
<br />
2. Create an empty controller CreateProductController which inherits from the previous<br />
3. Copy the action content to the new controller<br />
4. Remove the action from the previous controller<br />
5. Copy the filters/methods that are used by the action to the new controller<br />
6. Make the new controller inherit from the ApplicationController<br />
7. Change routes to add 'except: [:foo_action]'<br />
<br />
You can also see a simple example of this refactoring here:<br />
<br />
<a href="http://rails-refactoring.com/recipes/extract-single-action-controller-class/">http://rails-refactoring.com/recipes/extract-single-action-controller-class/</a><br />
<br />
<br />
<br />Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com2tag:blogger.com,1999:blog-7821856652257554779.post-51711405031457955912015-02-03T16:15:00.000+01:002015-02-05T02:32:41.437+01:00TDDing a unit, not a classSome time ago, I blogged about <a href="http://blog.arkency.com/2014/09/unit-tests-vs-class-tests/">"Unit tests vs Class tests"</a>, where I described how it differs when you think of a unit more as a collection of classes instead of a single class.<br />
<div>
<br /></div>
<div>
<b>How can we TDD such a unit?</b></div>
<div>
<br /></div>
<div>
This <a href="http://www.reddit.com/r/rails/comments/2tofoh/how_does_one_ttd_a_user_and_session_model/">reddit thread</a> triggered me to explain it a bit more. The title of the thread was interesting: "How does one TDD a user and session model?"</div>
<div>
<br /></div>
<div>
Such question is a good example, how the class tests seem to be the default in the "unit testing" thinking. Instead of asking how to TDD the Authentication unit, we're asked how to TDD some single classes - which often depend on each other.</div>
<div>
<br /></div>
<div>
Here is my response:<br />
<br />
One way to do it is to think one level higher. Don't focus on the User and Session classes, but focus on the whole feature/module that you're building. In this case, that's probably Authentication, right?<br />
<br />
Think of Authentication as a class, which is a facade. It's very likely, that you will come up with User and Session classes, sooner or later. They will be more like implementation details.<br />
<br />
You probably need to implement functions like:</div>
<div>
<ul>
<li><i>register</i></li>
<li><i>logging in</i></li>
<li><i>logging out</i></li>
<li><i>change_password</i></li>
<li><i>change_email</i></li>
<li><i>change_login</i></li>
<li><i>remember_me</i></li>
<li><i>delete_user</i></li>
</ul>
<br />
Together they can make nice stories. You can start with a simple test like:</div>
<div class="CodeRay">
<div class="code">
<pre><span style="color: #008800; font-weight: bold;">def</span> <span style="color: #0066bb; font-weight: bold;">test_wrong_credentials_dont_authenticate</span>
authentication = <span style="color: #003366; font-weight: bold;">Authentication</span>.new
authentication.register_user(<span style="background-color: hsla(0,100%,50%,0.05);"><span style="color: #771100;">"</span><span style="color: #dd2200;">user</span><span style="color: #771100;">"</span></span>, <span style="background-color: hsla(0,100%,50%,0.05);"><span style="color: #771100;">"</span><span style="color: #dd2200;">password</span><span style="color: #771100;">"</span></span>)
assert_raises(<span style="color: #003366; font-weight: bold;">WrongCredentials</span>) { authentication.authenticate(<span style="background-color: hsla(0,100%,50%,0.05);"><span style="color: #771100;">"</span><span style="color: #dd2200;">user</span><span style="color: #771100;">"</span></span>, <span style="background-color: hsla(0,100%,50%,0.05);"><span style="color: #771100;">"</span><span style="color: #dd2200;">wrong password</span><span style="color: #771100;">"</span></span>) }
<span style="color: #008800; font-weight: bold;">end</span>
</pre>
</div>
</div>
<div>
<br />
<br />
(if you don't like exceptions, you can turn it into returning true/false instead)<br />
<br />
One by one, you could build the whole feature this way, while being test-driven all the time.<br />
<br />
In a Rails app, you will then use this Authentication object from the Rails controllers. This is also a good way of <a href="http://rails-refactoring.com/">improving Rails controllers</a>.<br />
<br />
<b>This approach is sometimes called top-down</b>. You start with the expectation from the higher module (Authentication) and this drives you to implement the lower-level classes like User and Session.<br />
<br />
Another approach is called bottom-up, where you start with the User and Session classes from the beginning and don't worry with the wrapping module, yet.<br />
<br />
The different approaches may result in different tests. <b>With the top-down approach you end up with module tests, while with bottom-up most likely you end up with a test per class.</b></div>
Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com1tag:blogger.com,1999:blog-7821856652257554779.post-54734741682646007202015-01-04T23:56:00.001+01:002015-01-04T23:56:09.645+01:00Ruby and instance_variable_get - when it's useful?When working on my book about <a href="http://rails-refactoring.com/">refactoring Rails controllers</a>, I've collected a number of "unusual" Rails solutions from real-world projects. They were either sent to me from the readers or I found them in some open-source Rails projects.<br />
<br />
One of them was the idea of using <b>instance_variable_get</b>.<br />
<br />
<b>instance_variable_get in the Redmine project</b><br />
<br />
I was working on one of the most important recipes from my book - <b>"Explicitly render views with locals"</b>. It's important, as it opens the door to many other recipes - it makes them much simpler.<br />
<br />
When I was practising this recipe, I tried to use it in many different projects. One of the open-source ones was Redmine. I applied this refactoring to one of the Redmine actions. I've searched through the view to find all @ivars and replaced them with an explicit object reference (passed to the view through the locals collection). This time it didn't work. The tests (Redmine has really high test coverage) failed.<br />
<br />
The reason was a helper named error_messages_for(*objects). It's used in many Redmine views.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgAMP5yt3jBnKJP48Gz35ZZezbVWpQuHSf4-howPGdcDGQnD3JmDTFZ3nEdUbDKdBsU_MYMpvfscM1qgyhD87VXAgQw1lT0Sz_jE52GWMw91auZ3C54LOUS1PQvPugn4TwzBSADwCtO8Q/s1600/Screenshot+2014-12-30+15.50.37.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgAMP5yt3jBnKJP48Gz35ZZezbVWpQuHSf4-howPGdcDGQnD3JmDTFZ3nEdUbDKdBsU_MYMpvfscM1qgyhD87VXAgQw1lT0Sz_jE52GWMw91auZ3C54LOUS1PQvPugn4TwzBSADwCtO8Q/s1600/Screenshot+2014-12-30+15.50.37.png" height="46" width="400" /></a></div>
<br />
The <a href="https://github.com/redmine/redmine/blob/bfd811304601edbc3c17edc1259a1029c230726d/app/helpers/application_helper.rb#L1027">implementation</a> looks like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0Sj8miB9HXeqw1f2FDuHQ3jEeofCZ7ZG-O1RySnLSuTOWW4plpI7wEijeB9P-0jZTmquGwopabTKD4cmBOR-lD9vDzYSxqAdjB5dMJQhi_apHWLNO6l-hYk7-E61dhZYlU3HMinxlyxc/s1600/Screenshot+2014-12-30+15.47.21.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0Sj8miB9HXeqw1f2FDuHQ3jEeofCZ7ZG-O1RySnLSuTOWW4plpI7wEijeB9P-0jZTmquGwopabTKD4cmBOR-lD9vDzYSxqAdjB5dMJQhi_apHWLNO6l-hYk7-E61dhZYlU3HMinxlyxc/s1600/Screenshot+2014-12-30+15.47.21.png" height="147" width="400" /></a></div>
<br />
The idea behind this is to display error messages for multiple @ivars in a view. As you see, it uses the instance_variable_get calls to retrieve the @ivar from the current context. It's only used in cases, when a string is passed and not an @ivar directly.<br />
<br />
This situation taught me 3 lessons.<br />
<br />
1. I need to test my recipes in as many projects as possible to discover such edge cases.<br />
2. A high test coverage gives a very comfortable situation to experiment with refactorings.<br />
3. Ruby developers are only limited by imagination. The language doesn't impose any constraints. It's both good and bad.<br />
<br />
I've extended the recipe chapter with a warning about the instance_variable_get usage:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9tZKpUkDguryEO8ArcMblOwWHl8eetcYmPBPgwwLwFOnehWUaIyk9dAEJpxlS_EvOytbVgxijfKFSkkPtucvh4XsW9p3rInw0aIOY6zhVQLnNoY9GaQ2xqEhR01CbojgApzMFxl-eub4/s1600/Screenshot+2014-12-30+15.47.38.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9tZKpUkDguryEO8ArcMblOwWHl8eetcYmPBPgwwLwFOnehWUaIyk9dAEJpxlS_EvOytbVgxijfKFSkkPtucvh4XsW9p3rInw0aIOY6zhVQLnNoY9GaQ2xqEhR01CbojgApzMFxl-eub4/s1600/Screenshot+2014-12-30+15.47.38.png" height="231" width="400" /></a></div>
<br />
<b>The lifecycle of a Rails controller</b><br />
<br />
After some time, I was working on another chapter called "Rails controller - the lifecycle". In that chapter I describe step by step what is happening when a request is made, starting from the routes, ending with rendering the view. Each step is associated with a snippet of the Rails code.<br />
<br />
Everybody knows that if you have assign an @ivar in a controller, it's automatically available as an @ivar in the view object, even though they are different objects.<br />
<br />
The trick here is that the Rails code uses instance_variable_get as well. It grabs all the instance variables and creates their equivalents in the view object using the instance_variable_set. Here is part of the chapter:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvCz-2aTJmtutV1op003y1unDceNTqnDzOOZVJtOAR3ufaec7Krsd2nuwq6I_PaGBFNqsgVu2NA8MmwwXNDmCMz7ODgGkFirVm1-yk6e-iTiTK_pXfaK2KxG3TyL07TRNymBIiPBnKdO8/s1600/Screenshot+2014-12-30+16.10.47.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjvCz-2aTJmtutV1op003y1unDceNTqnDzOOZVJtOAR3ufaec7Krsd2nuwq6I_PaGBFNqsgVu2NA8MmwwXNDmCMz7ODgGkFirVm1-yk6e-iTiTK_pXfaK2KxG3TyL07TRNymBIiPBnKdO8/s1600/Screenshot+2014-12-30+16.10.47.png" height="400" width="352" /></a></div>
<br />
<b>Easier debugging in rubygems code</b><br />
<b><br /></b>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEQcuzQ2SEMa5uugqkqmnR8sTsNIFIPklE9j6XmyKs-x8Fz9T_TJ1Yr2X5jCvy7Aai3e-PhOln8Zvp6xPi3tKr1R4nBmmnihVPsNGa-03IMROOas_eXaui3nTZCkR7cPQdu18lfFWZg9g/s1600/Screenshot+2015-01-04+23.47.01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEQcuzQ2SEMa5uugqkqmnR8sTsNIFIPklE9j6XmyKs-x8Fz9T_TJ1Yr2X5jCvy7Aai3e-PhOln8Zvp6xPi3tKr1R4nBmmnihVPsNGa-03IMROOas_eXaui3nTZCkR7cPQdu18lfFWZg9g/s1600/Screenshot+2015-01-04+23.47.01.png" height="50" width="400" /></a></div>
<b><br /></b>
In the rubygems code you will find this <a href="https://github.com/rubygems/rubygems.org/blob/master/app/models/pusher.rb#L94-L98">piece of code</a>. It's a way of displaying the current state (@ivars) of the object. At first, it may look useful. I'm sure it served well for this purpose. However, the root problem here is not how to display the state. The root problem is that the state is so big here that it needs a little bit of meta programming to retrieve it easily. Solving the root problem (splitting it into more classes?) would probably reduce the need for such tricks.<br />
<b><br /></b>
<b>When it's useful?</b><br />
<br />
instance_variable_get is a way of bypassing the object encapsulation. There's a good reason that in Ruby we hide some state using @ivars. Such a hidden state may or may not be exposed in some way. I'd compare instance_variable tricks to using the "send" method.<br />
<br />
My rule of thumb is that it's sometimes useful when you build a framework-like code. Code that will be used by other people via some kind of DSL. Rails is such an example. I'm not a big fan of copying the @ivars to the view, but I admit it plays some role in attracting new people to Rails.<br />
<br />
However, it's a rare case, that instance_variable_get may be a good idea to use in your typical application.<br />
<br />
The temptation to use it is often related to reducing the amount of code. That's a similar temptation to using the "send"-based tricks. I'm guilty of that in several cases. I learnt my lessons here. It might have been "clever" for me, but it was painful for others to understand. It's rarely worth the confusion.<br />
<br />
I've seen enough legacy Rails projects to know, that sometimes the instance_variable_set trick is useful in tests. It's still "cheating", but it may be a good temporary step to get the project on the right path. Some modules/objects may be hard to test in isolation in a legacy context. Sometimes, we may need to take an object (like a controller) and set some of its state via instance_variable_set at the beginning of the test. It's similar to stubbing. This way we may be able to build a better test coverage. Test coverage on its own doesn't mean anything. However, good test coverage enables us to refactor the code, so that it no longer needs meta programming tricks.<br />
<br />
When in doubt, don't use instance_variable_get.Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0tag:blogger.com,1999:blog-7821856652257554779.post-23622225838244525482014-12-28T19:52:00.000+01:002014-12-29T11:22:35.136+01:00How to write a Ruby-related book - the toolsI have recently published the 1.0 release of the <a href="http://rails-refactoring.com/">"Rails Refactoring: Rails Controllers" book</a>. It took me over 1 year since I started. Over the time, I've experimented with many tools which helped me along the way.<br />
<br />
This post is a summary of some of the tools.<br />
<br />
<b>The short version</b><br />
<br />
<a href="http://www.iawriter.com/mac/">iaWriter</a> for the initial writing<br />
vim/sublime for editing<br />
<a href="https://leanpub.com/">LeanPub</a> for PDF/epub/mobi generation<br />
Github for storing the source files (markdown)<br />
<a href="https://getdpd.com/">DPD</a> for selling<br />
<a href="http://mailchimp.com/">MailChimp</a> for email list<br />
Trello for task management<br />
<br />
<b>The longer version</b><br />
<b><br /></b>
After I knew what to write about (the process how I came up with the "idea" is another topic - let me know if you're interested in reading about it) - I've had a bunch of notes, scattered across many tools - Evernote, Hackpad, MindNode, code repositories.<br />
<br />
Despite all the temptations, I didn't try to find the best tool for writing. I know myself and that would result in endless experiments without any delivery. Obviously, there was a temptation to write such tools on my own. I'm very happy I didn't go this way.<br />
<br />
The minimal requirements was to have a tool that generates a PDF.<br />
<br />
<b>Kitabu</b><br />
<br />
The first tool that seemed to be good enough was <a href="https://github.com/fnando/kitabu">kitabu</a>. It was a good tool - think Rails but for books, a whole framework.<br />
They even give you the familiar "<span style="background-color: #f7f7f7; color: #333333; font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; font-size: 14px; line-height: 1.45;">$ kitabu new mybook"</span> tool.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKQ_VLH8JL4coB_rs51yL0pFZOkUfNjZD_gjPYwUenz1I7ZENxkYZv_BpOUE7APGAP2wIgj4TWsok5HUCj3tMJ_SSWFRtso3O08bUqtdusXBnGeHDLECCegQEyuSha_653_d1Xv4gP324/s1600/Screenshot+2014-12-28+19.13.05.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKQ_VLH8JL4coB_rs51yL0pFZOkUfNjZD_gjPYwUenz1I7ZENxkYZv_BpOUE7APGAP2wIgj4TWsok5HUCj3tMJ_SSWFRtso3O08bUqtdusXBnGeHDLECCegQEyuSha_653_d1Xv4gP324/s1600/Screenshot+2014-12-28+19.13.05.png" height="279" width="320" /></a></div>
<br />
<br />
Kitabu was a very programmer-friendly approach.<br />
<br />
I eventually gave up on Kitabu. The problem was with the commercial PDF tool (PrinceXML) which is used by default. I was OK with paying for good software, but at that time, the license was about $2,000 which was a bit too high.<br />
<br />
<b>Scrivener</b><br />
<br />
Then I switched to <a href="http://www.literatureandlatte.com/scrivener.php">Scrivener</a>. I loved this tool. I found it through some "real" writers forum. It's very popular among writers. It's a desktop app. It's great for notes collection, structuring, drafting. It's good at WYSIWYG. It has a built-in PDF generation. It supports export/import from markdown.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsrOflalxe8NCDevzRGkunfUkuGroPpHJ6alYbVim_Oj-cBYCKpg30MShziq9M0NvBayxE80VYEPncTx_h5FGqGTcQj0tZTneX9mHcF2tNsrWoZJ5ESb91P2MPGiai9S33XnCxI211FZg/s1600/Screenshot+2014-12-28+19.12.02.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsrOflalxe8NCDevzRGkunfUkuGroPpHJ6alYbVim_Oj-cBYCKpg30MShziq9M0NvBayxE80VYEPncTx_h5FGqGTcQj0tZTneX9mHcF2tNsrWoZJ5ESb91P2MPGiai9S33XnCxI211FZg/s1600/Screenshot+2014-12-28+19.12.02.png" height="216" width="320" /></a></div>
<br />
<br />
At some point, more people from my team started to help mi with the book. The Scrivener approach wasn't very team-friendly (or I wasn't able to use it). No easy way of two-way sync with markdown. Other people would have to be forced to use Scrivener as well. Also, it wasn't very version-control-friendly.<br />
<br />
<b>Leanpub</b><br />
<b><br /></b>
Meanwhile, Robert Pankowecki (with a little bit of my help) was working on the <a href="http://blog.arkency.com/developers-oriented-project-management/">Developers Oriented Project Management</a> book. He used Leanpub and this tool was very team-friendly. There was a repo, we could all contribute into. It generates PDF/mobi/epub (on their servers) via a Github hook.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFeaJpu77TP9ytp5dNJrURfu3EVVZr52kuA0QPt-Z40Vo5_goFArxduAgbGsvWGsIu9Y9CZfwnKigCBHOyPYn76ZANHxCINXDll6Ndu0oCqngtjChE9RAHUg5wv9Qt7KUBRGWwKHTzFJg/s1600/Screenshot+2014-12-28+19.08.20.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiFeaJpu77TP9ytp5dNJrURfu3EVVZr52kuA0QPt-Z40Vo5_goFArxduAgbGsvWGsIu9Y9CZfwnKigCBHOyPYn76ZANHxCINXDll6Ndu0oCqngtjChE9RAHUg5wv9Qt7KUBRGWwKHTzFJg/s1600/Screenshot+2014-12-28+19.08.20.png" height="204" width="320" /></a></div>
<br />
The Github repo:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRtKt3q8yBIVb_dMuu14ksAxFSQCirxeoQu35n5UybIY9j23wS7QwvHuuMEkUQ8v_3tkVQtidbTJFZ2x6GrNGZhLMNGwlSN13vAtvNVhIJI612nevvL_zM_gA-VszIh0tp-t59HVYaKmo/s1600/Screenshot+2014-12-28+19.22.49.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRtKt3q8yBIVb_dMuu14ksAxFSQCirxeoQu35n5UybIY9j23wS7QwvHuuMEkUQ8v_3tkVQtidbTJFZ2x6GrNGZhLMNGwlSN13vAtvNVhIJI612nevvL_zM_gA-VszIh0tp-t59HVYaKmo/s1600/Screenshot+2014-12-28+19.22.49.png" height="57" width="400" /></a></div>
<br />
(as you see there were 300 commits so far and 13 people contributed to the book!)<br />
<br />
I was sceptical at first, as they (at least at that time) didn't give emails from the book readers. I found it very limiting for marketing/sales activities. However, LeanPub lets you generate the PDF and take the files with you to sell somewhere else. That sounded perfect to us.<br />
Over the last year, I've seen how Leanpub (the UI) keeps getting better. I may seriously consider switching to them as the selling tool as well at some point. They now also have an iOS app for reading your books.<br />
So far, we're staying with Leanpub for our books (the third one is in progress).<br />
<br />
My book is very code-heavy. LeanPub is great for it. They not only support syntax highlighting but they also let us present nicely the diff between two pieces of code.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT23z1vHu22IIEqTkANmE49rHh_BKYmGRdwpWCSjmgc7O85ZieUUyJWtlQa3GdB_nYTvGV8_Ho9f0b3Mst1eIWIlOInslh1t0R2BYwNzU3W1gdnn9qAYAd3EJLDZeAMF5uJbYyod88CmY/s1600/Screenshot+2014-12-28+19.10.53.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjT23z1vHu22IIEqTkANmE49rHh_BKYmGRdwpWCSjmgc7O85ZieUUyJWtlQa3GdB_nYTvGV8_Ho9f0b3Mst1eIWIlOInslh1t0R2BYwNzU3W1gdnn9qAYAd3EJLDZeAMF5uJbYyod88CmY/s1600/Screenshot+2014-12-28+19.10.53.png" height="218" width="400" /></a></div>
<br />
<br />
One minor issue with Leanpub is that you need to wait for the PDF generation (30-60 seconds). I usually work locally, do frequent commits to the local repo. Every now and then I push to the github repo. This triggers a hook, which notifies Leanpub. After a while, I launch a simple bash script - download_and_preview.sh - which downloads the newest PDF and opens Preview on my Mac (if it's already open then it reloads the file). This is a good-enough flow.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirlJ2MraOUctnVQAurCfXnAj3Px_7z5mZWONjIJRa6XP-1fUEJiZ8cYjoKBb79xBP4cql_Zm5OT87hOho1OU_G0PHBJt_jXBER9E4XbGriUc6VkliENZDh6D71F1EtK1Js6AmFLHlPzFY/s1600/Screenshot+2014-12-28+19.14.32.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirlJ2MraOUctnVQAurCfXnAj3Px_7z5mZWONjIJRa6XP-1fUEJiZ8cYjoKBb79xBP4cql_Zm5OT87hOho1OU_G0PHBJt_jXBER9E4XbGriUc6VkliENZDh6D71F1EtK1Js6AmFLHlPzFY/s1600/Screenshot+2014-12-28+19.14.32.png" height="35" width="400" /></a></div>
<br />
<br />
<br />
<b>iaWriter</b><br />
<br />
Leanpub lets me write in MarkDown. For some time, I've used vim for that. After a while, I realized that there are two aspects of writing. When I write the initial version of a chapter I need a full focus to let the flow work. <a href="http://www.iawriter.com/mac/">iaWriter</a> is a perfect tool for distraction-free writing, with a beautiful full-screen mode. This is where I do most of my initial writing.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlf0VDcQdaw2iDeljSscTwZOoxrqU9ZJBQz-_GUj4FsccZBGGlg2IeTWVChM6Snxb_J-Scu-s9fvWiMjrF_yV3VZBTH5GFFd80osFQ08lRlVqvq6qvdVtX8coVjGYAh23EnGCXiU0nXVU/s1600/Screenshot+2014-12-28+19.06.42.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlf0VDcQdaw2iDeljSscTwZOoxrqU9ZJBQz-_GUj4FsccZBGGlg2IeTWVChM6Snxb_J-Scu-s9fvWiMjrF_yV3VZBTH5GFFd80osFQ08lRlVqvq6qvdVtX8coVjGYAh23EnGCXiU0nXVU/s1600/Screenshot+2014-12-28+19.06.42.png" height="317" width="400" /></a></div>
<br />
<br />
When the draft of the chapter is ready, I need to do more editing (it's like refactoring but for normal text). This is when I usually launch either vim or sublime. The vim shortcuts lets me do editing faster.<br />
<br />
When I'm done and ready for a new release of the book, I run the 'release' script:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjh_f8Y834nINWbIeT5RV4XDXTwi10d4DBFLg1TdAEwIvevnjuMzhavUjGQymr0Xl-EGsIMUoefO9A_hIbKcb0zKMDMtCA_xvF6JWvvJw0QKetEmZM-SKBrT4Z23ypEUktuOfm-Qaxk3bA/s1600/Screenshot+2014-12-28+19.16.42.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjh_f8Y834nINWbIeT5RV4XDXTwi10d4DBFLg1TdAEwIvevnjuMzhavUjGQymr0Xl-EGsIMUoefO9A_hIbKcb0zKMDMtCA_xvF6JWvvJw0QKetEmZM-SKBrT4Z23ypEUktuOfm-Qaxk3bA/s1600/Screenshot+2014-12-28+19.16.42.png" height="68" width="400" /></a></div>
<br />
This created a capistrano-like directory and creates a new .zip file.<br />
<br />
<b>DPD</b><br />
<b><br /></b>
I use the <a href="https://getdpd.com/">DPD</a> system for selling. Unfortunately, they don't have the API to automatically upload a new .zip file and manually change the product configuration. I hate this part, as it's very error-prone. I even attached the wrong file to the wrong product once.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjINZYJQS6zZomNf1KU3AwSpJj4tasBSnrCKNaFgrYSkW7TwD9WDEc8PLJwnOfs5Xlghedpwetu2pWEFbp8M5N7cv-Zy4tL1ceprvTAZ1NwaBjGJ0jASL6qAy0Y3mzxyEzseQ6jxzWkLIs/s1600/Screenshot+2014-12-28+19.21.24.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjINZYJQS6zZomNf1KU3AwSpJj4tasBSnrCKNaFgrYSkW7TwD9WDEc8PLJwnOfs5Xlghedpwetu2pWEFbp8M5N7cv-Zy4tL1ceprvTAZ1NwaBjGJ0jASL6qAy0Y3mzxyEzseQ6jxzWkLIs/s1600/Screenshot+2014-12-28+19.21.24.png" height="72" width="400" /></a></div>
<br />
As for payments, DPD only supports PayPal (at least for a Polish company, last time we checked), so this is what I went with. I'm not a big fan of PayPal, but it didn't seem to be a huge problem for all the buyers.<br />
<br />
Whenever I have a new release, I can send an email from the DPD panel to all the customers, which automatically generates the appropriate download URL.<br />
<br />
As you may expect, DPD gives you all the reporting, charts, data which you may need.<br />
<br />
<b>Slack</b><br />
<b><br /></b>
Over the time, we've created notifications around the whole process. Whenever a new commit is pushed into the repo, a new notification appears on a special Slack channel. Whenever a new sale is made, we have a SalesPanda bot which notifies us about it to the same channel.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1XMZytzUqctWEzjFkkfvs4ZnjVo_SqWdCHgBz1S2QwRRLmWVhImT3aTsdb6aAz9g-c9g-r0uXtScSC6UAlpnRxIHiDqc4KjHsUARRB4YfegOXKR1MrSdD44fh0cJtNBq-j28frODOPGk/s1600/Screenshot+2014-12-28+19.48.53.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1XMZytzUqctWEzjFkkfvs4ZnjVo_SqWdCHgBz1S2QwRRLmWVhImT3aTsdb6aAz9g-c9g-r0uXtScSC6UAlpnRxIHiDqc4KjHsUARRB4YfegOXKR1MrSdD44fh0cJtNBq-j28frODOPGk/s1600/Screenshot+2014-12-28+19.48.53.png" height="87" width="400" /></a></div>
<br />
<br />
<br />
<b>Summary</b><br />
<b><br /></b>
As you see, the whole process is a combination of multiple tools. In some places, they are integrated automatically, while some places are still manually updated. The perfect setup would be to have a Continuous Delivery and we're very close to such thing here. When the delivery is a PDF, the problem is that you would need to email people on every Delivery. This doesn't sound perfect, though. With this book, I think I've had 4 releases so far and this worked well - starting from February 2014 until now.<br />
<br />
Feel free to email me at andrzejkrzywda@gmail.com if you need any help with writing a book. It might be overwhelming at first.<br />
<br />
The landing page (pure html/css) of the book mentioned in this post is here: <a href="http://rails-refactoring.com/">http://rails-refactoring.com</a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhprsvPuvXvDBqE1ejUXP31_wJT7pofyi9S7ZGs0fMOFhSfPUfY9jywz4smS8Zk8W8A03bNdRP-y6_ORHdG4FuQG_ERCwI3CrS98ZUMjilAhYUDSeJJZQNjvnWpzYxAoD6WqCU_mmjmSwU/s1600/Screenshot+2014-12-28+19.42.11.png" height="277" width="400" /></div>
<br />
<br />
<br />Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com3tag:blogger.com,1999:blog-7821856652257554779.post-62601130733065207522014-12-01T13:05:00.002+01:002015-01-08T19:38:48.715+01:00I'll refactor this laterImagine this...<br />
<br />
You're finishing your current ticket. The project manager keeps pinging you on IM, whether it's finished. This feature is important to a number of users. The business pressure is high. They want you to finish it ASAP.<br />
<br />
<b>"Could you deploy it before the lunch time?"</b> - they beg.<br />
<br />
You made some shortcuts in the code. It was just faster to put the code in the controller. You know how service objects are better, but this time it was just faster.<br />
<br />
<b>"I'll definitely be refactoring this later"</b> - you think.<br />
<br />
Just before the lunch, you push to master, run the deployment script. Everything seems to work. At the lunch, you're thinking how you're going to improve the code - extract the service object, add some more tests to cover the if branch that was added just at the last moment.<br />
<br />
Back at the office. Everybody knows that you finished the previous ticket and the PM is happy. From the team perspective - <b>you're now available for the next task.</b> <br />
<br />
"Could you help me debugging this problem?" - your colleague asks. <br />
<br />
"We need the new reports in the admin panel" - the PM is back to you.<br />
<br />
There's no way you can now fix the code shortcuts, you've made in the morning. You switched the context 3 times since then. <b>There's just no time to do it.</b> Other important things are waiting for you.<br />
<br />
Did you just increase the technical debt? Is it your fault? You hate this kind of situations. You feel guilty.<br />
<br />
Is there a way of avoiding such situations?<br />
<div>
<br />
<b>Can the code be debt-free?</b><br />
<br />
In that story, you didn't manage to fix the code.<br />
How it could have been done better?<br />
<br />
Some people would say that you shouldn't deliver, before the code is great. The task is not finished, before the refactoring is finished.<br />
<br />
<b>"It's unprofessional"</b> - they say.<br />
<br />
There's some truth to that, but it's based on more assumptions.<br />
<br />
"It's OK to have some technical debt, it's a pragmatic approach" - other people say. "Just document the problem somewhere" - they add.<br />
<br />
Have you been in projects, where a special place for documenting the technical debt was created?<br />
<br />
Some add it to the Pivotal/Redmine/wiki. Others try to keep a file in the repo - something like <b>technical_debt.txt</b>.<br />
<br />
It can work, but it requires a huge discipline in the team. I used to be a big fan of this approach. After several approaches to it, now I think it's less realistic.<br />
<br />
What are other options?<br />
<br />
There's this "pragmatic" option to <b>document the problem in the code comment</b>. From what I see in the projects, I'm reviewing this may be the most popular option. I don't like it. I've looked at dozens of such comments, looked at the git repo history - the comments are almost always out of date. They're there and no one ever fixes the problem.<br />
<br />
I really like another option. This practice alone isn't enough, but it's a good middle solution. <br />
<br />
<b>Document the hack in the git commit message.</b><br />
<br />
Just write about the situation, why it was created like that, what were the time constraints. You may try to justify it a bit. You may explain how it can be fixed in the future.<br />
<br />
Those messages are not part of the code, thus they don't make the code less readable. They are meta information, available to everyone, any time they want.<br />
<br />
See a bad code? Just use your IDE to show the git logs for this place.<br />
<br />
Bad code has other bad consequences. As developers, we like to point out the places, where code is wrong. Sometimes, a hack is implemented in 5 minutes (pragmatic), but then it takes 2 hours in the future for 2 people to discuss why it even got to the repository.<br />
<br />
That's the real meaning of a debt. <b>A 5-minute hack can turn into 2-hour discussion.</b><br />
<br />
I've listed several approaches. I've tried them all. None of them is really good, right?<br />
<br />
No hope then?<br />
<br />
Well, there's another way of thinking. It's probably less spectacular and it requires better skills, but it can reduce most of the problems above.<br />
<br />
First of all, <b>there are hacks and hacks</b>.<br />
<br />
Some code should never be written in the first place. If you wrote a >100-lines method from scratch then <b>it's a mess, not a code</b>. Such code shouldn't go the repo. It doesn't matter if it's tested or not. There are some basic rules of coding that apply to our projects. It might be good for just spiking - writing some code to see if the concept can work. Afterwards it gets deleted.<br />
<br />
Other cases are more on the technical debt side of things.<br />
<br />
It's good to have such skills, that it doesn't make a time difference for you to write the code inside the action or in the service object.<b> I just don't believe the time spent on typing those few characters/words more makes a difference</b>. We're talking about seconds here, not even minutes.<br />
<br />
More often, you're in situations, where you need to tweak some existing code to make the feature work. The original code wasn't yours - it doesn't even matter. What matters here is that this place requires a cleanup anyway. Let's say that you didn't have time to improve the existing code. There was no time for the Boy Scout rule. You've extended the existing action by some new 'if' statements. The whole path now works.<br />
<br />
Now, this is the problematic situation. It's not your fault that the code was so bad at the beginning. You didn't improve it, though. <b>You even made it worse.</b> How much worse? It depends. <br />
<br />
It's good to have a set of rules that all team agrees on. <br />
<br />
<b>Rails is so great, because it comes with conventions.</b> As a team, you're not only choosing the web framework but also <b>a convention framework</b>. The problem is that at some point The Rails Way is not enough. This is the scary time when the team may not have enough guidelines. This is the time when it's not so clear anymore, where to put code and how to structure it.<br />
<br />
<b>That's why we coined the term The Next Way</b>. It's a label to put some practices into. Service objects, form objects, adapters, repo objects. This is our way to solve the problem of missing conventions. It doesn't solve all of the problems, however it does help in limiting the length of the discussions. <br />
<br />
<b>The Next Way is just one possible set of conventions.</b> We go with that but your team may choose anything else. What's important here is to have something that the team can agree on.<br />
<br />
Thanks to The Next Way, we know what's the best format of a service object. Yes, there's lots of formats and discussing which one is best takes time.<br />
<br />
So, The Next Way describes the goal. Your code is in point A and The Next Way code is Z. There's lots of steps in-between. <br />
<br />
Being aware that improving code is a process helps a lot. Some would argue that being in point C is still bad. As long you as you all know that it's better than A - you can all agree that it's an improvement anyway.<br />
<br />
Let's take an example here.<br />
<br />
Imagine that your new feature requires displaying a new sentence in the view which shows the total value of the orders. The current view and action is very @ivar-heavy. There's no service object here, no repository objects as well. If you know The Next Way, then you know that removing @ivars is one of the steps we make to enable us for further steps.<br />
<br />
In this interpretation, adding a new @ivar, like @total_order_value makes the code worse. It's not a big deal, but it's definitely not an improvement.<br />
<br />
Now, what's good when you all have the commons set of techniques, like The Next Way is that <b>everyone knows that it needs to be fixed</b>. If you didn't have time to do it (like in the story we started with) in the first place - it doesn't really matter that much.<br />
<br />
Why?<br />
<br />
<b>Because it's very easy to fix it</b>. Once you know what is the goal, it's a matter of minutes to just turn the @ivar into an explicit rendering of a view following the "Explicitly Render Views with Locals" recipe.<br />
<br />
Whoever next comes to this code and is more lucky with the business pressure can just fix it (with the help of the recipe if needed), commit, push, deploy. That's it. <b>No lengthy discussions, no blaming, all clear.</b><br />
<br />
I've seen many teams struggle when they entered the <b>Beyond-The-Rails-Way phase</b>. This phase is hard to avoid. When it happens, the team has problems with the consistency of the code. Sometimes the code looks like a collection of random blog posts. One technique here, another there. There are some good ideas, but there's no clear goal for all the code.<br />
<br />
Once we've embraced The Next Way as a common set of techniques it was all easier. It is like <b>The-Rails-Way-On-Steroids</b>. It's more clear, where the code is. It's now clear when the code is in step C or closer to point Z.<br />
<br />
What I'd like to encourage you to with this blogpost is to find your set of techniques in your team. This will help you and it will speed up your team work.<br />
<br />
You can take what's in our book as a starting point and fork from there. The "Patterns" part of the book is all about The Next Way and its techniques. This is the description of the goal - the Z points. The "Recipes" chapter, on the other hand is all about the steps between the points.<br />
<br />
<a href="http://rails-refactoring.com/">Buy the book here</a><br />
<br />
If you already bought the book, please consider starting the discussion in your team. Ask if it's clear what are the team conventions once The Rails Way is not enough. <br />
<br />
Once you have the book, <b>please don't just read it and put it away.</b> The recipes need to be practiced regularly before they become a habit.<br />
<br />
Start today - timebox 15 minutes, choose any action and try to apply the Recipe. I encourage you to start with the "Explicitly Render Views with Locals" one. It's a good start to get the feel of such changes.<br />
<br />
There's a second episode of the <a href="http://rails-refactoring.com/podcast/">Rails Refactoring Podcast</a> - we're talking about the DNA of the Rails community and about The Rails Way. The whole episode is 35 minutes. We now also support RSS and iTunes, so subscribe to the podcast if you haven't done so yet :)</div>
Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com1tag:blogger.com,1999:blog-7821856652257554779.post-51394699628947661982014-11-28T10:38:00.002+01:002014-11-28T10:44:30.009+01:00The Rails culture and The Rails Way<br />
<br />
What is Rails for you?<br />
<br />
Is it just a technology? Is it about the community?<br />
<br />
<b>Do you remember the first time you scaffolded a Rails application?</b> <br />
<br />
How did it feel?<br />
<br />
Were you proud of achieving so much in so little time? Did you impress anyone by using Rails?<br />
<br />
Rails is no longer the youngest technology around. Did it change anything?<br />
<br />
Did you ever think how Rails ideas helped to shape the world? Did you notice how many startups choose Rails as the technology? It’s amazing that sometimes those people don’t fully know their business idea yet, but they know it will be implemented in Rails!<br />
<br />
<b>Rails changed the business world. For the better.</b><br />
<br />
It was no longer so expensive to come up with a prototype or with an MVP. More ideas could be validated.<br />
<br />
Some of the ideas were totally wrong. They didn’t have the market fit. Still, their authors lost less money than they would by choosing other (at that time) technology.<br />
<br />
Many ideas (and their authors!) were validated positively. The MVP has proved to be interesting for the users. People wanted to pay for using it. Those ideas turned into businesses. Many of those still exist today.<br />
<br />
As developers, we sometimes forget how much impact our work has on the world around us. All of the above wouldn’t have happened without us and Rails.<br />
<br />
What about those less technical people? Did they have their chance in the Rails revolution?<br />
<br />
Yes!<br />
<br />
It was late 2007 when I was contacted by a potential client. He said he was a fashion designer and he needed help with Rails deployment.<br />
<br />
What?<br />
<br />
<b>A fashion designer needing help with Rails deployment!</b><br />
<br />
“What do you want to deploy?”, I asked, assuming he got some technical terminology wrong. “Oh, it’s a prototype of a web application which helps men choose good clothes for them.”<br />
<br />
I looked at it and I was speechless. It was a fully working app, with a non-trivial algorithm implemented in Ruby.<br />
<br />
It was actually ready for deployment. That’s all I was needed for here. This scared me. One year before, I decided to rely my programming career on Rails. Is this what I signed up for? Non-technical people being able to implement an application needing me just for the deployment?<br />
<br />
I wanted to go back to my former Java world. To the world, where my job wasn’t threatened by fashion designers!<br />
<br />
<b>I realised that something big is happening. </b><br />
<br />
I was lucky enough to be part of it. Rails enabled more people to be involved in creating web applications. I was very curious where it's all going to.<br />
<br />
That was the time when new gems (they were called plugins at that time) started to pop up every week - acts_as_taggable, acts_as_anything, acts_as_hasselhoff (yes, there's such plugin: <a href="https://github.com/lazyatom/acts_as_hasselhoff/">https://github.com/lazyatom/acts_as_hasselhoff/</a> ). <br />
<br />
The fashion projects ended very well. When the client understood that I'm faster than him in developing the features, he took care of marketing and other stuff. I wasn't just the deployment person anymore.<br />
<br />
<b>Creating new Rails projects in 2008 was like combining little pieces together. </b><br />
<br />
At the beginning it was fun. However, the whole new wave of Rails developers started creating new versions of their gems every week. Each version had different dependencies. The authentication libraries kept changing every month at that time. At some point, it wasn't just connecting the pieces, but also hard work on untangling the dependencies to make it all work together. <br />
<br />
<b>The Rails Way was born</b><br />
<br />
This concept was never clearly defined. It was a term to describe the Rails approach. <br />
<br />
It's worth noting that at that time, everyone in Rails was coming from somewhere. I was from the Java world. Some people came from the PHP world. There were even some ex-Microsoft people. <br />
<br />
At that time there were no developers who "were born with Rails".<br />
<br />
When The Rails Way concept was appearing it was a way of distinguishing it from "the architecture astronauts Java way" or the "PHP spaghetti way". We needed to be unique and have something to unite us.<br />
<br />
Most of our community DNA was very good, but there was also something negative. A big part of the Rails community was united with the anti-Java slogans. Everything Java-like was rejected. XML? No, thank you, we've got yaml. Patterns? No, thanks. <br />
<br />
As a community, we entirely skipped the DDD movement, which took over the Java and .NET worlds. <br />
<br />
"We don't need this"<br />
<br />
"We've got ActiveRecord. We take the object from the database row and use it in all the three layers. Fat models or fat controllers? Whatever, let's just not create new layers."<br />
<br />
This way of thinking became more popular.<br />
<br />
<b>The Rails Way was very successful</b><br />
<br />
A new generation of developers started to appear. They were the ones who were born with Rails. Ruby was their first language. Rails was their first framework. The didn't bring the baggage of Java or PHP past life. <br />
<br />
They joined the Rails community and embraced what was presented to them. That was The Rails Way. <br />
<br />
<b>What is The Rails Way?</b><br />
<br />
It's hard to define it easily. I tried to do it recently and I found a few features that make it so uniq:<br />
<ul>
<li>ActiveRecord objects everywhere, including the views</li>
<li>External gems used for most of the features</li>
<li>Non-trivial logic implemented with the combination of filters, callbacks, validations, state-machine - often in a non-easy-to-follow-way.</li>
<li>Magic - Convention over Configuration, DRY, metaprogramming</li>
<li>Only 3 layers - Models, Views, Controllers</li>
</ul>
<br />
<br />
<b>When is The Rails Way good?</b><br />
<br />
It's really good for developers who start their career. I keep teaching The Rails Way to the students - at the beginning. That's the most efficient way to get a result. It's the best way to stay motivated while learning more. <br />
<br />
Within a project, The Rails Way is great at the beginning, when you're still not sure, where you go with the features and you need to experiment. In different project, the meaning of the beginning may be different. In some projects, I see the need to get out of the Rails Way as soon as the second month of development starts. In other projects it may be a year.<br />
<br />
<b>When is The Rails Way not enough?</b><br />
<br />
When you start wondering - does that code belong to the model or to the controller - it's a sign that you may be looking for something more than the Rails Way. <br />
<br />
When it's not clear how a feature works, because it's MAGIC - it's a sign the code controls you, not the other way round. You need something more to turn the magic into an explicit code.<br />
<br />
When you start creating model classes which don't inherit from ActiveRecord::Base and you have problems explaining to the team, why you needed that.<br />
<br />
When you try to test, but it either takes ages, because you need full integration tests, or you die by over-mocking.<br />
<br />
When you try to switch to a hosted CI, but they are unable to run your test suite.<br />
<br />
When you can only migrate data at nights, because the migrations lock the tables.<br />
<br />
<b>Learning from mistakes</b><br />
<br />
I've had the "luck" to review hundreds of Rails projects over the last 10 years. The same patterns were visible over and over again. An app was in quick development for the first months and then it started stagnating to the point where no one was happy with the speed.<br />
<br />
I've started collecting those patterns. I grouped them into code smells, anti-patterns, magic tricks.<br />
<br />
<b>Alternative architectures</b><br />
<br />
Meanwhile, over the years, I was studying many non-Rails-Way architectures like DCI, DDD, CQRS, Hexagonal. <br />
<br />
Then I started to draw lines between those two.<br />
<br />
<ul>
<li>How can I get from the Rails code smells into DDD?</li>
<li>Does DCI make sense in Rails apps?</li>
<li>Is there place for the Hexagonal adapters?</li>
<li>What are the aggregates in a Rails app?</li>
</ul>
<br />
Ruby and Rails are very unique and specific. Some things fit well into it, while others seem foreign to the way we write code.<br />
<div>
<br /></div>
<div>
<b>The Next Way techniques</b></div>
<div>
<b><br /></b></div>
<div>
<ul>
<li>service objects</li>
<li>adapters</li>
<li>repository objects</li>
<li>form objects</li>
<li>domain objects</li>
<li>events</li>
<li>presenters</li>
</ul>
<br />
<b>From A to Z</b><br />
<br />
I picked some of the building blocks of the architectures and tried to apply them in the Rails projects. The ones that didn't fit, I rejected. At the end, I only kept the ones which looked helpful for the typical problems.<br />
<br />
This was just the beginning. Even if you know the starting problem (point A) and you know the end result (point Z), there's many steps in between that need to be made very carefully.<br />
<br />
<b>Safety of changes</b><br />
<br />
I assumed the code transformations will be done on production applications. No place for any risk here. Some of the changes may even be applied to untested code.<br />
<br />
Your application needs to be safe, even when you apply the changes. Your boss and your clients will never allow introducing any bug "because I was improving the architecture". It's just not acceptable.<br />
<br />
<b>Working on the recipes</b><br />
<br />
It took me over a year to put together the refactoring recipes. Your code contains lots of small issues which make it harder to introduce a better design.<br />
<br />
You won't introduce service objects if your controllers are filters-heavy. The dependencies will break your code.<br />
<br />
You won't introduce service objects, if your views rely on @ivars magic. You need to be explicit with what you're passing to the views.<br />
<br />
You won't make the build faster if it the tests still hit the database. You won't get rid of the real database as long as your ActiveRecord classes contain any logic. You need to introduce repository objects.<br />
<br />
You won't introduce service objects easily, if your controller action can do different things, depending on the params (params[:action] anyone?). You need to use the routing constraints.<br />
<br />
You won't find any shortcut, unless you know the SimpleDelegator trick which helps you move a lot of code into a temporary service object at once.<br />
<br />
Those are some of the things I was working on. Those recipes are tested in big Rails projects by many different teams.<br />
<br />
Those recipes work.<br />
They will make your architecture improvement easier.<br />
<br />
<b>The book</b><br />
<br />
This all led to me to writing the <a href="http://rails-refactoring.com/">"Fearless Refactoring: Rails Controllers" </a><a href="http://rails-refactoring.com/">book</a>. <br />
<br />
The core of the book are recipes. However, the recipes alone may leave you with just the mechanics, so we've added many chapters which explain the techniques in details. <br />
<br />
We've also added the "Big examples" chapters. They take you through some (ugly) code and apply the recipes, one by one. <br />
<br />
Thanks to all of you who bought the book when it was still beta since February I'm very confident about its quality. You sent me a great feedback. You sent me the before/after pieces of code. This book wouldn't happen without the people who trusted us so early. Thank you!<br />
<br />
<b>1.0 release</b><br />
<br />
Some of you prefer to read books only when they are completed. Now is the best time to get it.<br />
<br />
On Monday, December 1st, the book goes 1.0, yay! During the next days we still keep the discounted price: $35. On Monday, the price goes up to its final price ($49). On Monday, you'll receive the 1.0 book update, no matter when you bought it.<br />
<br />
You can get the book at <a href="http://rails-refactoring.com/">http://rails-refactoring.com</a>. Use the REFACTORING code and you will get it 20% off!<br />
<br />
(we also have the 1-day 25% discount for our "Developers Oriented Project Management" book with the <span style="background-color: white; color: #3d3c40; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 14px; line-height: 18.399999618530273px;">BLACKFRIDAY2014 code - get it here: </span><a href="http://blog.arkency.com/developers-oriented-project-management/">http://blog.arkency.com/developers-oriented-project-management/</a> - many people switched to remote work after reading this book!)</div>
Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com3tag:blogger.com,1999:blog-7821856652257554779.post-22788593320178560732014-09-21T15:29:00.000+02:002014-09-21T15:29:01.921+02:00Terry Pratchett, the Long Earth and IT projectsI’ve just finished reading the <a href="http://en.wikipedia.org/wiki/The_Long_Earth">“The Long Earth”</a> novel by Terry Pratchett and Steven Baxter. While I expected the book to be more Pratchett’ish in the sense of humour (it’s not) I found it a very inspiring read anyway.<br />
<br />
<b>Parallel worlds</b><br />
<br />
“Long Earth” is based on the idea of parallel worlds. While reading it, I couldn’t resist the temptation of imagining what would happen if we had the same idea applied to IT projects.<br />
<br />
Remember the last time you started a project? I’m sure you’ve had some ideas on which architecture to choose or more likely, which language/framework to base it on.<br />
<br />
Should we go with Rails? Isn’t node.js the better thing nowadays? Is it a good idea to go with CQRS here? Scala will save us? This time it will be better?<br />
<br />
Now, imagine that all the decisions were made and all the alternative realities are happening.<br />
<br />
Let’s say, that in the Primary World you went with Rails, Angular, without CQRS.<br />
<br />
3 months in, you have the typical Rails problems, the models are overloaded with responsibilities, the controllers are not really that thin. The build now takes 5 minutes while most of the frontend code is untested. The team members start complaining - “We wouldn’t have such problems with Node.js”, “Can you see it now - we should have gone with CQRS in the first place”, “Scala, we need Scala, because of reasons (monads)”.<br />
<br />
Given the idea of parallel worlds (or rather parallel IT projects), you could jump into the world where Scala was chosen, just to notice, that the project is even in a worse shape, because some people didn’t get the idea of non-mutating state and it’s all not pure enough, while the frontend is not done at all, because all the time was spent discussing why Scala is actually worse than Haskell.<br />
<br />
Then you jump into the node.js alternative world. A quick look at the codebase - yes, callbacks everywhere. How did it go with code reuse on server/frontend? Oh yes, they don’t really share that much. Also, part of the codebase is in JS, while the other parts are in CoffeeScript, because you hired those new JavaScript developers, who hate Coffee, while the Rubyists in the team can’t parse JS at all.<br />
<br />
<b>Wouldn’t that be great?</b><br />
<br />
It’s all science-fiction obviously. I wonder, though, how much would it change our decision making process, if we knew that we could always look at how it goes in the alternative worlds.<br />
<br />
Would it make our decisions better?<br />
<br />
Would we learn that all projects have problems at some point, despite the technologies and architecture choices?<br />
<br />
Would we learn that no matter what we do, we may end up with another legacy codebase?<br />
<br />
Now, back to reality. We have only one, the Primary World. We can’t jump into other worlds. What tools do we have to measure our decisions? Is it actually worth to measure at such a high level?<br />
<br />
Maybe it’s better to just learn how to get out of any mess that we (and others) create?<br />
<br />
<br />
<br />Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0tag:blogger.com,1999:blog-7821856652257554779.post-51587749456022559662014-07-02T23:52:00.000+02:002014-07-02T23:52:33.625+02:00The secret to change your team habitsOver the last few weeks, we've been sending several lessons to our Arkency Newsletter (<a href="http://eepurl.com/LnL3b">not there yet?</a>) on how to become more Async with your programming team. They included techniques like:<br />
<div>
<br />
<a href="http://blog.arkency.com/2014/06/async-standups/">Async, textual, standups</a><br />
<a href="http://blog.arkency.com/2014/06/effective-async-communication/">Async knowledge sharing and gathering documentation before synchronous online meetings</a><br />
<a href="http://blog.arkency.com/2014/06/async-remote-toolbox/">Using and building tools which can greatly support you with your async and/or remote environment</a><br />
<a href="http://blog.arkency.com/2014/02/from-feature-vision-to-stories/">Splitting bigger stories into smaller ones on the fly</a><br />
<a href="http://blog.arkency.com/story/async-and-remote/">And more...</a><br />
<br />
<br />
By applying those lessons, you can make your team more effective. It doesn't matter if you do Rails, Python or Java. The team techniques and problems remain the same. <br />
<br />
<b>I'm sure, you've noticed that it's not as easy to switch the team habits to the new ones.</b><br />
<br />
<br />
Why do the people forget to work on small stories only?<br />
Why it's so hard to introduce async standups instead of the sync, voice-based ones, that everyone loves?<br />
Why are people not reviewing each other code changes?<br />
<br />
The thing is, <b>it's hard to eliminate habits (ask any smoker!)</b>. <br />
<br />
There are two rules for introducing new habits:<br />
<ol>
<li>Know what's your goal, what are the new habits to introduce. Luckily, you know the techniques we suggested in our email course and in our book.</li>
<li>It's easier to change existing habits than to eliminate them</li>
</ol>
<br />
The second point is crucial (and that's the secret!):<br />
<b><br /></b>
<b>Habits are based on hooks</b> (think Aspect Oriented Programming, but in real life).<br />
<br />
What are the current habits in your team? Is it that everyone prepares at 9.50am, because at 10am the standup starts? <b>Don't try to eliminate it (yet), just turn it into something different.</b> Do the text-based standup instead, even if it's at the same time with everybody. Just share your statuses in the communication tools or in the Google Doc or Hackpad. That's a smaller step and probably more likely to be adopted. Heck, you can even do it, while all are on Skype, if you prefer even smaller steps.<br />
<br />
There's a cool concept of Tiny Habits, that can help your team change more easily. This concept is directed towards single people and their habits, but the mechanisms stay the same for the team - try it and apply it for your team (it's free!):<a href="http://tinyhabits.com/">http://tinyhabits.com/</a><br />
<br />
A good experiment is to identify your team "hooks". Some example ones may include:<br />
<ul>
<li>a new commit pushed to the repo</li>
<li>new build failure</li>
<li>standup time</li>
<li>weekly meeting time</li>
<li>start of the day of work</li>
<li>end of the day of work</li>
<li>lunch time</li>
<li>new deployment</li>
</ul>
Once you identify your hooks, try to replace the actions that happen before/after the hook happens. Make it as simple as possible!<br />
<br />
Let's say, that one of your goals is to increase the knowledge transfer in your team and you decided that the '<b>foreman</b>' technique is the way to go. The simplest form of 'foreman' is to review someone's else code. You can gradually introduce it as a technique in your team, that whenever anyone finishes a ticker ("after finish ticket" - hook), they look at some of the recent commits (action!) in the repo and comment on them (even if it's a simple "+1"). At the beginning, you can make it just 10 minutes. It's enough to at least look at some code.<br />
<br />
<b>Hook</b>: You finished a ticket<br />
<b>Action</b>: Review someone's else code for 10 minutes<br />
<br />
You can't do much in 10 minutes, but if you know the Kronos/Chairos time management technique, that we were promoting, you know how to use the time best.<br />
<br />
Good luck!<br />
<br />
If you feel, like there's still more you can learn about the new async team techniques, <a href="http://blog.arkency.com/developers-oriented-project-management/">just grab our recent book</a> - it's designed to safely refactor your team towards being more effective!<br />
<br /></div>
Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0tag:blogger.com,1999:blog-7821856652257554779.post-73526073353888729552014-06-10T00:11:00.003+02:002014-06-10T00:47:51.682+02:00Custom exceptions or domain events?The topic of custom exceptions is surprisingly controversial. Some argue that exceptions shouldn't be used for anything related to "business", while others (me included) say that exceptions like InsufficientFunds are fine - I even wrote a whole chapter about using custom exceptions to simplify controllers in my <a href="http://rails-refactoring.com/">Rails Refactoring book</a>.<br />
<br />
I've read an interesting blog post today about custom exceptions (<a href="http://www.maciejaniserowicz.com/2014/06/09/custom-exceptions/">here</a> - unfortunately it's in Polish), where the author advocates for using "business exceptions".<br />
<br />
The example comes from a dialling application, so there are the following exceptions:<br />
<br />
<ul>
<li>CallAlreadyInProgressException, </li>
<li>IncorrectNumberException, </li>
<li>NumberAlreadyDialedException</li>
</ul>
<br />
When I first looked at the code, I nodded in agreement. Given such domain, those exceptions make total sense to me. I'd implement it the same way.<br />
<br />
When I linked to this post in our team chat, <a href="http://praglowski.com/">Mirek</a> (who has more knowledge about DDD and CQRS than I do) said that it'd be better to implement with domain events. This surprised me a bit, as when the topic of custom exceptions is brought up, domain events are rarely shown as an alternative.<br />
<br />
What's the difference between custom exceptions and domain events?<br />
<br />
Look at this code:<br />
<br />
<script src="https://gist.github.com/andrzejkrzywda/063f2cb42e9142ff6e19.js"></script>
Domain events decouple the call to the method from returning the result. This is at the core of the CQRS approach - one of the most<a href="http://andrzejonsoftware.blogspot.com/2013/12/the-four-architectures-that-will.html"> inspiring architectures</a> I've ever read about. In short - any system operation is either a Command (a change to the system) or a Query (a read from the system). This rule drives the whole architecture.<br />
<br />
In the code, it means that when you call dialler.call(number), you're not directly interested in the result, even to the point, that the method can fail (raise an exception). You made a command and that's it.<br />
<br />
Now, obviously, you do need to know about the failure. That's why you publish an event, using whatever mechanism under the hood. It can be a simple singleton EventBus class, which just keeps a map of objects interested in certain events and notifies them if any such event happens. In our case, we could have a UINotifier class listening to the CallAlreadyInProgress event and sending a special UI message to the user of the system (the technical details are not important here - it can be via polling or Web Sockets).<br />
<br />
There is another difference - with events we need to "publish" the fact that all went fine. What was implicit with exceptions (no exception is raised - success), here needs to be explicit. We publish the "ConnectionEstablished" event.<br />
<br />
This creates a nice simplification of the whole code around it. It may make it a bit more indirect, but it's actually very simple. All of the pieces of code involved do just one thing.<br />
<br />
<br />
<br />Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com7tag:blogger.com,1999:blog-7821856652257554779.post-27663188273147635802014-05-28T11:52:00.001+02:002014-05-28T11:52:41.819+02:00Remote team - mobile toolsWhen working remotely and/or asynchronously you may be often in situations where a mobile access to the team/project data is very useful. See my previous blog post on <a href="http://andrzejonsoftware.blogspot.com/2014/04/remote-team-tools.html">desktop tools for remote teams</a>.<br />
<br />
Here is a list of tools I often use in the context of the Arkency team. I use all of them from my iPhone 5s. I think most of them have their Android versions.<br />
<br />
<br />
<ul>
<li>Team/project</li>
<ul>
<li><a href="https://itunes.apple.com/us/app/slack/id803453959">Slack</a></li>
<ul>
<li>our IM tool of choice, good UX, easy to use, even with a 20+ team</li>
<li>the nice thing is that it caches all the history of our channels, so I can sync with them whenever I want</li>
</ul>
<li><a href="https://itunes.apple.com/us/app/hackpad-for-ios/id789857184">Hackpad</a></li>
<ul>
<li>accessing offline and creating hackpads offline is the killer feature</li>
</ul>
<li><a href="https://itunes.apple.com/pl/app/trello-organize-anything/id461504587">Trello</a></li>
<li><a href="https://itunes.apple.com/en/app/ioctocat/id669642611">iOctocat</a></li>
<ul>
<li>This app pushes me a notification whenever any new commit appears in any of my github repos. I can easily review the diff, comment on the changes or just browse through the code - highly recommended!</li>
<li>basic version is free. it's worth upgrading to receive notifications ($12.99)</li>
</ul>
<li><a href="https://itunes.apple.com/pl/app/mumble/id443472808">Mumble</a></li>
<ul>
<li>the voice communication tool of our choice, push to talk, multiple rooms</li>
</ul>
</ul>
<li>Social</li>
<ul>
<li>Twitter</li>
<li>Facebook</li>
<li><a href="https://itunes.apple.com/app/alien-blue-unofficial-reddit/id370144106">AlienBlue</a></li>
<ul>
<li>a Reddit client - useful if you often post your blog posts to Reddits</li>
<li>free, but worth upgrading for $1.99</li>
</ul>
</ul>
<li>Getting Things Done</li>
<ul>
<li><a href="https://itunes.apple.com/app/mindnode/id312220102">MindNode</a></li>
<ul>
<li>$9.99</li>
<li>it's the mind mapping tool, that I was looking for a long time</li>
<li>it has a Mac version (paid separately) and integrates/syncs via iCloud</li>
</ul>
<li><a href="https://itunes.apple.com/pl/app/evernote/id281796108">Evernote</a></li>
<ul>
<li>Quick to find important information, even from a mobile.</li>
</ul>
</ul>
<li>Geo</li>
<ul>
<li><a href="https://itunes.apple.com/en/app/foursquare/id306934924">Foursquare</a></li>
<ul>
<li>Even though, we are a remote team, many of us live in the Wroclaw area. When people are in the habit of checking in, you can easily see if anyone is close to you right now. I'm a strong believer of async/remote work but when there's a chance to meet face to face, that's always a good idea!</li>
</ul>
</ul>
</ul>
<div>
<br /></div>
<div>
<div>
<br /></div>
</div>
<div>
<br /></div>
<div>
This blogpost is a work-in-progress chapter from the <a href="http://blog.arkency.com/developers-oriented-project-management/">"Developer Oriented Project Management"</a> book. The book is just weeks before the final release. Grab it now, before the price goes up!</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com2tag:blogger.com,1999:blog-7821856652257554779.post-55226485331664048802014-05-26T11:05:00.000+02:002014-05-26T11:05:55.566+02:00Async standupsWhen you work remotely, you want to have some kind of a standup meeting regularly. In our team, after experimenting with many different approaches, we settled with text-based, asynchronous standups every day. Additionally, every project has a weekly 'sync' meeting.<br />
<br />
Whatever tool we currently use for remote communication (irc in the past, now Slack), we create a channel that is dedicated to #standup. We don't have a specific time to post there, usually we do it, when we begin our work session - so, in the spirit of async - different people at different times.<br />
<br />
I consider #standup to be a very good opportunity to communicate cross-project, to educate, to learn, to help. Short standup messages are not bad, but they miss this opportunity.<br />
<br />
<b>When writing the standup message, think more about the others, than about yourself</b> - what can they get from it by reading your status?<br />
<br />
<b>Example </b><br />
<br />
Yesterday I finished the "fix the price calculator" feature, which was mostly about removing the Coffee code and rely on the value retrieved from the backend, via ajax. The nice thing was that the backend code was already covered with tests, while the Coffee one wasn't. After that I helped Jack with the "allow logging in with email" feature (we need it now because we have a batch import of users from system X soon). After that I did a small ticket, where I block buying licences for special periods of time. This was nicely TDD'ed, thanks to the concept of <a href="http://robert.pankowecki.pl/ddd/#/">aggregate</a>, introduced by Robert recently - all the tests pass < 1s. Here is a commit worth looking at: <link github="" to=""></link>.<br />
Today I'm going to start with foreman'ing the recent commits and after that I want to work the XYZ system to allow a better editing of entries. I'm not sure how to start it, so all help is welcome.<br />
<br />
<b>What's good?</b><br />
<b><br /></b>
<br />
<ul>
<li>many details, </li>
<li>letting other people jump in and help me,</li>
<li>some opinions about the code that I saw, </li>
<li>some details about practices I applied (TDD, foreman'ing) </li>
<li>reminds about some business information - import of users from the X system, happening soon </li>
<li>links to the commit (potential education) </li>
</ul>
<br />
<br />
<b>Format </b><br />
<br />
1. yesterday<br />
2. today<br />
3. good thing<br />
4. bad things<br />
5. challenges<br />
6. call for help<br />
7. reminder about good practices (tdd, foreman, help colleagues)
<br />
8. code examples (link)<br />
9. business-related info<br />
<br />
<br />
(this blog post is a work-in-progress chapter in the <a href="http://blog.arkency.com/developers-oriented-project-management/">Developer-oriented Project Management book</a>.)Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0tag:blogger.com,1999:blog-7821856652257554779.post-49615441374554868372014-04-29T11:15:00.000+02:002014-05-01T20:35:25.124+02:00Remote team toolsI've been speaking today at a local IT entrepreneur meetup about remote work and about the ways a company can transition towards being more remote.<br />
<br />
The part of the talk that seemed to be most interesting was the toolset that we're using at the moment. I thought I'd share this list here, as well.<br />
<br />
Remember, that tools should just support your process and not replace it. If your goals are clear to you and your team, then the tools are just implementation details.<br />
<br />
<ul>
<li>Internal (written) Communication - <a href="http://en.wikipedia.org/wiki/Internet_Relay_Chat">IRC</a></li>
<li>Requirements/Tickets - <a href="https://trello.com/">Trello</a></li>
<li>Documentation - <a href="http://hackpad.com/">Hackpad</a></li>
<li>Voice communication - <a href="http://mumble.sourceforge.net/">Mumble</a></li>
<li>Code reviews - Github</li>
<li>Continuous Integration - Jenkins</li>
<li>Remote pairing - tmux</li>
<li>Video calls - Google Hangouts</li>
</ul>
<br />
<br />
<b>Internal (written) Communication - IRC</b><br />
<br />
For most of the internal communication in the team, we've been using IRC. It's a kind of a old-school tool. It served us well for about 7 years now, but meanwhile we've been experimenting with alternatives, like Slack (just recently).<br />
<br />
The tool itself is not that important, it's the goal it serves that is interesting.<br />
<br />
We have one channel per project and several generic channels, like #lol, #arkency, #links, #coffee, #products, #blog.<br />
<br />
The project channels are often integrated with other tools and receive notifications from Trello, Github, Jenkins. This is like the headquarters.<br />
<br />
In some projects we also use Slack or Flowdock for the same goal.<br />
<br />
<b>Requirements/Tickets - Trello</b><br />
<b><br /></b>
This is our default project management tool. It works as a backlog. It contains many tickets/stories, prioritised and described. It helps detailing the requirements and seeing what's the status.<br />
<br />
The tickets are also refactored - we extract new tickets, rename them, group them - whatever is needed.<br />
<br />
In some projects we use Pivotal, Redmine or Asana for the same goal.<br />
<br />
<b>Documentation - Hackpad</b><br />
<b><br /></b>
Hackpad - this is my favourite one. If you're not familiar with it already, it works similarly to Google Docs. In my opinion, it's a bit more interactive.<br />
<br />
It's basically a wiki on steroids. It has support for collections, it notifies about changes via email. You clearly see who wrote what. You can comment sections of code and checkboxes.<br />
<br />
Whatever interesting happens in our company, it gets an URL on Hackpad. Do I have an idea for a bigger refactoring in one project? I create a hackpad, paste some code and describe the plan. Others can join whenever they want (async!) and add their comments.<br />
<br />
<b>Voice communication - Mumble</b><br />
<b><br /></b>
Mumble is probably unknown to you. It's a tool very popular among gamers. They use it to communicate in a team, during a game. We started using it, as it was much more reliable than Skype. It's a very minimalistic tool. It has the concept of channels, so we designed it similarly to our communication tool (IRC). It also allows recording the conversations, so that people who were not able to attend (async!) can later listen to the most important fragments.<br />
<br />
<b>Code reviews - Github</b><br />
<b><br /></b>
We use Github for hosting code and for making the micro-code reviews. I call it micro, as they only let us comment the deltas - commits or pull request. They don't let us comment the existing code base, which is a limitation many similar tools share.<br />
If there's one place, I'd like to see improvement for remote teams it would be a proper code review tool.<br />
<br />
<b>Continuous Integration - Jenkins</b><br />
<b><br /></b>
We host the Jenkins instances to build our projects. I'm very far from liking it - it has many quirks, but overall we didn't find a good alternative to switch, yet.<br />
<br />
<b>Remote pairing - tmux</b><br />
<b><br /></b>
I blogged about <a href="http://andrzejonsoftware.blogspot.com/2008/02/remote-pair-programming.html">remote pair programming</a> 6 years ago. At that time, I was using screen + vim and I still think it's a good combo (together with Skype or Mumble). Nowadays, we don't pair program too often, but when people in my team do that, they often use tmux to connect to each other (terminal-based). Another tool is<a href="http://tmate.io/"> tmate.io</a>, which is also tmux-based.<br />
<br />
On a good connection you can also use Google Hangouts and their Desktop Sharing feature.<br />
<br />
<b>Video calls - Google Hangouts</b><br />
<br />
We use video calls very rarely and mostly, when external teams are involved who prefer it. In that case, we use Google Hangouts.<br />
<br />
<b>Summary</b><br />
<b><br /></b>
It's important to understand that those are only tools. They can change. I'm pretty sure, next year, we'll use a different toolset. What's important is the process around it - how you collaborate on projects, how you split stories, how you discuss, how you collaborate on the code.<br />
<br />
<br />
If you'd like to learn more about the techniques that we use in our remote and async collaboration (not only about the tools), then let me recommend the Robert Pankowecki book about it (I also wrote one chapter): <a href="http://blog.arkency.com/developers-oriented-project-management/">Developer Oriented Project Management</a>.<br />
<br />
What tools are you using? What would you recommend?Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com2tag:blogger.com,1999:blog-7821856652257554779.post-49610050381469823282014-04-27T11:30:00.000+02:002014-04-27T11:30:17.859+02:00TDD and Rails - what makes a good Unit?There is an ongoing discussion about TDD and Rails. It was recently heated by some some of the DHH statements in his RailsConf keynote and in the blog post: <a href="http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html">http://david.heinemeierhansson.com/2014/tdd-is-dead-long-live-testing.html</a><br />
<br />
One aspect of this discussion is the confusion about - What makes a good Unit?<br />
<br />
In the Rails community, I've seen people overusing mocks and stubs - you can detect it by looking at all the "should_receive" calls in the codebase. They're not always bad, but they might be potential code smells.<br />
<br />
The reason we use should_receive is in a way to draw the boundary between what's important to test right now and what's outside of the test scope.<br />
<br />
<b>Unit example</b><br />
<br />
Let's take an example - you've got an Order, which can have many OrderLines, a ShippingAddress and a Customer.<br />
<br />
Do we have 4 units here, representing each class? It depends, but most likely it may be easier to treat the whole thing as a Unit. You can write a test which test the whole thing through the Order object. The test is never aware of the existence of the ShippingAddress. It's an internal implementation detail of the Order unit.<br />
<br />
A class doesn't usually make a good Unit, it's usually a collection of classes that is interesting.<br />
<br />
This way of defining a Unit gives you tests, that don't need to change whenever the internals change - that's a good thing. You don't want to change tests on every refactoring - in fact it's a smell.<br />
<br />
<b>Unit-based architectures</b><br />
<b><br /></b>
Some time ago, I wrote a surprisingly popular post: <a href="http://andrzejonsoftware.blogspot.com/2013/12/the-four-architectures-that-will.html">The four architectures that will inspire your programming</a> in which I listed:<br />
<br />
<br />
<ul>
<li>Hexagonal Architecture</li>
<li>Clean Architecture</li>
<li>DDD</li>
<li>DCI</li>
</ul>
<div>
<br /></div>
<div>
In a way, all of them are focused on defining what a good Unit is and how to separate it from other Units. </div>
<div>
<br /></div>
<div>
<b>DDD</b> has the concept of an <a href="http://martinfowler.com/bliki/DDD_Aggregate.html">aggregate</a>, quote: "A DDD aggregate is a cluster of domain objects that can be treated as a single unit."<br />
<br />
<b>Clean Architecture</b> has the concept of use-cases which touch the topic slightly differently (by operations, not units), but overall it's very similar: <a href="http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html">http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html</a></div>
<br />
<b>Hexagonal Architecture</b> is all about a Unit surrounded by adapters, in my interpretation. They often call it the Middle Hex. <a href="http://alistair.cockburn.us/Hexagonal+architecture">http://alistair.cockburn.us/Hexagonal+architecture</a><br />
<br />
Last, but not least - <b>DCI</b>. This architecture deserves a special mention here. DHH quoted James Coplien in his TDD talk. James has been famous not only from his strong opinions on TDD, but more from his activity in the DCI world. He's one of the fathers of this movement. DCI is the most inspiring architecture here. Ruby and DCI makes a fantastic combination, however not all can work as in the DCI theory. DCI gives good tools for defining what a Unit can be. In short, their approach to what a Context is, may be used to defining Units. A Unit is this paradigm is a collaboration of objects. Read more here: <a href="http://fulloo.info/">http://fulloo.info/</a><br />
<br />
Have fun in researching more!<br />
<br />
If you want to follow more of my work - I'm writing <a href="http://rails-refactoring.com/">a book on Refactoring Rails apps</a>, which is already available. At the moment, I'm writing new chapters on how to write tests that support refactoring of Rails apps.<br />
<br />Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0tag:blogger.com,1999:blog-7821856652257554779.post-47744805150403301712014-04-15T15:35:00.000+02:002014-04-15T15:35:26.167+02:00Be careful with "the Rails way"<div>
The "the Rails way" expression is becoming popular in the Rails community. Depending on the people who use it, it means either something good or something bad. </div>
<div>
<br /></div>
<div>
<span style="font-size: xx-small;">(btw, this blog post has nothing to do with a book with a similar title)</span></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
This post is about why I think that "the Rails way" is not always so positive. </div>
<div>
<br /></div>
<div>
Let me start with the DHH ping pong story, which is happening now as it has a good code example to focus on.</div>
<div>
<br /></div>
<b>The history</b><br />
<div>
<b><br /></b></div>
<div>
The code ping pong with DHH has already started and my submission was chosen by DHH as the first one.<b><br /></b> For those of you who are not familiar with the code ping pong action - there was an interesting <a href="https://news.ycombinator.com/item?id=7335211">discussion</a> on HackerNews triggered by the <a href="http://eng.joingrouper.com/blog/2014/03/03/rails-the-missing-parts-interactors">“Rails - the Missing Parts”</a> post.<br />
<br />
At some point DHH wrote:<br />
<br />
<div>
<blockquote class="tr_bq">
"If this is a poor example, pick a good example. I'll be happy to code ping pong you whatever example you choose.”</blockquote>
<br />
The idea was picked up by Marcin "the awesome" Stecki from <a href="https://netguru.co/">Netguru</a>, who created <a href="http://www.dhh-ping-pong.com/">http://www.dhh-ping-pong.com/</a> and announced it at the <a href="http://wrocloverb.com/">http://wrocloverb.com/</a> conference.<br />
<br />
As I’m writing <a href="http://rails-refactoring.com/">a book on this exact topic</a> (how to turn Rails controllers into service objects) I decided to submit my example. I took the code from my recent blog post on refactoring: <a href="http://blog.arkency.com/2014/02/rails-refactoring-the-aha-moments/">http://blog.arkency.com/2014/02/rails-refactoring-the-aha-moments/</a><br />
<br />
DHH picked up the example and here we are, having different solutions to the same Rails problem.<br />
<br />
This is the actuall Pong page: <a href="http://www.dhh-ping-pong.com/pongs/13">http://www.dhh-ping-pong.com/pongs/13</a> (you can vote there).<br />
<br />
<b>Why I’m participating in this? </b></div>
<div>
<br /></div>
<div>
It wasn't an easy decision. Going public with some piece of code is not unusual in the age of open source. Here, however, it's going to be compared. It's going to be pointed out. There's some voting going on. I'm an easy target now ;) </div>
</div>
<div>
<br /></div>
<div>
It's not about voting, though.</div>
<div>
<br /></div>
<div>
The Rails community is huge nowadays. It's not the same small group of people, as it was in 2004-2005. We have hundreds of thousands Rails programmers in the world. Every day, new people are joining our community.</div>
<div>
<br /></div>
<div>
Rails is no longer used only for small apps. </div>
<div>
<br /></div>
<div>
It's used in enterprise. People rely on Rails codebases to make money for living. I'm sure, that somewhere out there, there is a Rails codebase, on which people lives depend on.</div>
<div>
<br /></div>
<div>
<b>Let's talk about responsibility.</b></div>
<div>
<br /></div>
<div>
Are we responsible for all Rails codebases out there? For sure, not. But there's a lot we can do to help our community and thus help the people who rely on Rails codebases.</div>
<div>
<br /></div>
<div>
Can we do something about those codebases being better? Not directly. </div>
<div>
<br /></div>
<div>
A small thing, that we can do is to trigger discussions. It's not for the sake of discussions. It's for the sake of learning. For the sake of improving. </div>
<div>
<br /></div>
<div>
It's easy to go too abstract with discussions. This is where DHH is totally right. </div>
<div>
<br /></div>
<div>
<b>Let's focus on the code. </b></div>
<div>
<br /></div>
<div>
I'm glad that DHH picked my example. It's based on a real Redmine code. Such code is written everyday by many programmers. The problem is small enough to be presented in one page. It's big enough to show different approaches.</div>
<div>
<br /></div>
<div>
Can my code be better? For sure! My code wasn't meant to be perfect. The main focus of <a href="http://rails-refactoring.com/">the research and practice for my book</a> is how to let people get out of the messy Rails codebases on a step-by-step basis. You can't risk rewriting the whole part. Every line of code can be hiding some potential user path. You have to make safe steps. </div>
<div>
<br /></div>
<div>
I believe in gradual improvement. I prefer evolution over revolution in the code.</div>
<div>
<br /></div>
<div>
That's why my example is not perfect. It's just a snapshot from a refactoring session that I took one evening. However, it's good enough to show some concepts. </div>
<div>
<br /></div>
<div>
It's showing the concept of a Service object. Even, if at the current shape it's using the "hack" of SimpleDelegator, it's worth to have it extracted.</div>
<div>
<br /></div>
<div>
I'm not proud of this code, neither I'm ashamed.</div>
<div>
<br /></div>
<div>
It's hard to discuss code refactorings without taking the time cost into account. It's not impossible to rewrite Redmine to a better code. It's a function of time. </div>
<div>
<br /></div>
<div>
If you look at the DHH code, the shape of the code (yes, code has a shape!) is better. Overall, the example is shorter than mine. I think not all the cases are covered, but that's not the point. DHH focused on using some of the Rails features to make the code shorter. The code is good. I'd take it over the existing Redmine code, without any doubt (assuming all the paths were covered!).</div>
<div>
<br /></div>
<div>
It's nice to see both the pieces of code, side by side.</div>
<div>
<br /></div>
<div>
<b>We both agree that the existing code was bad</b></div>
<div>
<br /></div>
<div>
First of all - that's probably most important here - we both agree that the existing code was bad. That's a good starting point.</div>
<div>
<br /></div>
<div>
<b>Where do we differ?</b></div>
<div>
<br /></div>
<div>
I didn't actually talk to DHH about it. I hope I'm not misinterpreting his intents here.</div>
<div>
<br /></div>
<div>
The main difference seems to be the fact, that <b>I tried to escape the framework as early as possible</b>. I avoided controller filters. I avoided model callbacks. Those are the things that I teach how to get rid of, if possible. DHH went the opposite way, he's using filters, he's using callbacks.</div>
<div>
<br /></div>
<div>
I'm not here to judge which approach is better.</div>
<div>
<br /></div>
<div>
Let me explain my refactorings here. I want to isolate my code from the framework. I didn't go that far, but I also want to isolate the 'logic' from persistence in the next steps (by using the repository pattern). The goal here is to have your logic framework-independent. To be able to run tests quickly, without hitting the database. To be able to split your app into smaller pieces - gems or microservices. To be able to control the whole application easier, this way.</div>
<div>
<br /></div>
<div>
In a way, it's an unusual approach in the Rails world. It's not so unusual if you look at other communities - Java, .Net, Scala, Clojure, Haskell, even PHP (with the fantastic Symfony2 framework).</div>
<div>
<br /></div>
<div>
Wasn't that the reason that we use Rails not to need to escape from it?</div>
<div>
<br /></div>
<div>
Yes and no.</div>
<div>
<br /></div>
<div>
It's a longer story, for another blog post, probably. In short, I believe that Rails is good for the start (as long, as you're not efficient with other approaches yet), however it's bad for a longer run. </div>
<div>
<br /></div>
<div>
Rails gives you a nice start, very quickly. This usually helps with the costs and the business side of the project. In the longer run, though - you have a much bigger codebase ( think > 100 database tables, if that means anything useful) and you want to split into smaller pieces. The more you're using Rails-specific features, the harder it is to split. It's a hard, ongoing transformation that can take months or years. That's why it's so important to realise it quickly and start sooner.</div>
<div>
<br /></div>
<div>
I've seen many projects that are stagnating with a typical Rails codebase. It's so hard to escape from the Rails monolith at some point.</div>
<div>
<br /></div>
<div>
You can say, that it's about programmers having low skills and that's the problem, not Rails. It's right to some extent. However, when you're stuck with a Rails codebase, you rely on a lot of magic. The Rails framework code is in fact becoming your code. Whatever happens inside, it's your problem now. <b>It's hard to be a good programmer in the legacy Rails environment.</b></div>
<div>
<br /></div>
<div>
At the beginning the pain is not so visible. It's hard later, when new requirements are coming. The ones, that are not shown on all Rails tutorials. The ones that require you to actually do some domain modelling, to secure the business logic, to hide some data from different roles. This is the place, where Rails is not helping you - it's going into your way. This is the moment, when you realise that mixing logic and persistence is not really the best idea. This is the moment, when your build already takes 20 minutes and you'd actually prefer to add even more tests. This is the moment, when you're better with <a href="http://www.threeriversinstitute.org/blog/?p=338">a modular design instead of the connected design</a>, as Kent Beck rightly points out.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.threeriversinstitute.org/blog/wp-content/uploads/2009/08/connectedAndModularDesign.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://www.threeriversinstitute.org/blog/wp-content/uploads/2009/08/connectedAndModularDesign.jpg" height="177" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
I'm showing a way that makes it possible to deal with bigger Rails codebases in the longer run. I'm not saying this is the only way to stay alive. It's just one way.</div>
<div>
<br /></div>
<div>
DHH and his team are very successful with "the Rails way". Business-wise I can't even compare my "successes" with their huge success. </div>
<div>
<br /></div>
<div>
Why choose the way I'm suggesting over "the Rails way"? I believe it's easier. It's based more on the overall programming rules, than on relying on some specific Rails features. You can look at the projects created in other communities and apply the lessons in your project. When you rely on Rails, you're in the ActiveRecord-based programming land. A place that lives somewhere between a relational database and OOP. It's a world on its own. You can be successful here, but it's a one-way ticket.</div>
<div>
<br /></div>
<div>
<br /></div>
Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com3tag:blogger.com,1999:blog-7821856652257554779.post-2603429763965348892014-01-23T17:47:00.004+01:002015-01-08T19:29:52.457+01:00Refactoring - the human factorI talked to many people about the concept of refactoring recently. I've noticed a pattern. Not all team members are equally pro-refactoring.<br />
<br />
I know how annoying it may be, when you're doing your best to improve the code, you learn how to do it the best way, you try to introduce it and then it's not only not appreciated, but also often rejected. Why is that?<br />
<br />
There's plenty of reasons, but most of them come down to the fact that a project is a team work. In a team, we work with other people. We all share the same goal - to let the project succeed. However, we're humans - each of us has a different perception of the goal and the path that leads to this goal.<br />
<br />
You may think that it's obvious that a better code will result in the success of the project. In most cases that's true.<br />
<br />
You may notice different levels of the refactoring-scepticism.<br />
<br />
<b>Do we really need to change the existing code?</b><br />
<br />
If you see such attitude, then one way of dealing with it is going back to the reasons for the refactoring. Is it because you spend a tremendous time on bug fixing? Is it because adding new features takes more and more time? Maybe it's because the app is slow and refactoring can help you extract some parts and later optimize them? <br />
<br />
There's never refactoring for the sake of refactoring.<br />
<br />
Whatever is the reason, make sure everyone understands it. If there's no understanding, move the discussion one step back. Why is it that your perception of the situation is different? Programmers are smart and logical people. Once you all see facts, metrics and numbers, it's easier to agree on the same solution.<br />
<br />
<b>Refactoring takes a lot of time</b><br />
<br />
This is a fair argument. We all care about the time we all spend on the project. Even if it's you doing the refactoring, then everyone is aware of the fact, that this time has a cost.<br />
<br />
The best way to deal with this argument is to keep improving refactoring skills. Both yours and your teammates. Examples from the Fowlers' "Refactoring" book are great. If you've done a quick refactoring, maybe it's worth showing to your team on a projector or record a screencast?<br />
<div>
<br /></div>
<div>
What you want is to have the refactoring cost being almost negligible. If your refactoring changes are fast and safe, then it's quicker to make the change than to discuss it.<br />
<br />
<b>I wouldn't refactor this part</b><br />
<br />
I made the mistake of refactoring the part of the code that wasn't really that important to change. It depends of the time spent. It's always good to improve the code everywhere, but what is the price? Does it take you 10 minutes, 1 hour? 10 hours? 10 days? Is it worth it?<br />
<br />
Time is our currency, make sure we spend them in the best way. <br />
<br />
<b>I would refactor it differently</b><br />
<br />
This problem appears when we have different visions of the refactoring. Let's say you learnt everything you could about DCI and you're sure that's the best direction to go with your project. You envision the contexts, the roles, the objects. Slowly, you keep extracting more code into modules that are later (hopefully) used as roles.<br />
<br />
At the same time, your colleague kept studying the concept of microservices. His goal is to split the app into multiple services talking to each other via HTTP/JSON.<br />
<br />
Where you see contexts, he sees services.<br />
<br />
This represents an architectural difference between both of you. <br />
<br />
To be honest, this is a nice problem to have. It means, that people in your team are passionate. They put time into learning new concepts and they are constantly trying to image the app in a different way.<br />
<br />
How to deal with it?<br />
<br />
I've chosen DCI and microservices as examples, but you could have a much different pair. What matters here is that most of the good architectures are not in fact that much different, however surprising it may sound.<br />
<br />
If you want to go DCI and your colleague wants to go microservices, then you have more in common than conflicts. Putting behaviour in the modules, as a step into using them as DCI roles is also a step into the microservices direction (you split the logic in a way that can be used by the microservice, later on). Your main difference is probably the last step - really, that's a nice problem to have :)<br />
<br />
<br />
One last thing, sometimes you may resort to another option:<br />
<br />
<b>Don't call it refactoring</b><br />
<div>
<b><br /></b></div>
<div>
OK, this one is controversial. In some teams, refactoring have negative meaning. It's probably for good reasons. Maybe they've had someone in the team, who didn't deliver value apart from endless refactoring? Try to understand it.</div>
<div>
<br /></div>
<div>
The goal is not to 'do refactoring', the goal is to do better, as a team.</div>
<div>
<br /></div>
<div>
If it doesn't help you, don't call it refactoring. Some teams are totally fine with the idea of <a href="http://programmer.97things.oreilly.com/wiki/index.php/The_Boy_Scout_Rule">The Boy Scout Rule</a>, which means more or less the same as refactoring. Keep improving the code quality, don't call it a refactoring.<br />
<br />
<br />
<b>Summary</b><br />
<br />
No matter what is the reason of the initial misunderstanding about the refactoring, make sure everyone understands it the same. Most of the times, there's something rational behind the refactoring need.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
----</div>
<div>
<br /></div>
<div>
What you just read is an excerpt from my book: <a href="http://rails-refactoring.com/">"Rails Refactoring: Service Objects"</a>. If you're a Rails programmer and struggle with an existing not-so-pretty Rails code, then you may find it interesting. The book is 191 pages, full of code examples and with recipes how to safely, step-by-step improve your Rails controllers, even if you don't have a full test coverage. </div>
<div>
<br /></div>
<div>
If you have examples of ugly Rails controllers, then please, send them to me: andrzejkrzywda@gmail.com.</div>
</div>
Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com1tag:blogger.com,1999:blog-7821856652257554779.post-19469907711382023652014-01-05T18:10:00.000+01:002017-02-04T16:22:04.889+01:00Twitter as a geek partyWhy do I follow close to 2000 people?<br />
Why do I keep complaining about the Twitter following limit (2000)?<br />
Why am I active on Twitter?<br />
Why did I just unfollow 150 people?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwdD9O-QpPlHQz-M7JDjcd0c4oSWtH7iVQrfID2S0sm-J9K8y3lo-NRc56krBU7eLNWCnzUWxpJeZ28_QqLEnldbcBt3juGWdMShnMTJmqAubDlYG8gsQ8rhJpuTvpnwMRueaLClCKvNU/s1600/107608641_0ea701ddb3_o.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="239" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwdD9O-QpPlHQz-M7JDjcd0c4oSWtH7iVQrfID2S0sm-J9K8y3lo-NRc56krBU7eLNWCnzUWxpJeZ28_QqLEnldbcBt3juGWdMShnMTJmqAubDlYG8gsQ8rhJpuTvpnwMRueaLClCKvNU/s320/107608641_0ea701ddb3_o.jpg" width="320" /></a></div>
<br />
<b><br /></b>
<b><br />[UPDATE February, 2017]</b><br />
This blogpost was written when Twitter was a great place for developers who were mostly interested in dev content. This was great for many years. As of late 2016, this has changed a lot. Even if you follow developers, you'll see mostly current politics content, usually US-centric. This means the technique described in this blogpost doesn't make sense anymore. Twitter is no longer an inspiring place for developers, who prefer to read about politics elsewhere or who prefer to stay out of politics.<br />
----<br /><br /><br />
<b>Twitter is an ongoing, very inspiring geek party</b><br />
<br />
I use Twitter in a bit of unusual way. Twitter to me is an ongoing, very inspiring geek party. It’s like a huge, virtual room (<a href="http://en.wikipedia.org/wiki/Snow_Crash">Snow Crash</a> anyone?) , which I can enter, whenever I want. I do it every now and then for short moments. I click some links, I see the pics. Conversations are most interesting - I focus on those. What do people talk about? Is it interesting to me? Is it interesting to my work?<br />
<br />
<b>Because the topics of their discussions inspire me</b><br />
<br />
I’m mostly connected to the Ruby/Rails community. Why do I follow PHP, Java, .NET people? Because the topics of their discussions inspire me. Why do they keep talking about DDD, when it’s a completely unknown concept in the Ruby community? Is it worth researching it? Can I join the conversation and explain how this problem is solved with Ruby? <br />
<br />
<b>I read about 10-20% of the tweets</b><br />
<br />
2000 people is much, but not much if you want to get inspired from many different directions. I hate the Twitter limit - for anti-bot reasons, they put this limit of 2000, probably with the assumption that no one sane, would want to follow so many people. There’s a problem with this assumption. I do want to follow thousands of people, but I don’t want to read all of the tweets. That would be insane. Twitter is not my email - I don’t read everything. I estimate that I read about 10-20% of the tweets. I want to have this mix of people in my timeline. Ruby is a lovely community, but the discussions don’t cover all of the interesting programming topics.<br />
<br />
t followings -l --sort=tweeted | head -10 | awk '{print $1}' | xargs t unfollow -i <br />
<br />
There’s one thing about the Twitter limit. It gets bigger if I get more followers. In short, I need to have about the same number of followers as the number of people who follow me. I’m not far from that - there’s about 1500 people following me right now, but it’s still not enough. That’s why from time to time I need to clean up the list of people I follow. I unfollow the most silent ones, who didn’t tweet for the last year or so. It doesn’t mean I don’t care about them. If not the limit, I’d be fine. Given, my Twitter usage, though, that makes most sense. I can always follow someone again, if they get more active.<br />
<br />
<b> I can’t even describe how much value I get from Twitter</b><br />
<br />
I’m so grateful to the people I follow. I learnt so much, I get inspired so often.<br />
<br />
I want to give the value back to my followers. I try to be active, tweet interesting links, engage in good conversations. Teach someone. Actively listen to other people problems. Try helping.<br />
<br />
I recommend you to try this approach. Follow more people (use <a href="https://twitter.com/search-home">Twitter search</a> to find interesting people). Treat is a geek party. Get inspired. Engage more. Don't read everything.<br />
<br />
If you're a programmer, you may enjoy <a href="https://twitter.com/andrzejkrzywda">following me</a> - I tweet mostly about programming, JavaScript, Ruby and working from home.<br />
<br />
(Photo credits: <a href="http://www.flickr.com/photos/romytetue/">http://www.flickr.com/photos/romytetue/</a> )Andrzej Krzywdahttp://www.blogger.com/profile/06399276063142826365noreply@blogger.com0