I bake softwareChristophe Philemottehttps://ibakesoftware.com/christophe.icohttps://ibakesoftware.com/christophe.pngChristophe PhilemotteThis is the pro website of Christophe PhilemotteZola2023-05-26T00:00:00+00:00https://ibakesoftware.com/atom.xmlImproving the homepage environmental footprint2023-05-26T00:00:00+00:002023-05-26T00:00:00+00:00https://ibakesoftware.com/blog/improving-website-footprint/
<h2 id="context">Context<a class="zola-anchor" href="#context" aria-label="Anchor link for: context">๐</a></h2>
<p>I've talked about the environmental impact of digital in
<a href="https://ibakesoftware.com/blog/apply-ademe-conclusions-to-software-development/">previous</a>
<a href="https://ibakesoftware.com/blog/a-naive-approach-of-software-sustainability/">blog posts</a>.
When the issue is intertwined and complex, there are some actions that will
significantly reduce the impact, such as reducing manufacturing, especially of
the terminals. When developing software, you can contribute to this reduction
by avoiding technical obsolescence. This also applies to simple websites. So
let's work on the current website.</p>
<p><a href="https://ibakesoftware.com/blog/clean-up-of-the-website/">When I redesigned it at the beginning of the year</a>,
I tried to keep it as light as possible by using a minimal CSS framework
(awsm.css) and as little javascript as possible<sup class="footnote-reference"><a href="#1">1</a></sup>. I also decided to use a
static generated website (Zola), so that the end result, i.e. all pages, are only
calculated once. However, I can't say how good it is in terms of footprint. If
I want to improve it, I need to be able to measure that footprint and evaluate
whether it is worth the effort. It may already be good enough.</p>
<h2 id="the-tools">The tools<a class="zola-anchor" href="#the-tools" aria-label="Anchor link for: the-tools">๐</a></h2>
<p>To measure, we'll use existing tools. Their purpose is to estimate the footprint
of a given web page. We'll use 3: EcoIndex, WebsiteCarbon, and EcoGrader.</p>
<p><a href="https://ecoindex.fr/">EcoIndex</a> scores your website using a model<sup class="footnote-reference"><a href="#2">2</a></sup> that
estimates the energy used by the server, network, and client to serve your
website. The model consists of a weighted sum of each. It uses a proxy to
estimate the energy consumed for each: the HTTP requests for the server, the
bandwidth used for the network, and the resulting DOM for the client. The score
is then converted into greenhouse gas and
<a href="https://en.wikipedia.org/wiki/Water_footprint#Blue_water_footprint">blue water</a>
equivalents. It is developed by the French
<a href="https://collectif.greenit.fr/">collective "Conception numรฉrique responsable"</a>.</p>
<p><a href="https://www.websitecarbon.com/">WebsiteCarbon</a> scores your website by
estimating the energy consumed from the bandwidth used to transmit the website.
The <a href="https://www.websitecarbon.com/how-does-it-work/">model</a> takes into account
the energy intensity of the web data, the energy source used by the data server
serving the data, the resulting carbon intensity, the annual Internet end-user
traffic, and the annual Internet energy. The result is then expressed in terms
of greenhouse gases. The model<sup class="footnote-reference"><a href="#3">3</a></sup> was developed by Chris Adams (The Green Web
Foundation), Rym Baouendi(Medina Works), Tim Frick (Mightybytes), Dryden
Williams (EcoPing), and Tom Greenwood (Wholegrain Digital). The calculator was
developed by Wholegrain Digital.</p>
<p><a href="https://ecograder.com/">Ecograder</a> uses the same methodology<sup class="footnote-reference"><a href="#3">3</a></sup> as
WebsiteCarbon to estimate greenhouse gas impact. It breaks down the size of a
web page into images, scripts, HTML/CSS, and others. By using some tools such
Google Lighthouse, it then recommends actions to improve the website. It also
rates the UX design including accessibility. It is developed by Mightybytes.</p>
<h2 id="the-starting-point">The starting point<a class="zola-anchor" href="#the-starting-point" aria-label="Anchor link for: the-starting-point">๐</a></h2>
<p>The first time I use the 3 tools on the homepage, I got the following results</p>
<ul>
<li><strong>EcoIndex:</strong> B grade<sup class="footnote-reference"><a href="#4">4</a></sup> (too heavy 2.796MB, simple 91 DOM elements, few requests 13)</li>
<li><strong>WebsiteCarbon:</strong> dirtier than 55%</li>
<li><strong>Ecograder:</strong> 79%<sup class="footnote-reference"><a href="#5">5</a></sup> (page weight 90%, UX design 73%, GreenHosting 100%, carbon score 60%)</li>
</ul>
<h2 id="the-budget">The budget<a class="zola-anchor" href="#the-budget" aria-label="Anchor link for: the-budget">๐</a></h2>
<p>Is it worth the effort? Looking at the stats, I can count about 500 visits to
the landing page since the beginning of the year. According to EcoIndex, this
results in ~700gCO2e and ~10.5l (blue water). For EcoGrader and WebsiteCarbon
it is about 425gCO2e.</p>
<p>Considering the maximum consumption of my laptop (90W) and the average annual
carbon intensity of the Belgian grid (~150gCO2e/kWh<sup class="footnote-reference"><a href="#6">6</a></sup>), this corresponds to
about 31 hours of work (<code>=425/150\*1000/90</code>). Depending on the improvement made
and the traffic, it might be worth it. Another way to look at it is that each
hour of work equals 13.5gCO2e, i.e. the cost of 10 to 16 visits. This seems to
be worth the effort.</p>
<h2 id="the-changes">The changes<a class="zola-anchor" href="#the-changes" aria-label="Anchor link for: the-changes">๐</a></h2>
<p>Most of the size of the site comes from 3 assets:</p>
<ul>
<li>the 2 images, and</li>
<li>the script that contains the index of all blog posts, which is used to search
the site.</li>
</ul>
<p>Let's start with the image. In total they weigh about 1MB. By checking their respective sizes, it seems that they're too big (200x200 is enough), also they're not well compressed. So I do the following:</p>
<ol>
<li>reduce their size with ImageMagick<sup class="footnote-reference"><a href="#7">7</a></sup>:
<code>convert <picture> -resize 200x200 <picture></code>,</li>
<li>optimize them with OptiPNG<sup class="footnote-reference"><a href="#8">8</a></sup>: <code>optipng <picture></code>,</li>
<li>compress it with pngquant<sup class="footnote-reference"><a href="#9">9</a></sup>: <code>pngquant -- <picture></code>.</li>
</ol>
<p>This results in a total size of 50kB, not bad.</p>
<p>For the search index, it is only worth loading when you do a search. My idea is
to load it only when we need it, i.e. when we type in the search text field.
That way it's a little less than 2MB that I can avoid.</p>
<pre data-lang="javascript" style="background-color:#2b303b;color:#c0c5ce;" class="language-javascript "><code class="language-javascript" data-lang="javascript"><span style="color:#65737e;">//Credit to https://zola.discourse.group/t/search-improvement/344/20
</span><span>
</span><span style="color:#b48ead;">function </span><span style="color:#8fa1b3;">delayedInitSearch</span><span>() {
</span><span> </span><span style="color:#b48ead;">function </span><span style="color:#8fa1b3;">loadScript</span><span>(</span><span style="color:#bf616a;">url</span><span>, </span><span style="color:#bf616a;">callback</span><span>) {
</span><span> </span><span style="color:#b48ead;">var </span><span style="color:#bf616a;">body </span><span>= document.body
</span><span> </span><span style="color:#b48ead;">var </span><span style="color:#bf616a;">script </span><span>= document.</span><span style="color:#96b5b4;">createElement</span><span>('</span><span style="color:#a3be8c;">script</span><span>')
</span><span> </span><span style="color:#bf616a;">script</span><span>.type = '</span><span style="color:#a3be8c;">text/javascript</span><span>'
</span><span> </span><span style="color:#bf616a;">script</span><span>.</span><span style="color:#bf616a;">src </span><span>= </span><span style="color:#bf616a;">url
</span><span> </span><span style="color:#bf616a;">script</span><span>.onreadystatechange = </span><span style="color:#bf616a;">callback
</span><span> </span><span style="color:#bf616a;">script</span><span>.</span><span style="color:#bf616a;">onload </span><span>= </span><span style="color:#bf616a;">callback
</span><span> </span><span style="color:#bf616a;">body</span><span>.</span><span style="color:#96b5b4;">appendChild</span><span>(</span><span style="color:#bf616a;">script</span><span>)
</span><span> }
</span><span> document.</span><span style="color:#96b5b4;">getElementById</span><span>("</span><span style="color:#a3be8c;">search</span><span>").</span><span style="color:#96b5b4;">addEventListener</span><span>("</span><span style="color:#a3be8c;">input</span><span>", </span><span style="color:#b48ead;">function</span><span>() {
</span><span> </span><span style="color:#8fa1b3;">loadScript</span><span>("</span><span style="color:#a3be8c;">/search_index.en.js</span><span>", </span><span style="color:#bf616a;">initSearch</span><span>)
</span><span> }, {once: </span><span style="color:#d08770;">true</span><span>})
</span><span>}
</span></code></pre>
<h2 id="the-final-result">The final result<a class="zola-anchor" href="#the-final-result" aria-label="Anchor link for: the-final-result">๐</a></h2>
<p>Let's go through the tools again:</p>
<ul>
<li><strong>EcoIndex:</strong> Grade A<sup class="footnote-reference"><a href="#10">10</a></sup>, i.e. 600gCO2e for 500 visits</li>
<li><strong>WebsiteCarbon:</strong> cleaner than 98%</li>
<li><strong>Ecograder:</strong> 98%<sup class="footnote-reference"><a href="#11">11</a></sup>, 15gCO2e for 500 visits</li>
</ul>
<p>It took me 2 hours of work, including research, so 27gCO2. Hopefully I'll have
another 500 visits ๐. According to the tools, I'll save between 100gCO2e and
400gCO2e. It seems to be worth the effort.</p>
<h2 id="the-models">The models<a class="zola-anchor" href="#the-models" aria-label="Anchor link for: the-models">๐</a></h2>
<p>As we can see, WebsiteCarbon and EcoGrader give us similar footprints because
they use the same model. The EcoGrader includes further measurements and
analysis to refine the report and provide recommendations. The scores obtained
by both are much lower than those obtained by EcoIndex. This is due to the
approach. WebsiteCarbon and EcoGrader assume that data transfer alone is a good
proxy for estimating energy consumption. The EcoIndex also takes into account
the complexity of the page and the number of requests. For the EcoIndex, the
size of the home page has the greatest impact on the energy consumption of the
network. This energy consumption is three times less important than that caused
by the DOM on the client terminal.</p>
<p>There are models that do not measure exactly, but give a good estimate. However,
it is important to understand the underlying assumptions in order to interpret
the results. I also think it's good to use different models to avoid having
only one perspective.</p>
<p>I also find it interesting that the EcoIndex estimates a different footprint
than green house gas. I wish we could have others because it is not the only
environmental concern.</p>
<h2 id="conclusion">Conclusion.<a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">๐</a></h2>
<p>These tools (and the models behind them) allow us to estimate the footprint
caused by visiting the home page. It does not directly cover the manufacturing
footprint, but it could help to keep some terminal models relevant for longer.</p>
<p>It is also a simple web page. For a web or mobile application, or any other kind
of software, the question will be more complex, even if the considerations
remain the same.</p>
<p>I'll probably try the same exercise for such a case. Let me know if you have one
in mind that you'd like me to study.</p>
<hr />
<p><strong>Footnotes:</strong></p>
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
<p>Beyond the privacy concerns, I also picked GoatCounter for its relatively
small javascript size (10kB against 100kB for gtag.js).</p>
</div>
<br/>
<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup>
<p>More details can be found in French on the
<a href="https://www.ecoindex.fr/comment-ca-marche/">EcoIndex website</a>,
<a href="https://blog.octo.com/sous-le-capot-de-la-mesure-ecoindex/">this article</a>
developing more the asumptions behind the model, or its
<a href="https://github.com/cnumr/ecoindex_python">implementation</a>.</p>
</div>
<br/>
<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup>
<p>The <a href="https://sustainablewebdesign.org/calculating-digital-emissions/">last version 3</a>
has been published on April 2022 on the website
<a href="https://sustainablewebdesign.org/">Sustainable Web Design</a>.</p>
</div>
<br/>
<div class="footnote-definition" id="4"><sup class="footnote-definition-label">4</sup>
<p>The <a href="https://www.ecoindex.fr/resultat/?id=d29629fc-a51d-4db3-bac8-837dfe6a1e38">corresponding EcoIndex report</a>.
This report might be removed by EcoIndex.</p>
</div>
<br/>
<div class="footnote-definition" id="5"><sup class="footnote-definition-label">5</sup>
<p>The <a href="https://ecograder.com/report/IFrMA5Bm7AAFa8Sim7xmHm05">corresponding EcoGrader report</a>
This might be removed by EcoGrader.
<br/></p>
</div>
<div class="footnote-definition" id="6"><sup class="footnote-definition-label">6</sup>
<p>This can be found thanks to <a href="https://app.electricitymaps.com/zone/BE">Electricity Maps</a>.</p>
</div>
<br/>
<div class="footnote-definition" id="7"><sup class="footnote-definition-label">7</sup>
<p>The doc of the <a href="https://imagemagick.org/Usage/resize/#resize"><code>resize</code> command</a>.</p>
</div>
<br/>
<div class="footnote-definition" id="8"><sup class="footnote-definition-label">8</sup>
<p><a href="https://optipng.sourceforge.net/">OptiPNG</a> recompresses image files to
a smaller size without losing any information.</p>
</div>
<br/>
<div class="footnote-definition" id="9"><sup class="footnote-definition-label">9</sup>
<p><a href="https://pngquant.org/">pngquant</a> is a lossy compression tool of PNG
images.
<br/></p>
</div>
<div class="footnote-definition" id="10"><sup class="footnote-definition-label">10</sup>
<p>The <a href="https://www.ecoindex.fr/resultat/?id=10337a85-cdfe-4540-98e6-a76b6e0ffa61">corresponding EcoIndex report</a>.
This report might be removed by EcoIndex.</p>
</div>
<br/>
<div class="footnote-definition" id="11"><sup class="footnote-definition-label">11</sup>
<p>The <a href="https://ecograder.com/report/vJB3Mcho8SmfZO12haKvx6zi">corresponding EcoGrader report</a>
This might be removed by EcoGrader. Note that I have also improved the
accessibility a bit by adding proper alternative text to the image and
adding an accessibility label to the search text field
(spotted thanks to <a href="https://wave.webaim.org/">the toole WAVE</a>).</p>
</div>
<br/>
Review of the Environmental impacts of digital technologies training2023-05-05T00:00:00+00:002023-05-05T00:00:00+00:00https://ibakesoftware.com/blog/review-of-environmental-impacts-of-digital-technologies-training/
<p>In my quest to learn sustainable IT, software engineering and design, I followed
the MOOC<sup class="footnote-reference"><a href="#1">1</a></sup> <a href="https://www.fun-mooc.fr/en/courses/environmental-impacts-of-digital-technologies/">Environmental impacts of digital technologies</a>
co-produced by <a href="https://www.inria.fr/en">Inria</a>
(a renowned French research institute in computer science and applied
mathematics) and <a href="https://www.class-code.fr/">Class'code association</a> (a
non-profit organization for the education of citizens in digital technologies).
They issue a certification as an Open Badge (which I've earned ๐). The training
is published on its
<a href="https://learninglab.gitlabpages.inria.fr/mooc-impacts-num/mooc-impacts-num-ressources/en/index.html">own website</a>
or on FUN in <a href="https://www.fun-mooc.fr/en/courses/environmental-impacts-of-digital-technologies/">English</a>
or <a href="https://www.fun-mooc.fr/fr/cours/impacts-environnementaux-du-numerique/">French</a>.
If you want to get the certification, you have to take it on FUN.</p>
<p>Let's first look at who is behind the MOOC. It is a collective work, resulting
from the contributions of several researchers, teachers and professionals. Some
have solid academic backgrounds in the field. Most have participated in French
working groups on sustainable digital technologies, either at
<a href="https://ecoinfo.cnrs.fr/">CNRS EcoInfo</a> (a unity of the National French Center of Scientific Research),
<a href="https://greenit.fr">GreenIT</a> (a profesional collective about Green IT)
or <a href="https://institutnr.org/">INR</a> (the French institute of sustainable digital).
Beyond their respective backgrounds, their style and approach are different from
those of the Green Software Practitioners training. First, they do not only
address software engineers. The MOOC introduces as many concepts as possible so
that everyone can catch up with all the aspects presented. The materials,
especially the videos, are able to convey their message with simplicity and
accuracy. Second, they place digital technologies in the context of the whole
human and environmental system. It's about the hardware, the software, the
services, what they can offer, what they can harm, what they can benefit, what
resources they require, what pollution they cause, and so on. In the last
chapter, for example, they show how difficult it is to conclude how positive
the balance is for a given digital technology. They introduce us to the subject
and teach us how to approach these questions with care and method. Finally,
it's the training that [Digital Collage recommends]
(https://digitalcollage.org/), especially if you want to become a professional
presenter.</p>
<p>Let's go back to the MOOC itself, its content, format and structure. It is
divided into 4 chapters: an introduction, non-renewable resources, very
tangible services, and economic and societal impacts. It took me about 6 hours
to read the text, watch the videos, do the activities, read the additional
resources, do some personal research, and take the final quizzes. Note that
they provide the transcript of the videos, a great alternative to speed
watching ๐. Everything is supported by references. A lot of topics are
discussed, and sometimes you can end up in a rabbit hole if you don't take the
easy way out. In fact, the extra material is not necessary to pass the course.
If you focus on the main parts, it should take 4 hours or less, depending on
your background. There are some activities to make you actively discover some
concepts or to reinforce the lessons. At the end of each chapter you will have
a final quiz to test your learning.</p>
<p>Because they approach every aspect with caution, I don't have much to criticize.
They are very transparent about the sources that support the statements they
share. If it's not very strong, if there's some uncertainty, if it's still
under research, if there's not strong scientific agreement, if the source
itself is not very transparent, they say so. One text that I appreciate
is <a href="https://learninglab.gitlabpages.inria.fr/mooc-impacts-num/mooc-impacts-num-ressources/en/Partie1/FichesConcept/FC1.4.2-EcologieNumerique-MoocImpactNum.html?lang=en">"Digital Ecology"</a>
, a supplementary material. They discuss how important it is to state the purpose
and place the technology in the system. Perhaps a small flaw is the
heterogeneous style. You can feel that the texts have been written by several
people and each one could be the starting point of a whole course in itself ๐.</p>
<p>In conclusion, I think this is a very good introduction to the topic. It gives a
very good overview of it and how to approach it. It does not pretend to teach
you the methods and approaches for assessing environmental impact or designing
equipment, software, or services to reduce it. It's worth noting that it
doesn't reduce the environment to the issue of climate (as important as that
is, it's not the only critical challenge we face). However, you'll end up with
the terminology, a bibliography, and a good overview of almost all of its
aspects to pursue further study or learning if you wish. Also, I think you'll
be better equipped to discuss and examine other materials and explanations.
Finally, for all these reasons, I think it's a better introduction than the
<a href="https://ibakesoftware.com/blog/review-of-green-software-practitioner-training/">Green Software Practitioners</a> training. If you have to choose just one, I'd go
with this MOOC for now.</p>
<hr />
<p><strong>Footnotes:</strong></p>
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
<p>MOOC means <a href="https://en.wikipedia.org/wiki/Massive_open_online_course">Massive Open Online Course</a></p>
</div>
<br/>
Sustainable IT newsletter #22023-04-21T00:00:00+00:002023-04-21T00:00:00+00:00https://ibakesoftware.com/blog/sustainable-it-newsletter-2/
<p>Since I had a few more news and articles, I'm sharing them with you this week.
Given the pace of publication on this topic, I don't think I'll be doing a
newsletter every week. I'm leaning towards one every 2 or 3 weeks.</p>
<h2 id="proposal-of-a-new-http-response-header-with-co2-eq">Proposal of a new HTTP response header with CO2-eq<a class="zola-anchor" href="#proposal-of-a-new-http-response-header-with-co2-eq" aria-label="Anchor link for: proposal-of-a-new-http-response-header-with-co2-eq">๐</a></h2>
<p>An <a href="https://www.ietf.org/archive/id/draft-martin-http-carbon-emissions-scope-2-00.html">IETF draft for a new HTTP response header with CO2-eq</a>
was submitted in early April. The amount of CO2-eq in grams will only correspond
to the electricity consumed (GHG scope 2). The goal is to allow the client of
the service to account for their Scope 3 carbon emissions, i.e. those emitted
upstream and downstream.</p>
<p>It's true that today it's difficult to estimate the Scope 3 of your service,
because in most cases there is no data available from the third party service
that you could use, and there are a lot of software that rely on such external
service.</p>
<p>While the idea is interesting, there are <a href="https://lists.w3.org/Archives/Public/ietf-http-wg/2023AprJun/thread.html#msg17">some concerns discussed</a>
, such as its trustworthiness, accuracy, or quantity adequacy. I'm curious to
see the final decision and the end result (if any).</p>
<h2 id="right-to-install-any-software-on-any-device">Right to install any software on any device<a class="zola-anchor" href="#right-to-install-any-software-on-any-device" aria-label="Anchor link for: right-to-install-any-software-on-any-device">๐</a></h2>
<p>In the previous newsletter we mentioned the current European proposal for a
right to repair. In my search for additional information, I've come across an
<a href="https://fsfe.org/news/2022/news-20220427-01.en.html">interesting viewpoint</a>
published about a year ago by the Free Software Foundation Europe and supported
by 34 organizations. They advocate unlocking all devices so that consumers
would have the right to install any software, choose any service provider, or
interact with any other device of their choice. This would also mean that the
manufacturer would have to provide access to drivers, tools, and other
interfaces.</p>
<p>I like this idea very much as it will allow to fight against software
obsolescence. For example, old Android devices aren't supported anymore. That
doesn't mean we can't use them. I was able to revive an old Motorola Moto G
from 2014 thanks to the <a href="https://e.foundation/">/e/OS</a>, a degoogled and
lightweight fork of Android.</p>
<p>Among the 34 signess there are /e/ Foundation, the European Right to Repair
Campaign, Fairphone, iFixit or Nextcloud.</p>
<h2 id="carbon-footprint-of-data-centers">Carbon footprint of data centers<a class="zola-anchor" href="#carbon-footprint-of-data-centers" aria-label="Anchor link for: carbon-footprint-of-data-centers">๐</a></h2>
<p>Just because data centers are seconds to the terminal in terms of environmental
impact does not mean that their impact is not significant. As for terminals,
it's difficult to do an accurate accounting. A common reason for this is the
confidentiality practices of companies, the so-called trade secrets. If they
can talk about their power consumption and their power usage effectiveness
(PUE), they usually don't disclose the number of servers and how often they are
replaced or repaired.</p>
<p>A recent blog does a good job of summarizing some of the issues to consider when
addressing the carbon footprint of a data center:
<a href="https://marmelab.com/blog/2023/04/12/carbon-impact-of-data-centers.html">"What is the carbon footprint of data centers?"</a>
The article is a takeaway of a presentation by a French researcher on the
subject, <a href="https://people.irisa.fr/Anne-Cecile.Orgerie/">A-C Orgerie</a>.</p>
<p>If you want to find information about a data center, you can find some in the
<a href="https://www.thegreenwebfoundation.org/directory/">Green Hosting directory</a>.
They explain <a href="https://www.thegreenwebfoundation.org/what-you-need-to-register/">how they rate the hoster</a>.
Not all listed datacenters have provided proof of their claim. But you can still
find interesting information like the PUE.</p>
<h2 id="predicting-the-evolutionf-of-the-environment-impact-of-the-digital-in-france">Predicting the evolutionf of the environment impact of the digital in France<a class="zola-anchor" href="#predicting-the-evolutionf-of-the-environment-impact-of-the-digital-in-france" aria-label="Anchor link for: predicting-the-evolutionf-of-the-environment-impact-of-the-digital-in-france">๐</a></h2>
<p>On March 6, ARCEP, a French regulatory authority, published its study on the
<a href="https://en.arcep.fr/news/press-releases/view/n/environment-060323.html">evolution of the digital environmental impact until 2030 and 2050</a>.
Among the conclusions, they predict a 45% increase in the digital footprint in
France by 2030 if nothing is done. By 2050, it could at least triple. They
study several scenarios, including one of sufficiency and minimization,
allowing to significantly reduce the impact.</p>
<p>I'm still looking for similar studies done for other countries and parts of the
world. If you know of any, please share them with me.</p>
<h2 id="third-party-service-best-practices">Third-party service best practices<a class="zola-anchor" href="#third-party-service-best-practices" aria-label="Anchor link for: third-party-service-best-practices">๐</a></h2>
<p>In the blog post <a href="https://greenspector.com/en/best-practice-limit-the-number-of-third-party-services/">"Best Practice: Limit the Number of Third-Party Services,"</a>
they develop an ecodesign best practice supported by several guidelines. They
illustrate the improvement with a real-world example: removing the Twitter feed
from every page of a website. They estimate a 40% reduction in carbon
footprint.</p>
Sustainable IT newsletter #12023-04-14T00:00:00+00:002023-04-14T00:00:00+00:00https://ibakesoftware.com/blog/sustainable-it-newsletter-1/
<p>As you may know, I'm studying sustainable IT with a focus on development. I have
found many interesting articles and news, and I think it would be a pity to
keep them to myself. So I'm going to share some interesting publications
(recent or not) on a regular basis. Tell me if you like it and what kind of
topic you'd like to see more of.</p>
<h2 id="rights-to-repair">Rights to repair<a class="zola-anchor" href="#rights-to-repair" aria-label="Anchor link for: rights-to-repair">๐</a></h2>
<p>In March, the Commission published a proposal to regulate and promote
<a href="https://commission.europa.eu/law/law-topic/consumer-protection-law/consumer-contract-law/rules-promoting-repair-goods_en">repair rights</a>.
This is a step in the right direction, as it will help extend the life of
terminals and other devices whose manufacture has the greatest impact on the
environment.</p>
<p>However, as <a href="https://repair.eu/news/not-yet-accessible-affordable-nor-mainstream-campaigners-tighten-the-screw-on-new-eu-right-to-repair-proposal/">Right to Repair Europe discusses</a>, there are still many aspects to frame, such as affordability or anti-repair
practices.</p>
<h2 id="ecolog">Ecolog<a class="zola-anchor" href="#ecolog" aria-label="Anchor link for: ecolog">๐</a></h2>
<p>On March 23, the French Sustainable IT Institute published a new guide on
guidelines for the design and construction of training courses on the subject:
<a href="https://ecolog.isit-europe.org/">Ecolog</a>.</p>
<p>This first version, in French, gives you a typology either by domain or by job.
For each domain, several training objectives are listed, explained, linked to
the UN <a href="https://sdgs.un.org/">Sustainable Development Goals</a>, and accompanied
by some references. For each job, this is the same, except that there is a link
to the <a href="https://gr491.isit-europe.org/en/">handbook of sustainable design of digital services (GR491)</a>
or the [AFNOR SPEC 2201] (https://www.boutique.afnor.org/en-gb/standard/afnor-spec-2201//fa203506/323315)
(AFNOR is the French standards body).</p>
<p>If you'd like to teach yourself, Ecolog can definitely help you find and study
which materials to look for and study.</p>
<h2 id="digital-heating-system">Digital heating system<a class="zola-anchor" href="#digital-heating-system" aria-label="Anchor link for: digital-heating-system">๐</a></h2>
<p>Since the data center must be cooled, the heat is wasted energy. There are
projects that are inspired by
<a href="https://en.wikipedia.org/wiki/Cogeneration">cogeneration</a> to not waste the heat.</p>
<p>I've found 2 such projects in the news. The first one is developed by a Belgian
company: <a href="https://levv.io/levv-heat">Levv heat</a>. It was
<a href="https://www.linkedin.com/posts/levvdigital_printempsnumaezrique-lighttech-numaezriquedurable-activity-7044960344254869504-Ma_5">presented</a>
during the Brussels Digital Spring at the end of March. The other one is
developed by the British company <a href="https://www.deepgreen.energy/heat">Deep Green</a>.
The system is connected to
<a href="https://www.theguardian.com/business/2023/mar/14/innovative-heat-tech-save-england-swimming-pools-from-closure">the heating system of swimming pools</a>.</p>
<h2 id="analysis-of-the-methodological-gap-between-existing-studies">Analysis of the methodological gap between existing studies<a class="zola-anchor" href="#analysis-of-the-methodological-gap-between-existing-studies" aria-label="Anchor link for: analysis-of-the-methodological-gap-between-existing-studies">๐</a></h2>
<p>On April 3, ARCEP, a French regulatory authority, published its
<a href="https://en.arcep.fr/news/press-releases/view/n/the-environment-030423.html">analysis of the differences in the methodologies used in studies on the environmental impact of digitalization</a>.</p>
<p>They have identified several reasons, such as the lack of data or their poor
quality, the poor or absent referencing of the works used, or a low use of the
ITU reference in this matter. They also make several suggestions.</p>
<h2 id="some-recente-releases">Some recente releases<a class="zola-anchor" href="#some-recente-releases" aria-label="Anchor link for: some-recente-releases">๐</a></h2>
<p>Here are some recent releases of tools.</p>
<p>The French collective GreenIT.fr presented
<a href="https://www.greenit.fr/2023/03/07/ecoindex-mise-a-jour-majeur-de-la-boite-a-outils/">the result of the refactoring of their Ecoindex toolkit</a> (in French, see also the <a href="https://www.youtube.com/watch?v=vZ0qcDQdPww">recorded presentation</a>).
Among other things, they updated all the tools with the latest version of the
handbook on sustainable design of digital services (see above). There is also a
<a href="https://github.com/cnumr/ecoindex_badge">badge</a> and a
<a href="https://github.com/cnumr/ecoindex-browser-plugin">browser extension</a>. Among the
tools, there is a <a href="https://github.com/cnumr/ecoindex_cli">CLI tool</a> that can
analyze locally websites. It can generate html report, for instance in a CI.</p>
<p>Another French collective, ecoCode, has
<a href="https://www.linkedin.com/feed/update/urn:li:activity:7047146316757372928/">announced version 1.0 of its tools</a>:
<a href="https://github.com/green-code-initiative/ecoCode">ecoCode</a> and
<a href="https://github.com/green-code-initiative/ecoCode-mobile">ecoCode mobile</a>. Both
are SonarQube plugins. The first is for Java, Javascript, PHP and Python, the
second for Android and iOS.</p>
Review of the Green Software Practitioner Training2023-04-07T00:00:00+00:002023-04-07T00:00:00+00:00https://ibakesoftware.com/blog/review-of-green-software-practitioner-training/
<p>Right now I'm learning as much as I can about sustainable IT, software
engineering and design. To that end, I took the online
<a href="https://learn.greensoftware.foundation/">"Green Software Practitioner Training"</a>
from the Green Software Foundation (GSF), an American foundation initiated by
Microsoft, Accenture, GitHub, ThoughtWorks, and the Linux Foundation in 2021<sup class="footnote-reference"><a href="#1">1</a></sup>.
You can get certified by the Linux Foundation
(<a href="https://training.linuxfoundation.org/training/green-software-for-practitioners-lfc131/">LFC131</a>)
, which
<a href="https://www.credly.com/badges/9c8bcb71-0d5f-471d-aa09-e777f8a643fc/public_url">I got</a>
๐๐พ). Here is my review of it.</p>
<p>First of all, I think it's important to look at the <a href="https://greensoftware.foundation/">GSF</a>.
This American foundation is supported by companies of the software market,
including the cloud computing one<sup class="footnote-reference"><a href="#2">2</a></sup>. They want software to be part of the
climate solution, focusing on carbon reduction<sup class="footnote-reference"><a href="#3">3</a></sup>. For them, there are only 3
actions to reduce carbon emissions: less physical resources, less energy, and
smarter use of energy (either from lower carbon sources or to support the
transition). That is indeed a valid approach. However, I'd say there is a
certain bias for 2 reasons. First, they focus on carbon footprint when there
are other important environmental impacts such as abiotic resource depletion,
especially <a href="https://ibakesoftware.com/blog/apply-ademe-conclusions-to-software-development/">for terminals</a>.
Second, among the actions they consider, there is no discussion of the purpose
of the software (e.g. increasing behaviors with negative impacts such as
advertising), or the minimization and relevance of features. In other
words, they do not examine some important aspects of the current software
industry that may not be compatible with our upcoming environmental challenges.
I think it's important to keep that in mind when taking this training.</p>
<p>In terms of format, the training is structured around the 6 basic principles
behind their approach: carbon efficiency, energy efficiency, carbon awareness,
hardware efficiency, measurement, and climate commitments. It took me about 3
hours to read, learn, do some personal research, and pass the final exam. The
web pages are light, nice to read, ... they clearly follow their own
principles. There is a quiz at the end of each chapter to make sure you
understand the main concepts.</p>
<p>I have identified a number of statements that I believe are biased or even
false. For example, in the chapter "Carbon Awareness" they state that</p>
<blockquote>
<p>If your computer is plugged directly into a wind farm, its electricity would
have a carbon intensity of 0 gCO2eq/kWh since a wind farm emits no carbon to
produce that electricity.</p>
</blockquote>
<p>This is true if you do not consider the production of the wind farm (aka Scope 3
of the GHG protocol).</p>
<p>The chapter "Hardware Efficiency" introduces the concept of carbon
amortization:</p>
<blockquote>
<p>A way to account for embodied carbon is to amortize the carbon over the
expected life span of a device.</p>
</blockquote>
<p>If this makes it possible to understand that increasing the lifetime of a piece
of hardware is important, I think it misleads to a biased conclusion: reducing
the total daily carbon emissions of the device. Amortization makes sense from an
economic perspective, but not from an environmental perspective. As I
understand it, increasing the lifespan of hardware is about reducing the
production of hardware. Also, amortization might make you think that the
emissions are delayed because you account for them through the use of the
device.</p>
<p>Later in the same chapter, they advocate public cloud computing as a good way to
increase hardware efficiency:</p>
<blockquote>
<p>With multiple organizations making use of the public cloud, spare capacity can
always be made available to whoever needs it, so that no servers are sitting
idle.</p>
</blockquote>
<p>While I agree that sharing resources is a good way to avoid wasting idle
computing resources, I think this is a false argument. First, it assumes that
there will always be enough computing resources (one of the pictures literally
mentions infinite spare capacity). When do we stop? Finally, this hardware
efficiency can lead to a take-back effect: the gain in efficiency will most
likely lead to an increase in usage that will offset the expected gain.</p>
<p>In the "Climate Commitments" section, they talk about offsetting. When they
remind us that mitigation is better than nothing, they present neutralization
and carbon removal as effective measures without any measured caution. There
are reasons<sup class="footnote-reference"><a href="#4">4</a></sup><sup class="footnote-reference"><a href="#5">5</a></sup> to doubt such statements, and it's important to stay critical to
make the right choices.</p>
<p>In conclusion, I find the 6 principles an interesting way to approach reducing
the carbon footprint of software. The training was also enjoyable to follow.
However, this is just an introduction. There's no real best practice or rule
that you can apply when developing software (even if there is a specific
<a href="https://patterns.greensoftware.foundation/catalog/web/">catalogue</a>). It is up
to you to follow these principles and implement them correctly. Another good
improvement would be to roughly explain the environmental impact of digital,
especially in terms of lifecycle. Finally, I can't help but read between the
lines a certain form of lobbying for the software market and the public cloud
in particular, which may not be intentional. If you remain critical, I think it
is still worth your time as it covers many important concepts (e.g. carbon
awareness, hardware efficiency) well.</p>
<hr />
<p><strong>Footnotes:</strong></p>
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
<p><a href="https://www.engadget.com/green-software-foundation-microsoft-build-linux-github-accenture-150050755.html">Microsoft, the Linux Foundation, and others team up to make software sustainable</a>, May 25 2021, engadget</p>
</div>
<br/>
<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup>
<p><a href="https://greensoftware.foundation/team/">GSF's team</a></p>
</div>
<br/>
<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup>
<p><a href="https://greensoftware.foundation/articles/what-is-green-software">What is green software?</a></p>
</div>
<br/>
<div class="footnote-definition" id="4"><sup class="footnote-definition-label">4</sup>
<p><a href="https://www.theguardian.com/environment/2023/jan/18/revealed-forest-carbon-offsets-biggest-provider-worthless-verra-aoe">Revealed: more than 90% of rainforest carbon offsets by biggest certifier are worthless, analysis shows</a>, Jan 2023, The Guardian</p>
</div>
<br/>
<div class="footnote-definition" id="5"><sup class="footnote-definition-label">5</sup>
<p>The wikipedia page reports the challenge to make <a href="https://en.wikipedia.org/w/index.php?title=Direct_air_capture&oldid=1148481447">Direct Air Capture</a> a profitable and effective process.</p>
</div>
La Fresque du Numรฉrique, a workshop on the environmental challenges of the digital world2023-03-31T00:00:00+00:002023-03-31T00:00:00+00:00https://ibakesoftware.com/blog/la-fresque-du-numerique-a-workshop-on-the-environmental-challenges-of-the-digital-world/
<p>In my last <a href="https://ibakesoftware.com/blog/apply-ademe-conclusions-to-software-development/">blog post</a>, we talked about the environmental impact of the digital
world. That may sound obvious when you say it, but it's not. As a user or
professional, you mainly see the use and its consequences. Because of its
growth, the main narrative has been positive. Roughly speaking, it will save
us. Honestly, I believed it. I bought it.</p>
<p>I belong to generation X, I had the chance to have access to personal computers.
I liked science, technology, ... and SciFi novels, especially cyberpunk. Not
original, right? I was amazed by the potential of computers, even if I could
see the possible abuse of their power.</p>
<p>When I studied engineering, I was interested in complex systems. I studied
control systems, cybernetics, and dynamical systems. I studied the World3
model. So I knew ... but I still didn't see the branches in the real world and
how much we were (and still are) dependent on the material world (fossil and
abiotic).</p>
<p>Why am I telling you this? I want to illustrate with my own case that the
beliefs and perspectives are very strong and they avoid us to see through them
if we don't look carefully and deeply. It took me 5 years to deconstruct mine
on my own. I wish someone had helped me from the beginning to get the big
picture (and the references).</p>
<p>The information may be available, but the narrative about the benign power of
the digital remains strong: "it's virtual, just bits, just a little
electricity, it's green, it'll solve everything". The reality is more complex:
making a 2kg laptop requires 800kg of material and several thousand gallons of
water. We have to raise awareness.</p>
<p><img src="https://ibakesoftware.com/blog/la-fresque-du-numerique-a-workshop-on-the-environmental-challenges-of-the-digital-world/fdn-carte-rucksack.png" alt="official card of the digital collage "The ecological backpack"" /></p>
<p>I was looking for training in ITC sustainability when I found a French NGO that
runs a workshop on the topic:
<a href="https://fresquedunumerique.org/">"La Fresque du Numรฉrique"</a>. It's based on the
pedagogy of <a href="https://fresqueduclimat.org/">"La Fresque du Climat"</a>: the
participants have to work together to rearrange a pile of facts that they get
during the workshop. They debate, exchange perspectives, and then correct
themselves thanks to the facilitator's feedback. Step by step, you uncover the
complex system behind it. It was refreshing and to the point, as in 3h30 we
were able to grasp the main mechanisms, implications, challenges and threats.</p>
<p>I think it's a great way to start and raise awareness in a group. They have an
<a href="https://digitalcollage.org/">English version</a> and some of the workshops are
online. For my part, I will continue to learn(and share) and in particular take
their training to become a facilitator.</p>
<p>By the way, <a href="https://climatefresk.org/">La Fresque du Climat</a> is also great.</p>
Apply the conclusions of the ADEME studies on the digital impact to software development.2023-03-21T00:00:00+00:002023-03-21T00:00:00+00:00https://ibakesoftware.com/blog/apply-ademe-conclusions-to-software-development/
<p><em>This article was updated on April 28 2023. Please find the comment about this
update after the article .</em></p>
<hr />
<p>When I started posting again, my plan was to do it every week or 2 weeks.
Considering that the last one was published on February 16th, you could say
I've failed. Indeed, but there's a reason: I fell into a rabbit hole, the study
of the sustainability of AI.</p>
<p>Along the way, I'm still learning many facts and studies on the sustainability
of digital that I'd like to share without writing a whole book. I think a good
recipe would be to focus on one small lesson or discovery and share my thoughts
about it. That's what I'm going to do today in this blog post.</p>
<p>The <a href="https://www.ademe.fr/en/frontpage/">ADEME</a> (the French Agency for Ecological
Transition) and the <a href="https://en.arcep.fr/arcep.html">ARCEP</a> (the French
Regulatory Authority for Electronic Communications, Postal and Print Media
Distribution) have published
<a href="https://en.arcep.fr/news/press-releases/view/n/the-environment-190122.html">a study in 2 parts</a>
about the impact of digital in France a year ago (recently they published a
third part focusing on the evolution of the impact for 4 different scenarios).
To analyze the impact of the French digital as a whole, they have decomposed
the digital in 3 parts (terminals, networks and data centers) and
[assessed their life cycle] (https://en.wikipedia.org/wiki/Life-cycle_assessment).</p>
<p>If there are known limitations (e.g. some excluded network hardware, non-French
services), the conclusions are quite significant and in line with other
studies (more about this in a next blog post):</p>
<ul>
<li>The main environmental impacts are depletion of fossil resources, carbon
footprint, ionizing radiation, and depletion of abiotic resources
(minerals and metals),</li>
<li>Terminals account for most of the impacts, from 65 to 90%,</li>
<li>Considering every life stage, terminals are responsible for more than 80% of
the depletion of abiotic resources, and about 80% of the carbon footprint,</li>
<li>Considering each device, use is responsible for about 80% of fossil
resource depletion and ionizing radiation, and</li>
<li>Data centers are second only to the terminals, and the manufacture and use of
servers account for about 50% of their impact.</li>
</ul>
<p>For consumers, one of the most obvious takeaways from these conclusions is to
extend the life of their devices as much as possible. As software developers,
we have a role to play in helping them do that: to create software that doesn't
make old devices obsolete.</p>
<p>The power consumption of software depends on the way it is built: the stack
used (programming languages, libraries, and third-party services), the number
and type of features, and how they are implemented. We can then act on their
implementation efficiency, but also on their feature relevance: a feature can
be implemented efficiently, but still be a waste because it's not really useful
to the user. For example, many mobile app trackers aggressively monitor the
user beyond reason: they are a waste of energy.</p>
<p>When it comes to the stack, this is a trickier question because it also depends
on what you know. Over the past decades, we have favored stacks that allow us
to build software quickly, rather than reducing its power consumption. This is
not something we can change in a day. That said, it can guide us in a given
ecosystem (e.g. web client) to choose one framework over another: you may not
need a javascript framework like Vue.js or React when modern CSS can do the
job.</p>
<p>These principles are a bit too vague because they don't give us goals to
achieve. When do we stop? When is enough? If we are serious about delivering
our software on some old hardware, this should be part of the requirements.
That's why I would pick some client hardware that I want to support from the
start. We can then check along the development that it works on those targets.</p>
<p>When it comes to the server, we can follow the same principles and approach. I
would add that we have a word in their choice. Whether it's bare metal or
cloud, I would go with the most common hardware and avoid any exotic hardware.
There are other considerations to take into account, such as the vendor and its
repairability. But that is beyond the scope of this topic, perhaps for a future
time.</p>
<p>There are also things you can't change except not to use them, such as
third-party services or libraries. The rest is about decreasing computing as a
whole.</p>
<p>I'm aware that there are tools, guidelines, and frameworks for improving the
sustainability of IT. They probably start from the same observations. I
still think it's interesting to go down the path myself to develop a deep
understanding of the topic.</p>
<p>What about you? How do you approach this question when you do?</p>
<hr />
<p><strong>Update 28 Apr 2023:</strong></p>
<p>A reader reported to me 2 unclear or wrong sentences:</p>
<blockquote>
<ul>
<li><em>The production of terminals is responsible for more than 80% of the carbon
footprint and the depletion of abiotic resources,</em></li>
<li><em>terminal use is responsible for about 80% of fossil resource depletion and
ionizing radiation, and</em></li>
</ul>
</blockquote>
<p>This was confusing and misrepresented. Here's what I wanted to say originally:</p>
<ul>
<li>Considering every life stage, terminals are responsible for more than 80% of
the depletion of abiotic resources, and about 80% of the carbon footprint,</li>
<li>Considering each device, use is responsible for about 80% of fossil
resource depletion and ionizing radiation, and</li>
</ul>
<p>Also, thanks to the discussion I had with him, I realized that I hadn't clearly
stated that the study focused on France. This means that you can't apply the
ratio to other countries, especially regarding the carbon footprint of use. For
example, Belgian electricity production has a carbon footprint 3 to 4 times
greater than that of France.</p>
<p>The method remains valid and some conclusions can be applied to other countries.
Also, the ratio is not a good way to report these amounts: even if the carbon
footprint of use is larger, the carbon footprint of production is about the
same. We are still starting with a significant "debt", which is increased by
use.</p>
Vega: visualization as code2023-02-17T00:00:00+00:002023-02-17T00:00:00+00:00https://ibakesoftware.com/blog/vega-visualization-as-code/
<p>Today's article will be a short one. I want to share with you a recent discovery:
<a href="https://vega.github.io/">Vega</a>.</p>
<p>In my last <a href="https://ibakesoftware.com/blog/a-naive-approach-of-software-sustainability/">blog post</a>,
I needed to plot some data. I could use a spreadsheet or another web application
and get a sleek visualization. But if I want to make a change, I have to go
back to the tool, make the change, export the result, and so on. This is
tedious, especially if you have tasted the power of tools that let you code
your visualization in the past.</p>
<p>Curious to see how the tools I knew had evolved, I looked at
<a href="http://www.gnuplot.info/">GNUPlot</a>, <a href="https://www.rdocumentation.org/packages/graphics/versions/3.6.2/topics/plot"><code>plot</code> in R</a>,
plotting Python libraries like <a href="https://plotly.com/python/">Plotly</a> or
<a href="https://matplotlib.org/">Matplotlib</a>, or even Javascript ones like
<a href="https://d3js.org/">D3.js</a> or <a href="https://www.chartjs.org/">Chart.js</a>. Some allow
to produce beautiful charts and graphs, but they require to use of a
programming language. I would prefer something declarative and specialized like
GNUPlot. Still thriving and powerful, GNUPlot is a little bit dusty.</p>
<p>After some searching on the web, I found <a href="https://vega.github.io/">Vega</a>, sort of
the modern heir of GNUPlot. The plotting is defined by a JSON file. There is
<a href="https://vega.github.io/vega-lite/">Vega-lite</a>, a concise variant for common
visualization. That just does the job. There is an
<a href="https://vega.github.io/editor/#/custom/vega-lite">online editor</a> to build
the graph interactively . The icing on the cake, there is a Rust CLI tool,
<a href="https://github.com/vega/vl-convert"><code>vl-convert</code></a> to automate the rendering as
SVG or PNG.</p>
<p>So for my previous post, I had this simple plot</p>
<img class="picture" alt="dev vs maintenance" src="https://ibakesoftware.com/blog/a-naive-approach-of-software-sustainability/dev-vs-maintenance.svg"/>
<p>It is the result of the following Vega-lite</p>
<pre data-lang="json" style="background-color:#2b303b;color:#c0c5ce;" class="language-json "><code class="language-json" data-lang="json"><span>{
</span><span> "</span><span style="color:#a3be8c;">$schema</span><span>": "</span><span style="color:#a3be8c;">https://vega.github.io/schema/vega-lite/v5.json</span><span>",
</span><span> "</span><span style="color:#a3be8c;">title</span><span>": "</span><span style="color:#a3be8c;">development to save maintenance</span><span>",
</span><span> "</span><span style="color:#a3be8c;">height</span><span>": </span><span style="color:#d08770;">240</span><span>,
</span><span> "</span><span style="color:#a3be8c;">width</span><span>": </span><span style="color:#d08770;">320</span><span>,
</span><span> "</span><span style="color:#a3be8c;">data</span><span>": {
</span><span> "</span><span style="color:#a3be8c;">values</span><span>": [
</span><span> {"</span><span style="color:#a3be8c;">t</span><span>": "</span><span style="color:#a3be8c;">0</span><span>", "</span><span style="color:#a3be8c;">effort</span><span>": "</span><span style="color:#a3be8c;">0</span><span>", "</span><span style="color:#a3be8c;">name</span><span>": "</span><span style="color:#a3be8c;">maintenance</span><span>"},
</span><span> {"</span><span style="color:#a3be8c;">t</span><span>": "</span><span style="color:#a3be8c;">30</span><span>", "</span><span style="color:#a3be8c;">effort</span><span>": "</span><span style="color:#a3be8c;">30</span><span>", "</span><span style="color:#a3be8c;">name</span><span>": "</span><span style="color:#a3be8c;">maintenance</span><span>"},
</span><span> {"</span><span style="color:#a3be8c;">t</span><span>": "</span><span style="color:#a3be8c;">0</span><span>", "</span><span style="color:#a3be8c;">effort</span><span>": "</span><span style="color:#a3be8c;">0</span><span>", "</span><span style="color:#a3be8c;">name</span><span>": "</span><span style="color:#a3be8c;">maint./2</span><span>"},
</span><span> {"</span><span style="color:#a3be8c;">t</span><span>": "</span><span style="color:#a3be8c;">1</span><span>", "</span><span style="color:#a3be8c;">effort</span><span>": "</span><span style="color:#a3be8c;">1</span><span>", "</span><span style="color:#a3be8c;">name</span><span>": "</span><span style="color:#a3be8c;">maint./2</span><span>"},
</span><span> {"</span><span style="color:#a3be8c;">t</span><span>": "</span><span style="color:#a3be8c;">2</span><span>", "</span><span style="color:#a3be8c;">effort</span><span>": "</span><span style="color:#a3be8c;">5.5</span><span>", "</span><span style="color:#a3be8c;">name</span><span>": "</span><span style="color:#a3be8c;">maint./2</span><span>"},
</span><span> {"</span><span style="color:#a3be8c;">t</span><span>": "</span><span style="color:#a3be8c;">30</span><span>", "</span><span style="color:#a3be8c;">effort</span><span>": "</span><span style="color:#a3be8c;">19.5</span><span>", "</span><span style="color:#a3be8c;">name</span><span>": "</span><span style="color:#a3be8c;">maint./2</span><span>"},
</span><span> {"</span><span style="color:#a3be8c;">t</span><span>": "</span><span style="color:#a3be8c;">0</span><span>", "</span><span style="color:#a3be8c;">effort</span><span>": "</span><span style="color:#a3be8c;">0</span><span>", "</span><span style="color:#a3be8c;">name</span><span>": "</span><span style="color:#a3be8c;">0 maint.</span><span>"},
</span><span> {"</span><span style="color:#a3be8c;">t</span><span>": "</span><span style="color:#a3be8c;">1</span><span>", "</span><span style="color:#a3be8c;">effort</span><span>": "</span><span style="color:#a3be8c;">1</span><span>", "</span><span style="color:#a3be8c;">name</span><span>": "</span><span style="color:#a3be8c;">0 maint.</span><span>"},
</span><span> {"</span><span style="color:#a3be8c;">t</span><span>": "</span><span style="color:#a3be8c;">2</span><span>", "</span><span style="color:#a3be8c;">effort</span><span>": "</span><span style="color:#a3be8c;">16</span><span>", "</span><span style="color:#a3be8c;">name</span><span>": "</span><span style="color:#a3be8c;">0 maint.</span><span>"},
</span><span> {"</span><span style="color:#a3be8c;">t</span><span>": "</span><span style="color:#a3be8c;">30</span><span>", "</span><span style="color:#a3be8c;">effort</span><span>": "</span><span style="color:#a3be8c;">16</span><span>", "</span><span style="color:#a3be8c;">name</span><span>": "</span><span style="color:#a3be8c;">0 maint.</span><span>"}
</span><span> ]
</span><span> },
</span><span> "</span><span style="color:#a3be8c;">mark</span><span>": "</span><span style="color:#a3be8c;">line</span><span>",
</span><span> "</span><span style="color:#a3be8c;">encoding</span><span>": {
</span><span> "</span><span style="color:#a3be8c;">x</span><span>": {"</span><span style="color:#a3be8c;">field</span><span>": "</span><span style="color:#a3be8c;">t</span><span>", "</span><span style="color:#a3be8c;">type</span><span>": "</span><span style="color:#a3be8c;">quantitative</span><span>", "</span><span style="color:#a3be8c;">title</span><span>": "</span><span style="color:#a3be8c;">month</span><span>"},
</span><span> "</span><span style="color:#a3be8c;">y</span><span>": {"</span><span style="color:#a3be8c;">type</span><span>": "</span><span style="color:#a3be8c;">quantitative</span><span>", "</span><span style="color:#a3be8c;">field</span><span>": "</span><span style="color:#a3be8c;">effort</span><span>", "</span><span style="color:#a3be8c;">title</span><span>": "</span><span style="color:#a3be8c;">cumulative effort (in days)</span><span>"},
</span><span> "</span><span style="color:#a3be8c;">color</span><span>": {"</span><span style="color:#a3be8c;">field</span><span>": "</span><span style="color:#a3be8c;">name</span><span>", "</span><span style="color:#a3be8c;">type</span><span>": "</span><span style="color:#a3be8c;">nominal</span><span>"}
</span><span> }
</span><span>}
</span></code></pre>
<p>I could automate the rendering with <code>vl-convert</code></p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">vl-convert</span><span> vl2svg</span><span style="color:#bf616a;"> -i </span><span>"</span><span style="color:#a3be8c;">my-plot.vl</span><span>"</span><span style="color:#bf616a;"> -o </span><span>"</span><span style="color:#a3be8c;">my-plot.svg</span><span>"
</span></code></pre>
<p>which was called each time a change was detected in the Vega-lite file
<code>my-plot.vl</code> (see e.g. <a href="https://github.com/watchexec/watchexec"><code>watchexec</code></a>).</p>
<p>Enjoy!</p>
A naive approach of software sustainability2023-02-06T00:00:00+00:002023-02-06T00:00:00+00:00https://ibakesoftware.com/blog/a-naive-approach-of-software-sustainability/
<p>When developing a piece of software, I had to weigh concerns beyond technical
considerations or its quality. Often it is about its economics, i.e. investing
in its development in order to reduce some cost: maintenance, operation,
support, runtime, ...</p>
<p>For example, you run Software-as-a-Service (SaaS) that requires one day of
maintenance each month. You want to reduce that maintenance, why not get rid of
it? Depending on the amount of work you need to accomplish one or the other.
Let's say you need 4 days of work to cut it in half, but 15 days to get rid of
it.</p>
<img class="picture" alt="dev vs maintenance" src="https://ibakesoftware.com/blog/a-naive-approach-of-software-sustainability/dev-vs-maintenance.svg"/>
<p>It seems reasonable to take the time to get rid of the maintenance, since it's
completely paid off after 16 months. However, this means that you can't use
those 15 days to develop another feature or fix an bug. Depending on the
situation, it might be wiser to cut the maintenance effort in half, leaving
room for other tasks.</p>
<p>Another example is migration. This is the kind of code that you're only going to
run once. When it's done, you're usually not going to use it again. Sure, you
want to make sure it does what it was designed to do. But should you spend a
lot of time on other aspects, such as its maintainability? If it doubles the
work, probably not.</p>
<p>It's the same for all manual tasks of any kind (e.g. development, support,
operations). When should you spend time automating them? In terms of efficiency<sup class="footnote-reference"><a href="#1">1</a></sup>,
the answer is not always positive<sup class="footnote-reference"><a href="#2">2</a></sup>.</p>
<p>Cost is certainly a dominant factor. With the new challenges like climate or
resource constraints, I'd like to take them into account, if not prioritize
them. How should I do that?</p>
<p>Naively, I'd approach it similarly: compare the greenhouse gas footprints
(I'll call them carbon footprints in the following) or the amount of resources
required. In practice, even a rough estimate of either is not as easy as
finding its monetary cost. After trying to estimate the carbon footprint of a
given software (e.g. mobile app, web app) myself, I stumbled over 2 intertwined
obstacles: the software dependencies and the indirect carbon emissions<sup class="footnote-reference"><a href="#3">3</a></sup>.</p>
<p>Most software depends on other software, either to be developed or to run. There
is a deep and long chain of software dependencies. This means that if you want
to account for indirect carbon emissions, you have to go through the
dependencies. If the software is open source, you can find most of them.
Ideally, if each dependency did the same thing, we could estimate the total
indirect carbon emissions. In practice, this information is missing. If the
software is proprietary or run as a service, you don't have access to the
dependencies. It's up to the company building and/or running the software to
disclose this information, if any.</p>
<p>So it's not easy to accurately estimate the carbon footprint of a piece of
software, and I haven't talked about its life cycle yet. Since we don't have
accurate accounting, we have to find another approach.</p>
<p>We can look at existing tools<sup class="footnote-reference"><a href="#4">4</a></sup>. But they are imperfect<sup class="footnote-reference"><a href="#5">5</a></sup>, consider only on
some parts (e.g. client side), are dedicated to a certain category of software
(e.g. web application), work with a certain technology, measure on a given
scenario (e.g. one visit), or use a small sample<sup class="footnote-reference"><a href="#6">6</a></sup>. Even when supported by
scientific work<sup class="footnote-reference"><a href="#7">7</a></sup>, it's important to remember that there is no consensus
among scientists<sup class="footnote-reference"><a href="#8">8</a></sup> yet.</p>
<p>We can use proxies, such as the cost of the infrastructure and the third-party
services used. However, the footprint of 1EUR is not the same in all cases: it
depends on the region of the infrastructure<sup class="footnote-reference"><a href="#9">9</a></sup> or the margin made.</p>
<p>Stepping back, we may not need to go into the details. In fact, there are two
sides to such an exercise. Because we are accustomed to approaching this
question in economic terms, we tend to value both sides as an amount of money.
We have gone so far as to put a price on
<a href="https://en.wikipedia.org/wiki/Health_economics">health</a>. At the end of the day,
it's political, it's a societal choice. When we talk about sustainability, we do
so because we face a global threat. This threat is shaking our society,
including the current economic model. It's not about meeting a standard and
getting a label, it's about standing up for something we believe is good. Of
course, we may not always agree on what is good, but there are some obvious
cases, such as basic needs.</p>
<p>This gives us one side of the balance. For the other side, we can use a simple
proxy: less is better. In fact, the footprint is directly related to usage.
It's reasonable to assume that software A that requires more (machines, energy,
frequency, storage, bandwidth, complexity, people) than software B will have a
higher footprint. Without changing the purpose, you may need to spend more to
reduce some aspects (e.g. development effort to increase performance). It comes
back to comparing the investment and usage footprints: the investment is
interesting if its footprint is covered by the resulting improvement in total
usage. As a consequence, the investment margin evolves with the usage
frequency: the benefit of reducing 1g of GHG 1000 times is the same as the
benefit of reducing 1kg of GHG once.</p>
<p>Let's conclude this already long essay. When approaching the software sustainability, here are the first questions I'd ask:</p>
<ol>
<li>what iss the purpose of the software?</li>
<li>how often will it be used?</li>
<li>how <em>heavy</em> is the software in terms of computing and network resources,
hardware, and dependencies?</li>
<li>how <em>heavy</em> is the software development in terms of design complexity,
required expertise, people, computing and network resources, services and
tools, hardware, and dependencies?</li>
</ol>
<p>The qualitative answers will help to roughly assess the situation and possibly
decide what to do: don't do it, investigate further, do it.</p>
<hr />
<p><strong>Footnotes:</strong></p>
<div class="footnote-definition" id="1"><sup class="footnote-definition-label">1</sup>
<p>When considering automation, there may be other aspects to consider
besides efficiency. For example, knowledge documentation.</p>
</div>
<br/>
<div class="footnote-definition" id="2"><sup class="footnote-definition-label">2</sup>
<p><a href="https://xkcd.com/1205/">Is it worth the time?</a> by xkcd.</p>
</div>
<br/>
<div class="footnote-definition" id="3"><sup class="footnote-definition-label">3</sup>
<p>The indirect carbon emission is all the emission caused by the producers
and the users of the product or service. In the
<a href="https://en.wikipedia.org/wiki/Carbon_accounting#GHG_Protocol">GHG protocol</a>,
it is covered by the <a href="https://ghgprotocol.org/standards/scope-3-standard">scope 3</a>.
In the standard <a href="https://en.wikipedia.org/wiki/ISO_14064">ISO 14064</a>, it
is counted in the Part 1 as indirect emission.</p>
</div>
<br/>
<div class="footnote-definition" id="4"><sup class="footnote-definition-label">4</sup>
<p>For instance, the free <a href="https://ecoindex.fr">ecoIndex</a> or
<a href="https://greenframe.io">GreenFrame</a>.</p>
</div>
<br/>
<div class="footnote-definition" id="5"><sup class="footnote-definition-label">5</sup>
<p>This is well explained by Marmelab in its article
<a href="https://marmelab.com/blog/2020/11/26/argos-sustainable-development.html">"Argos: Measure the Carbon Footprint of Software, Improve Developer Practices"</a>.</p>
</div>
<br/>
<div class="footnote-definition" id="6"><sup class="footnote-definition-label">6</sup>
<p>Whatever you measure, we usually do not know the nature of the system
behind: it might be stochastic, unstable, varying. As such, we can't rely
on one single data point or even 3. Beyond the context of the measurement
(e.g. how, when, what), it's usually a good practice to have enough samples
to draw out any conclusion. In particular when benchmarking the
performance of a software, the result can be affected by many factors such
as the other processes, or the machine health.</p>
</div>
<br/>
<div class="footnote-definition" id="7"><sup class="footnote-definition-label">7</sup>
<p>See for instance the methodology of
<a href="https://mlco2.github.io/codecarbon/methodology.html#">CodeCarbon</a> or
<a href="https://github.com/marmelab/greenframe-cli/blob/main/src/model/README.md">Greenfarm</a>.</p>
</div>
<br/>
<div class="footnote-definition" id="8"><sup class="footnote-definition-label">8</sup>
<p>"The large discrepancies between the various estimates
[of the consumption of data centers] call for a comparison of the
modelling approaches, extrapolations and measurement", p12,
<a href="https://theshiftproject.org/wp-content/uploads/2020/06/2020-06_Did-TSP-overestimate-the-carbon-footprint-of-online-video_EN.pdf">"Did The Shift Project really overestimate the carbon footprint of online video?"</a>,
M. Efoui and J.N. Geist, The Shift Project, June 2020.</p>
</div>
<br/>
<div class="footnote-definition" id="9"><sup class="footnote-definition-label">9</sup>
<p>Knowing the region allows us to find the carbon footprint of the
<a href="https://www.globalpetrolprices.com/energy_mix.php">region's electricity production</a>.</p>
</div>
Yet another beginning2023-01-23T00:00:00+00:002023-01-23T00:00:00+00:00https://ibakesoftware.com/blog/yet-another-beginning/
<p>I won't be the first or the last to change and start something new. I won't be
the first or - hopefully - the last to do so after understanding the challenges
ahead (e.g. climate, resources, energy, biodiversity). Anyway, life could be
seen as a bunch of new beginnings ๐คท. Nothing new.</p>
<p>What's new is what I'm going to do, what I'm going to offer, and what I'm going
to talk about here, on the <a href="https://ibakesoftware.com/blog/">blog</a>. This is what I'm going to talk
about this time ๐ค.</p>
<p>First, let's remember what I've been doing since PullReview. In 2016, I joined a
Belgian IT services company, <a href="https://euranova.eu">Euranova</a>. I did some
consulting work, helped develop the culture and expertise of their software
engineers, and looked for possible products to build and incubate. At the end
of 2017, I started working as the CTO of one of them: <a href="https://digazu.com">Digazu</a>.
We built a platform for data products.</p>
<p>Last September 2022 I left Digazu after 5 years. It wasn't easy, especially
since I really enjoyed working and learning with my teammates. I left because
I was internally in conflict with the paradigm we supported with Digazu: a
world of data abundance. It clashed with my desire for restraint and balance,
as I believe that every ounce of energy and resources (e.g. metals, rare
earths) should be used wisely โ๏ธ.</p>
<p>As scarcity comes, I even believe that the software world will have to change.
Right now, most of the cost of software is the cost of people. Due to the
commoditization of energy and computer hardware parts, the operating costs are
quite low in comparison. You can rent a machine with 2 vCPUs, 8GB RAM and a few
hundred SSDs from a cloud provider for less than 100EUR per month. The price
includes management, maintenance and investment. In comparison, the time of an
employee (e.g. developer, designer, marketer, salesman) costs more than that.
In Europe or USA we can say at least 20 times more. I have often based my
decisions on this difference. I guess I'm not the only one. Tomorrow, will we
continue to use so much computing power when it could cost 10 times more to do
the same job?</p>
<p>I don't want to wait ๐. That's why I want to <a href="https://ibakesoftware.com/work/">focus on projects</a> that
address basic needs (e.g., food, shelter, transportation, education,
healthcare) or emerging global challenges (e.g., climate, biodiversity,
resources, energy). I will then talk about these and some personal ones that do
such.</p>
<p>I have also started to look into the energy, resource, and carbon footprints of
software. This is a topic I'd like to discuss more on the <a href="https://ibakesoftware.com/blog/">blog</a>
and hopefully provide information, critical discussion, or answers to others ๐ฃ.</p>
<p>Cu soon ๐.</p>
A clean up of the website2023-01-18T00:00:00+00:002023-01-18T00:00:00+00:00https://ibakesoftware.com/blog/clean-up-of-the-website/
<p>I know, I know, I've been quiet. I haven't posted anything for a long time. My
last post is from Aug 2016, the <a href="https://ibakesoftware.com/blog/i-bake-software/">first post</a>
under the name <em>"I bake software"</em>. I also wrote one on the blog of
<a href="https://web.archive.org/web/20170923103823/https://www.pullreview.com/">PullReview</a>
to announce <a href="https://ibakesoftware.com/blog/the-end/">its end</a>.</p>
<p>I shared a little though, as I gave a few <a href="https://ibakesoftware.com/talks/">talks</a> (TakeOff Conf 2016,
MyData 2017, ConFoo Montreal 2017 & 2018, Paris.rb 2018, Kafka Summit SF 2019).</p>
<p>As a few things have changed for me, it's a good time to change, clean up, and
revamp the website too ๐.</p>
<p>I'm keeping it as a static website as I want to keep it's cpu/memory/network
bandwith low. But I've switched the generator from Jekyll to
<a href="https://www.getzola.org/">Zola</a>. There isn't any strong arguments behind this
choice except my growning interest for Rust and its style.</p>
<p>In line with the choice of static, I've picked a classless lightweight CSS
framework: <a href="https://igoradamenko.github.io/awsm.css/index.html">awsm.css</a>.</p>
<p>I've replaced the analytics with <a href="https://www.goatcounter.com/">GoatCounter</a>
for its simplicity and its respect for
<a href="https://www.goatcounter.com/help/gdpr">privacy</a>. As such, I don't have to
annoy the visitors with cookie consent.</p>
<p>I've updated the content, mainly the homepage where I explain When can I help.</p>
<p>Rather than exposing my email, I've added a contact form and set up a
<a href="https://formspark.io/">Formspark</a> and <a href="https://botpoison.com/">Botpoison</a>
accounts to forward the message to my email address. Both services are made by
<a href="https://www.bjornkrols.com/">Bjorn Krols</a>. Very lean, neat, and Belgian ๐ซ.</p>
<p>Finally, I've migrated all the old blog posts that I wrote during past ventures.</p>
<p>Enjoy, and see you soon for more news, especially about what happened since 2016,
and what I'm going to do next ๐คซ.</p>
The end.2018-02-14T00:00:00+00:002018-02-14T00:00:00+00:00https://ibakesoftware.com/blog/the-end/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>The first code of PullReview has been pushed in January 2013. We were 3, Martin, Stephan, and I. It was launched in October 2013.
It slowly grew for about 2 years. Life being about choices and decisions, we split, Martin and Stephan taking different roads. I tried
to actively run and grow PullReview alone. After one year, the customer base was not still enough. I decided to find a new adventure and
joined Eura Nova in January 2016. I put PullReview in maintenance mode and slowly reduced the operational cost. The revenue was enough to
cover them. It worked for 2 years. I was happy that I could continue to help developers.</p>
<p>Recently, 2 big customers stopped their subscription. The revenue does not cover the costs anymore. This is the end of PullReview. I'll
stop it next Monday, the 19th February 2018, the free and paying versions. There are good alternatives, I'm sure you'll find one that
suits you.</p>
<p>It was a great adventure, I learned a lot, I could help a lot of developers.</p>
<p>Thank you to all the people that have been a part of it, the family, the friends, the customers, the users. Thanks!</p>
<p>The End.</p>
I Bake Software2016-08-12T00:00:00+00:002016-08-12T00:00:00+00:00https://ibakesoftware.com/blog/i-bake-software/
<p>Recently, I was on the <a href="https://join.slack.com/t/rubyburgers/shared_invite/zt-up6gbx69-V~AaZJq0xtPtCmKMiDBlfg">Ruby Burger chat rooms</a>.
We were discussing a video presenting a company as a great place to work as a software developer. It was full of caricatures such as "ninja".
<a href="https://yannickschutz.com/">Yannick</a>, a friend, was then saying the following:</p>
<blockquote>
<p>We are looking for farmer javascript devs
looking for policeman Java devs</p>
</blockquote>
<p>I realize it resonates a lot with me more than "ninja" or "guru" or
whatever-inadequate-adjective-you-could-find-to-make-it-cool. Since I started to
bake my own :bread:, pancakes, brioches, and so on, I embrace the idea of
software development as a craft.</p>
<p>I'm proud to present myself as a <strong>baker dev</strong>. It inspires me to build the
<a href="/">present personal web site</a>. Enjoy!</p>
Giving Back with 24 Pull Requests2014-12-01T00:00:00+00:002014-12-01T00:00:00+00:00https://ibakesoftware.com/blog/giving-back-with-24pullrequests/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p><strong>What would we do without all those magnificent Gems and Rubies?</strong> Thanks to
the many developers that make them and open their source, we can develop great
apps.</p>
<p><strong>Now is the time to give back.</strong> It's time to say thanks to their authors, to
send them a pull request, to send them back 24 little gifts and join the
<a href="https://24pullrequests.com/">24 Pull Requests movement</a>.</p>
<p>24 Pull Requests is a yearly initiative designed to let you give back little
gifts of code over the holiday season. Just visit
<a href="https://24pullrequests.com/contributing">24pullrequests.com/contributing</a> to
find out how to contribute a pull-request a day in the days leading up to
Christmas.</p>
<p>We at <a href="https://web.archive.org/web/20170923103823/https://www.pullreview.com/">PullReview</a> want to join and support this
initiative. <strong>PullReview can help you contribute</strong>, it can underline and explain
where you could improve the code quality, fix vulnerabilities, or add a missing
test. It can also help the maintainers to review all the contributions and check
at a glance that conventions and contribution guidelines are respected.</p>
<p><strong>If you are a maintainer</strong>, have submitted your project to 24 Pull Requests,
and are interested in checking submitted contributions with PullReview,
just contact me, I'll help you set up
PullReview to do so.</p>
<p><strong>If you want to get help from PullReview to contribute</strong> to open source Ruby
projects on 24 Pull Requests, follow these steps:</p>
<ul>
<li>pick a project on <a href="https://24pullrequests.com/">24 Pull Requests</a>;</li>
<li><a href="https://help.github.com/articles/fork-a-repo/">fork it</a>;</li>
<li>check the contribution guidelines, usually provided in <code>CONTRIBUTING.md</code> or
<code>README.md</code> (PullReview might suggest improvements that go against them),</li>
<li>check existing reviews on the upstream repository (the review of the master
branch is usually linked to the PullReview the badge into the <code>README.md</code>, if
not you can browse it at <code>https://pullreview.com/github/<account>/<repo name>/reviews/master</code> if it exists);</li>
<li>fix issues reported by PullReview (if you add your fork to
<a href="https://web.archive.org/web/20170923103823/https://www.pullreview.com/">PullReview</a>, it will check your modifications and
detect your fixes),</li>
<li><a href="https://help.github.com/articles/creating-a-pull-request/">submit a pull request</a>.</li>
</ul>
<p>If the upstream project is not already on <a href="https://web.archive.org/web/20170923103823/https://www.pullreview.com/">PullReview</a>,
you will have to add your fork to PullReview and push a first commit on the main
branch to get a review on the whole base code.</p>
<p><strong>Last thing</strong>, if you submit 24 pull requests to Ruby projects, we'll have a little
gift for you.</p>
<p><em>Happy coding back <3!</em></p>
PullReview: Shareable Private Review and Test Coverage Integration2014-08-04T00:00:00+00:002014-08-04T00:00:00+00:00https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>It's been a while since <a href="https://ibakesoftware.com/blog/pullreview-badge-and-integration-with-bitbucket-and-gitlab/">the last PullReview news</a>, so it's time to give you some updates.</p>
<p>Over these past three months, <a href="https://xkcd.com/303/">we certainly havenโt been slacking</a> and have brought in a bundle of features, for example:</p>
<ul>
<li><a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#share-review">Share your reviews with your devmates</a></li>
<li><a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#test-coverage">Never miss the chance to cover a code modification with a test</a></li>
<li><a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#custom-notif">Get personalised notifications</a></li>
<li><a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#trends">Know how your tech debt is evolving</a></li>
<li>and lots more
<ul>
<li><a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#filter-file">Filter a review for any given file</a></li>
<li><a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#faster-loading">Faster loading home and review pages</a></li>
<li><a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#auto-mute">Don't be frustrated by some conventions you don't follow</a></li>
<li><a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#cucumber">Don't be afraid to use Cucumber, features are now recognized as tests</a></li>
<li><a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#yearly-subs">You don't need to be bothered by monthly invoices and payments - just subscribe once for the whole year</a></li>
<li><a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#hot-spot">Quickly spot files with the most critical issues in your integration branch</a></li>
<li><a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#slack">Be notified on your Slack room</a></li>
</ul>
</li>
</ul>
<p>Thanks to user bug reports, weโve fixed several bugs and have made PullReview more robust. Thank you and please do continue to report any bugs you encounter. It helps a lot.</p>
<p>Weโve also carried out several upgrades: the usual security upgrades, Rails 4, and others.</p>
<p>We're very proud that PullReview is of use to around 1000 Open Source projects. To list but the most well known: GitLab, Bundler and Cucumber-Rails.</p>
<p>As you may know, we're still bootstrapping the company by offering our development services. If you need help (e.g. developing a Rails app, improving the dev workflow, maintaining a legacy app, learning how to refactor), we'd love to help you out. Just drop us an email!</p>
<p>Below, we'll describe the new features one by one. We'll finish off with some new features that we're looking for a few testers for: <a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#js-review">Get reviews on your JavaScript</a>, and <a href="https://ibakesoftware.com/blog/pullreview-shareable-private-review-and-test-coverage-integration/#fork-review">Get reviews on Pull Requests created from a fork</a>.</p>
<hr />
<h2 id="share-review">Share your reviews with your devmates<a class="zola-anchor" href="#share-review" aria-label="Anchor link for: share-review">๐</a></h2>
<p>It was already possible to share a public review when working with other developers on the same project, it can be useful to share a review: you can request help on a specific issue and can check the status of a PullRequest before reviewing it etc.</p>
<p>Now you can also share a private review with other team members. All they need to do is follow the repo as well. In fact, each team member can find all private reviews on branches they hadnโt actually contributed to on a dedicated page (https://www.pullreview.com/?show_team=true) that can be visited by clicking on the button "Their reviews".</p>
<p><img src="/blog/images/pullreview-their-reviews-button.png" alt="Their Reviews" /></p>
<hr />
<h2 id="test-coverage">Never miss the chance to cover a code modification with a test<a class="zola-anchor" href="#test-coverage" aria-label="Anchor link for: test-coverage">๐</a></h2>
<p>As you know, each time you commit, PullReview helps you not to miss adding a test to your branch.</p>
<p><img src="/blog/images/pullreview-test-infected.png" alt="Test infected!" /></p>
<p>But it's a very simple rule, based on the ratio of modified sources and tests. It works most of the time but it's not precise. What if PullReview could tell you exactly which modification youโre missing out on testing?</p>
<p><img src="/blog/images/pullreview-test-coverage.png" alt="Test coverage" /></p>
<p>As a PullReview customer, we'd like to give you early access to this new feature we shipped in June for private repositories (that some of you have already discovered). This new feature will help you not to miss out on writing a test to cover a change you just made in your code. Basically, PullReview will also read your test coverage reports and tell you if youโre missing covering any code changes (the tests should be run somewhere, for instance by a CI provider).
To enable it, go to your repository page (https://www.pullreview.com/settings/repositories) and follow the setup instructions. Just click on the little list icon on the left of the lock icon. This will only appear for repositories that have been reviewed.</p>
<p><img src="/blog/images/pullreview-test-coverage-setup-button.png" alt="Test coverage setup" /></p>
<hr />
<h2 id="custom-notif">Personalised notifications<a class="zola-anchor" href="#custom-notif" aria-label="Anchor link for: custom-notif">๐</a></h2>
<p>You can be notified by email when, for instance, a new review is ready. Before now, you didn't have this choice. PullReview sent emails to <a href="https://github.com/settings/emails">your primary GitHub email address</a>.</p>
<p>Perhaps your primary GitHub email address is a personal one and you'd prefer to receive reviews of your company repositories on your work email address? Whatever your reasons, you can now select another email address primarily used by PullReview to notify you. Just visit your account page (https://www.pullreview.com/settings/accounts) and choose the email address.</p>
<p><img src="/blog/images/pullreview-select-primary-email.png" alt="Select your primary email" /></p>
<p>Perhaps you work for different organizations and don't want to receive all notifications at the same email address? You can now set up notification routes that basically let you decide for one repo that you want to be notified on that HipChat room, for another organization that you want to be notified on that email address etc.</p>
<p>To set up your notification routes, go to your account page (https://www.pullreview.com/settings/accounts), scroll down to the Notifications pane, uncollapse it, and go to the Notification Center.</p>
<p><img src="/blog/images/pullreview-notification-center.png" alt="Notification Center" /></p>
<p>To add a route, click on the HipChat or Email button, fill in the form and save it.</p>
<p><img src="/blog/images/pullreview-notification-center-form.png" alt="Notification Center Setup" /></p>
<hr />
<h2 id="trends">Know how your tech debt is evolving<a class="zola-anchor" href="#trends" aria-label="Anchor link for: trends">๐</a></h2>
<p>When developing new features or fixing bugs day after day, you can miss the big picture of the state of your technical debt. How is it evolving over the time? Are we managing to keep it stable?</p>
<p>You'll find the answer by visiting the analytics page of your integration branch by clicking on the analytics icon (top right of the list in the review page).</p>
<p><img src="/blog/images/pullreview-analytics-button.png" alt="Analytics Button" /></p>
<p>There you'll find trends for each category at the bottom of the analytics page.</p>
<p><img src="/blog/images/pullreview-trends.png" alt="Trends of your technical Debt" /></p>
<hr />
<h2 id="filter-file">Filter a review for any given file<a class="zola-anchor" href="#filter-file" aria-label="Anchor link for: filter-file">๐</a></h2>
<p>You've just pushed a few changes, reaching a good intermediary milestone. It seems a good time to clean up what has already been done. You look at the corresponding review on PullReview. You decide to start to add documentation, for instance. But you would like to do it file by file rather than jumping around.</p>
<p>It's now possible to filter reviews for a given file:</p>
<ul>
<li>Uncollapse the action, for instance "Add documentation to the following method",</li>
<li>Click on "All issues for this file"</li>
</ul>
<p><img src="/blog/images/pullreview-review-by-file.png" alt="Filter out a review by file" /></p>
<p>You can also do it by yourself by adding the query <code>?file=<filepath></code> at the review URI.</p>
<hr />
<h2 id="faster-loading">Faster loading home and review pages<a class="zola-anchor" href="#faster-loading" aria-label="Anchor link for: faster-loading">๐</a></h2>
<p>Thereโs nothing more frustrating than waiting for a webpage to load. It just looks like things have broken. Weโve had several loading performance issues with long reviews. Weโve made several improvements such as caching or partial loading and have managed to reduce the loading time for some large review pages from over one minute down to a few seconds. We've reached an acceptable thread-off for now. If you experience very slow web page loading, please let us know. Thereโs nothing better than real cases to improve performance.</p>
<hr />
<h2 id="auto-mute">Don't be frustrated by conventions you don't follow<a class="zola-anchor" href="#auto-mute" aria-label="Anchor link for: auto-mute">๐</a></h2>
<p>In most cases, there is no right or wrong code style. What matters is to have and follow one. For instance, the <a href="https://github.com/bbatsov/ruby-style-guide#consistent-string-literals">usage of single or double quotes for string literal quotes</a>.</p>
<p>We have observed two rules of the Ruby Style Guide followed by PullReview that are debatable: <a href="https://github.com/bbatsov/ruby-style-guide#consistent-string-literals">double vs. single quotes</a> and <a href="https://github.com/bbatsov/ruby-style-guide#hash-literals">Hash literal syntax</a>. As a consequence, people were inundated with reviews when they werenโt following them. Not very meaningful.</p>
<p>For that reason, PullReview can now detect when you arenโt following them and will inform you that it has ignored the rule.</p>
<p><img src="/blog/images/pullreview-auto-mute-example.png" alt="Double quote rule automatically ignored" /></p>
<hr />
<h2 id="cucumber">Don't be afraid to use Cucumber, features are now recognized as tests<a class="zola-anchor" href="#cucumber" aria-label="Anchor link for: cucumber">๐</a></h2>
<p>In addition to classic test and spec files, PullReview can now recognize your Cucumber features as tests.</p>
<hr />
<h2 id="yearly-subs">You don't need to be bothered by monthly invoices and payments - just subscribe once for the whole year<a class="zola-anchor" href="#yearly-subs" aria-label="Anchor link for: yearly-subs">๐</a></h2>
<p>Who enjoys matching invoice to payment when doing the accounting? Because the answer to that is no one, we now offer a yearly subscription. It means just one payment and invoice per year. If you are interested in a yearly subscription, just send us an email.</p>
<hr />
<h2 id="hot-spot">Quickly spot files with the most critical issues in your integration branch<a class="zola-anchor" href="#hot-spot" aria-label="Anchor link for: hot-spot">๐</a></h2>
<p>For an integration branch, PullReview reviews the whole code base. Depending on the project story, the resulting review could be quite long. So how could that be useful? So far, you canโt say where to start refactoring.</p>
<p>PullReview can now tell you what the hotspots are, i.e. files with the most critical problems.</p>
<p><img src="/blog/images/pullreview-hotspots.png" alt="Hotspots" /></p>
<p>For instance, on the master branch of Bundler, the hottest spot is <code>definition.rb</code>.</p>
<p>You'll just get hotspots on new reviews for integration branch, not on old ones.</p>
<hr />
<h2 id="slack">Be notified on your Slack room<a class="zola-anchor" href="#slack" aria-label="Anchor link for: slack">๐</a></h2>
<p>To inform you when a review is ready, PullReview can send you an email, leave you a message in a HipChat room, or update the GitHub Status or badge. It can also do it now by leaving you a message in a Slack room.</p>
<p><img src="/blog/images/pullreview-slack-example.png" alt="Example of a Slack notification" /></p>
<p>Simply go to your account page (https://www.pullreview.com/settings/accounts#notification) and set up a new notification route.</p>
<p><img src="/blog/images/pullreview-slack-setup-form.png" alt="Add a Slack notification" /></p>
<hr />
<h2 id="js-review">Get reviews on your JavaScript<a class="zola-anchor" href="#js-review" aria-label="Anchor link for: js-review">๐</a></h2>
<p>When you develop a Rails app, you write the code in Ruby, but you can also write it in JavaScript. That's why PullReview will also review your JavaScript code. This is still in Beta and we're looking for more testers. If you're interested in testing it, send us an email.</p>
<hr />
<h2 id="fork-review">Get reviews on Pull Requests created from a fork<a class="zola-anchor" href="#fork-review" aria-label="Anchor link for: fork-review">๐</a></h2>
<p>When you're developing and maintaining an open source project, it takes a lot of time to review and check each PullRequest. Unfortunately, PullReview didn't used to review PullRequests coming from a fork. This meant that a lot of open source maintainers couldnโt use PullReview to check them.</p>
<p>But PullReview can now review them. It's in Beta and we're looking for testers. If you have to check and review a lot of PullRequests coming from a fork and would like to test this new feature, just send us an email.</p>
<hr />
<h2 id="happy-summer">Happy Summer!<a class="zola-anchor" href="#happy-summer" aria-label="Anchor link for: happy-summer">๐</a></h2>
<p>It's summertime and time to take some days off.</p>
<p>Sunny days are back for most of us, always a great time to get out, spend time with friends and family, and leave codes behind you.</p>
<p>About a year ago, we launched the alpha version of PullReview. How time flies! Back then, there were about twenty users. There are now around a thousand of you! Thank you very much, we hope to continue to help you and others.</p>
<p>We're here if you ever have any questions or need anything. [ust drop us an email, we read all our messages personally.</p>
When is your code DRY enough?2014-04-25T00:00:00+00:002014-04-25T00:00:00+00:00https://ibakesoftware.com/blog/when-is-your-code-dry-enough/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>You're aware that <a href="https://ibakesoftware.com/blog/duplication-is-a-rampant-disease/">duplication is a rampant disease</a>: more code, more fragile, less maintainable, less readable. You even use <a href="http://ruby.sadi.st/Flay.html">one</a> or <a href="https://web.archive.org/web/20170923103823/https://www.pullreview.com/">another tool</a> and make your code reviewed to find most of them.</p>
<p><strong>When facing some duplicate code, you're not always feeling comfortable to dry it up.</strong> You're not even sure you'll keep - as is - the code you've just wrote. By experience, you don't want to spend a whole day to end, maybe, with an abstract solution end to reason about.</p>
<p>Should you avoid similar <em>create</em> actions in different Rails controllers? Should you use metaprogramming and avoid long similar case expressions? What about recurring pattern in your Rails routes? Or multiple repetitions in your specs? When should I stop?</p>
<p>You're right to wonder if it's right or not. Reducing duplication is not only time consuming but it could make your code less readable. Eventually, you want to make your code more maintainable, not less.</p>
<p><strong><a href="http://en.wikipedia.org/wiki/Dont_repeat_yourself">DRY</a> is not about identical chunks of bits or characters in different places. DRY aims at not repeating domain concepts</strong>. If not, there is a risk that some copy of a domain concept won't be maintained properly. For instance, when implementing invoicing, you want the calculation of VAT implemented in only one place. By doing so, if it changes, there is only one place to change.</p>
<p>When removing duplications that doesn't belong to the same domain concept, it's likely that you'll come with a wrong abstraction. If one of the factored domain changes, it will affect the abstraction and every dependencies that has then to be handled as exceptions. Moreover, the code will be hard to understand and to debug, especially if you use metaprogramming.</p>
<p>In order to know when you should dry your code, you could follow the rule of thumb <a href="http://c2.com/cgi/wiki?ThreeStrikesAndYouRefactor">Three Strikes And You Refactor</a>. <strong>I personally apply a more specific approach</strong>:</p>
<ol>
<li>when implementing a feature, code without worrying about duplication (in a dedicated branch)</li>
<li>when you've reached a stable implementation, before merging it, check for duplication (thanks to you, code review, a tool)</li>
<li>for each found duplication
<ul>
<li>don't remove it if
<ul>
<li>you don't - yet - understand them as duplicated concepts</li>
<li>explicit code is more important as in tests</li>
<li>the solution is complex and hard to understand</li>
</ul>
</li>
<li>otherwise remove it</li>
</ul>
</li>
</ol>
<p>In any case, if you find a recurring pattern in your code more than three times, it should particularly gains your attention.</p>
<p>If you feel uncertain, it's better to let the duplication for the moment. Then, if possible, discuss it during the code review. The reviewer will maybe come with another perspective helping you to come with a good abstraction.</p>
PullReview: Badge and integration with BitBucket and GitLab2014-04-16T00:00:00+00:002014-04-16T00:00:00+00:00https://ibakesoftware.com/blog/pullreview-badge-and-integration-with-bitbucket-and-gitlab/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p><a href="https://web.archive.org/web/20170923103823/https://www.pullreview.com/">PullReview</a> recently gets a few new features:</p>
<ul>
<li>Badge</li>
<li>Public Review for Public Repo</li>
<li>BitBucket and GitLab</li>
<li>and lots more:
<ul>
<li>HipChat notification</li>
<li>Performance of the home page</li>
<li>Profile</li>
<li>Heartbleed</li>
<li>Support Contact</li>
</ul>
</li>
</ul>
<hr />
<h2 id="badge">Badge<a class="zola-anchor" href="#badge" aria-label="Anchor link for: badge">๐</a></h2>
<p>Badges in README.md are a very common way to inform people about your project good health. PullReview now provides its own badges:</p>
<p><img src="/blog/images/badge1.png" alt="badge PullReview KO" /></p>
<p><img src="/blog/images/badge2.png" alt="badge PullReview OK" /></p>
<p>Each badge presents a brief status as following:</p>
<ul>
<li>โ the number of detected issues</li>
<li>โ the number of fixed issues</li>
<li>(+ the number of issues fixed since the previous review)</li>
</ul>
<p>It will be colored depending on the progress:</p>
<ul>
<li>red if
<ul>
<li>more issues have just been added than fixed</li>
<li>there are more to fix than fixed</li>
</ul>
</li>
<li>otherwise it will be green</li>
</ul>
<p>When you click on the badge you'll then access the corresponding review page.</p>
<p>You'll find the link and the markdown snippet for the badge just below the review title by clicking "Badge urls".</p>
<p><img src="/blog/images/badge-urls.png" alt="badge-urls" /></p>
<p>The badges are also available for private repositories. In that case, the URI also contains a unique token given the access to the badge. The URI is then enough in itself to see the badge (but only the badge). Share it carefully.</p>
<p>Share your badge and show off all your improvements!</p>
<hr />
<h2 id="public-repositories-reviews-are-now-public">Public Repositories reviews are now public<a class="zola-anchor" href="#public-repositories-reviews-are-now-public" aria-label="Anchor link for: public-repositories-reviews-are-now-public">๐</a></h2>
<p>You can now share the URI of your review with anybody, and they will have access to your review. For instance, by clicking on a badge, a person can visit your review and discover its details. All the details are shared except the security vulnerabilities. To avoid premature disclosure, those ones are only readable by the owner of the review.</p>
<hr />
<h2 id="bitbucket-and-gitlab-support">BitBucket and GitLab support<a class="zola-anchor" href="#bitbucket-and-gitlab-support" aria-label="Anchor link for: bitbucket-and-gitlab-support">๐</a></h2>
<p>It's now possible to review a repo hosted either on BitBucket or on GitLab. On the list of repositories (https://www.pullreview.com/settings/repositories), click on the button "Add a repository"</p>
<p><img src="/blog/images/add-repo-button.png" alt="add-repo-button" /></p>
<p>Then fill the form to add your BitBucket or GitLab repo:</p>
<p><img src="/blog/images/add-repo-form.png" alt="add-repo-form" /></p>
<p>Notice, that it's also possible for GitHub repository when you didn't grant us enough permission to retrieve the list of your repositories, and add deploy key and webhook.</p>
<p>For BitBucket as for GitHub, you can also grant us some permission that will ease your setup: retrieving the list of all your repositories and one-click setup adding deploy key and webhook.</p>
<p><img src="/blog/images/bitbucket-auth.png" alt="bitbucket-auth" /></p>
<hr />
<h2 id="hipchat-notification">HipChat notification<a class="zola-anchor" href="#hipchat-notification" aria-label="Anchor link for: hipchat-notification">๐</a></h2>
<p>HipChat is one of the great chat applications. It's really a great way to communicate but also to be notified of everything that happens inside your team. In addition to Email and GitHub Status, you can now be notified directly into your HipChat room when a review is ready. Just go on your account page (https://www.pullreview.com/settings/accounts), browse the Notification tab, and setup the connection with HipChat</p>
<p><img src="/blog/images/hipchat-form.png" alt="hipchat-form" /></p>
<hr />
<h2 id="performance-of-the-home-page">Performance of the home page<a class="zola-anchor" href="#performance-of-the-home-page" aria-label="Anchor link for: performance-of-the-home-page">๐</a></h2>
<p>We've improved the performance of the home page with the list of available reviews. For some of you, it will make a big difference as it's no more slowed down by the size of your reviews.</p>
<p>We're working now on the performance of the review page.</p>
<hr />
<h2 id="profile">Profile<a class="zola-anchor" href="#profile" aria-label="Anchor link for: profile">๐</a></h2>
<p>As you may have noticed, there is now a profile page (https://www.pullreview.com/settings/profile)</p>
<p><img src="/blog/images/profile.png" alt="profile" /></p>
<p>Stay tuned - more and more metrics, awards and badges coming your way in the next weeks.</p>
<hr />
<h2 id="heartbleed">HeartBleed<a class="zola-anchor" href="#heartbleed" aria-label="Anchor link for: heartbleed">๐</a></h2>
<p>You've certainly heard of <a href="http://heartbleed.com/">HeartBleed</a> <a href="https://en.wikipedia.org/wiki/Heartbleed">vulnerability</a>. We've already took several measures including:</p>
<ul>
<li>We've upgraded all our systems to use the newer and protected version of OpenSSL. We did it on the productions servers the day just after the vulnerability became public.</li>
<li>We've reissued new SSL Certificates and revoked the old ones.</li>
</ul>
<p>We're still working on the issue, but on less urgent side effects.</p>
<p>For <a href="https://github.com/blog/1818-security-heartbleed-vulnerability">GitHub</a>, <a href="http://blog.bitbucket.org/2014/04/09/all-heartbleed-upgrades-are-now-complete/">BitBucket</a>, and <a href="https://about.staging.gitlab.com/releases/2014/04/08/omnibus-packages-patched-against-cve-2014-0160/">GitLab</a>, we advise you to read their respective blog post on the topic. In addition, as PullReview relies on GitHub for login, we recommend you to follow their <a href="https://github.com/blog/1818-security-heartbleed-vulnerability">recommendations</a>:</p>
<ul>
<li><a href="https://github.com/settings/admin">Change your GitHub password</a>. Be sure your password is strong; for more information, see <a href="https://help.github.com/articles/what-is-a-strong-password">What is a strong password?</a></li>
<li><a href="https://help.github.com/articles/about-two-factor-authentication">Enable Two-Factor Authentication</a>.</li>
<li><a href="https://help.github.com/articles/updating-your-github-access-credentials">Revoke and recreate personal access and application tokens</a>.</li>
</ul>
<hr />
<h2 id="support-contact">Support Contact<a class="zola-anchor" href="#support-contact" aria-label="Anchor link for: support-contact">๐</a></h2>
<p>If you need support, have any questions, comments or feedback, there are several ways to contact us:</p>
<ul>
<li>by email</li>
<li>by Twitter: <code>@pullreview</code></li>
<li>by the in-app conversation system: just click on the mail icon <img src="/blog/images/inapp-message.png" alt="inapp-message" /> when you're logged in</li>
</ul>
<hr />
<h2 id="happy-spring">Happy Spring!<a class="zola-anchor" href="#happy-spring" aria-label="Anchor link for: happy-spring">๐</a></h2>
<p>The sunny days are back for most of us. Always a great time to get out, spend time with friends and family, and leave the code behind you.</p>
<p>We're here if you have any questions or need anything. As listed above, there are plenty of way to reach us.</p>
7 daily use cases of Ruby String2014-04-11T00:00:00+00:002014-04-11T00:00:00+00:00https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-string/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>Strings are everywhere. You deal with <code>String</code> instances not only every day, but probably every minute. They came from files, databases, REST APIs, or you simply use them to print results. It's a pervasive representation, and Ruby provides <a href="http://www.ruby-doc.org/core-2.1.0/String.html">plenty to ease its manipulation</a>. But <code>String</code> comes with its own share of problems and you won't always find a quick solution in the doc like how to deal with invalid byte sequence or convert back a <code>String</code> to a Date with an uncommon format.</p>
<p>Below, I share 7 common use cases of <code>String</code> I met very often and should be useful to you.</p>
<ol>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-string/#one">How to remove enclosing characters like parenthesis?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-string/#two">How to compare two Strings insensitively?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-string/#three">How to clean a <code>String</code> by removing newline, carriage return, leading and trailing spaces?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-string/#four">How to convert a <code>String</code> to a Regexp?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-string/#five">How to convert a <code>String</code> to a Date with uncommon format?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-string/#six">How to remove accents?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-string/#seven">How to clean up invalid byte sequences?</a></li>
</ol>
<h2 id="one">1. How to remove enclosing characters like parenthesis?<a class="zola-anchor" href="#one" aria-label="Anchor link for: one">๐</a></h2>
<p>You retrieve data from a file:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>line = '</span><span style="color:#a3be8c;">(this is a data from the file)</span><span>'
</span></code></pre>
<p>The data is always wrapped by () that you don't want. You can get the data without them as following:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>line[</span><span style="color:#d08770;">1</span><span>..-</span><span style="color:#d08770;">2</span><span>]
</span><span style="color:#65737e;"># => 'this is a data from the file'
</span></code></pre>
<p>This actually removes the first and last characters of the <code>String</code>.</p>
<p><strong>reference:</strong> <a href="http://www.ruby-doc.org/core-2.1.0/String.html#method-i-5B-5D">String#[]</a>, <a href="http://www.ruby-doc.org/core-2.1.0/String.html#method-i-slice">String#slice</a></p>
<h2 id="two">2. How to compare two Strings insensitively?<a class="zola-anchor" href="#two" aria-label="Anchor link for: two">๐</a></h2>
<p>In an online shop, the user can search for product by their name:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>products = [
</span><span> "</span><span style="color:#a3be8c;">Banana</span><span>",
</span><span> "</span><span style="color:#a3be8c;">Apple</span><span>",
</span><span> "</span><span style="color:#a3be8c;">Orange</span><span>"
</span><span>]
</span><span style="color:#65737e;"># ...
</span><span>
</span><span>search_string = "</span><span style="color:#a3be8c;">apple</span><span>"
</span></code></pre>
<p>You don't want to force your users to be case sensitive (they arenโt), so you can do:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>products.</span><span style="color:#96b5b4;">select </span><span>{ |</span><span style="color:#bf616a;">product</span><span>| product.casecmp(search_string) == </span><span style="color:#d08770;">0 </span><span>}
</span><span style="color:#65737e;"># => ["Apple"]
</span></code></pre>
<p>As pointed out by <a href="http://apeiros.me/">apeiros</a> in the comments, it wonโt work for any non-ASCII characters. So, a better version would be:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>products.</span><span style="color:#96b5b4;">select </span><span>{ |</span><span style="color:#bf616a;">product</span><span>| product =~ /#{</span><span style="color:#ebcb8b;">Regexp</span><span>.escape(search_string)}/</span><span style="color:#b48ead;">i </span><span>}
</span><span>
</span></code></pre>
<p><strong>reference:</strong> <a href="http://www.ruby-doc.org/core-2.1.0/String.html#method-i-casecmp">String#casecmp</a></p>
<h2 id="three">3. How to clean a String by removing newline, carriage return, leading and trailing spaces?<a class="zola-anchor" href="#three" aria-label="Anchor link for: three">๐</a></h2>
<p>In a little script, you read data from the console:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>command = </span><span style="color:#96b5b4;">gets
</span></code></pre>
<p>You can clean up what you read by simply doing:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>command = </span><span style="color:#96b5b4;">gets</span><span>.strip
</span></code></pre>
<p>Thanks to <a href="http://apeiros.me/">apeiros</a> for making me notice that <code>strip</code> removes also trailing newline and carriage return. It's not needed to use <code>chomp</code>.</p>
<p><strong>reference:</strong> <a href="http://www.ruby-doc.org/core-2.1.0/String.html#method-i-chomp">String#chomp</a>, <a href="http://www.ruby-doc.org/core-2.1.0/String.html#method-i-strip">String#strip</a></p>
<h2 id="four">4. How to convert a String to a Regexp?<a class="zola-anchor" href="#four" aria-label="Anchor link for: four">๐</a></h2>
<p>You're developing a Gem that maintains a database of locations of files. In the configuration file, the user can blacklist specific pathnames with regular expressions. You retrieved one of them (you don't want to locate the files in your trash):</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>blacklisted_pathname = "</span><span style="color:#96b5b4;">\.\/\.</span><span style="color:#a3be8c;">trash</span><span>"
</span><span>
</span></code></pre>
<p>You can then use it to directly check:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>file_paths.</span><span style="color:#96b5b4;">select </span><span>{ |</span><span style="color:#bf616a;">file_path</span><span>| !(file_path =~ /#{blacklisted_pathname}/) }
</span></code></pre>
<p>or keep it for later:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>r = </span><span style="color:#ebcb8b;">Regexp</span><span>.</span><span style="color:#8fa1b3;">new</span><span> blacklisted_pathname
</span></code></pre>
<p>Don't forget to correctly escaping in your <code>String</code>, or even better, use <code>Regexp.escape</code> as suggested by <a href="http://apeiros.me/">apeiros</a>.</p>
<p><strong>reference:</strong> <a href="http://www.ruby-doc.org/core-2.1.1/Regexp.html#method-c-new">Regexp#new</a>, <a href="http://www.ruby-doc.org/core-2.1.1/doc/syntax/literals_rdoc.html#label-Regular+Expressions">Regular Expressions literal and interpolation</a></p>
<p><strong>Aside note:</strong> for that particular use case, you should probably use <a href="http://ruby-doc.org/core-2.1.1/File.html#method-c-fnmatch">File#fnmatch</a></p>
<h2 id="five">5. How to convert a String to a Date with uncommon format?<a class="zola-anchor" href="#five" aria-label="Anchor link for: five">๐</a></h2>
<p>In an old database, the dates are stored as <code>String</code> as following:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>date = "</span><span style="color:#a3be8c;">1979;4;2</span><span>"
</span></code></pre>
<p>You can convert it as a Date as following:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#ebcb8b;">Date</span><span>.strptime(date, "</span><span style="color:#d08770;">%Y</span><span style="color:#a3be8c;">;</span><span style="color:#d08770;">%m</span><span style="color:#a3be8c;">;</span><span style="color:#d08770;">%d</span><span>")
</span><span style="color:#65737e;"># => ;
</span><span>
</span></code></pre>
<p><strong>reference:</strong> <a href="http://www.ruby-doc.org/stdlib-2.1.1/libdoc/date/rdoc/Date.html#method-c-strptime">Date#strptime</a></p>
<h2 id="six">6. How to remove accents?<a class="zola-anchor" href="#six" aria-label="Anchor link for: six">๐</a></h2>
<p>You're building a web app and you'd like to allow a quick search among the members like</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>"</span><span style="color:#a3be8c;">Kurt Gรถdel</span><span>"
</span></code></pre>
<p>Accents and diacritics could be easily forgotten, and you want to remove them from the searched string. You can do it easily with ActiveSupport</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#8fa1b3;">require </span><span>"</span><span style="color:#a3be8c;">active_support/inflector</span><span>" </span><span style="color:#65737e;"># not necessary if Rails
</span><span>
</span><span style="color:#ebcb8b;">ActiveSupport</span><span>::</span><span style="color:#ebcb8b;">Inflector</span><span>.transliterate("</span><span style="color:#a3be8c;">Kurt Gรถdel</span><span>")
</span><span style="color:#65737e;"># => 'Kurt Godel'
</span></code></pre>
<p><strong>reference:</strong> <a href="http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-transliterate">Inflector#transliterate</a></p>
<h2 id="seven">7. How to clean up invalid byte sequences?<a class="zola-anchor" href="#seven" aria-label="Anchor link for: seven">๐</a></h2>
<p>You read a text File encoded in UTF-8. You manipulate each of its line, but at some point you get the error</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#a3be8c;">ArgumentError:</span><span> invalid byte sequence </span><span style="color:#b48ead;">in </span><span style="color:#bf616a;">UTF</span><span>-</span><span style="color:#d08770;">8
</span></code></pre>
<p>on the line</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>line = '</span><span style="color:#a3be8c;">This is an invalid byte sequence 44</span><span>'
</span><span style="color:#65737e;"># => 'This is an invalid byte sequence \xA4'
</span></code></pre>
<p>Well, you need to clean up your line before working on it by using <code>scrub</code>:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#65737e;"># if < 2.1, use the backport gem string-scrub
</span><span style="color:#65737e;"># by adding to your Gemfile
</span><span style="color:#65737e;"># gem "string-scrub"
</span><span style="color:#65737e;"># if >= 2.1, it"s part of String (yeah \o/)
</span><span>
</span><span>line.scrub!("")
</span><span style="color:#65737e;"># => 'This is an invalid byte sequence '
</span></code></pre>
<p>Old way:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>line.encode!("</span><span style="color:#a3be8c;">UTF-8</span><span>", "</span><span style="color:#a3be8c;">binary</span><span>", </span><span style="color:#a3be8c;">invalid: :replace</span><span>, </span><span style="color:#a3be8c;">undef: :replace</span><span>, </span><span style="color:#a3be8c;">replace: </span><span>"")
</span><span style="color:#65737e;"># => 'This is an invalid byte sequence'
</span></code></pre>
<p>But if you have non-ASCII characters, it will remove them. In that case, you should go for a solution as <a href="https://gist.github.com/apeiros/5748037">apeiros' one.</a></p>
<p><strong>references:</strong> <a href="http://www.ruby-doc.org/core-2.0.0/String.html#method-i-encode-21">String#encode!</a>, <a href="http://www.ruby-doc.org/core-2.1.0/String.html#method-i-scrub-21">String#scrub!</a> (2.1)</p>
<p><strong>read also:</strong> <a href="http://robots.thoughtbot.com/fight-back-utf-8-invalid-byte-sequences">Fight Back UTF-8 Invalid Byte Sequences</a></p>
<h2 id="what-s-your-daily-use-cases-of-strings">What's your daily use cases of Strings?<a class="zola-anchor" href="#what-s-your-daily-use-cases-of-strings" aria-label="Anchor link for: what-s-your-daily-use-cases-of-strings">๐</a></h2>
<p>Compared with daily use cases of <a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-array/">Array</a>, <a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-hash/">Hash</a>, or Regexp, some for <code>String</code> are very basic, but very common. I love how Ruby allows you to deal with slicing for instance. It's very elegant.</p>
<p>Whatโs yours? What are your typical daily use cases of <code>String</code> and elegant Ruby to resolve them?</p>
When should I use a Set in Ruby?2014-04-04T00:00:00+00:002014-04-04T00:00:00+00:00https://ibakesoftware.com/blog/when-should-i-use-a-set-in-ruby/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>You develop a small contact manager for a client.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>Contact = </span><span style="color:#ebcb8b;">Struct</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#a3be8c;">:name</span><span>, </span><span style="color:#a3be8c;">:email</span><span>)
</span></code></pre>
<p>One important feature is the possibility to define a list of contacts.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>granny = </span><span style="color:#ebcb8b;">Contact</span><span>.</span><span style="color:#8fa1b3;">new</span><span>('</span><span style="color:#a3be8c;">granny</span><span>', '</span><span style="color:#a3be8c;">granny@weatherwax.me</span><span>')
</span><span>bill = </span><span style="color:#ebcb8b;">Contact</span><span>.</span><span style="color:#8fa1b3;">new</span><span>('</span><span style="color:#a3be8c;">bill</span><span>', '</span><span style="color:#a3be8c;">bill@door.me</span><span>')
</span></code></pre>
<p>At first, you started with an array,</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>contacts = []
</span></code></pre>
<p>but you realize quickly that you have to check for duplicates. You end in many places with something like:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>contacts << granny </span><span style="color:#b48ead;">unless</span><span> contacts.</span><span style="color:#96b5b4;">include?</span><span> granny
</span></code></pre>
<p>or</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>contacts.uniq!
</span></code></pre>
<p>Last time you were working with the list, you needed to send a campaign email to each contact:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>contacts << granny
</span><span style="color:#65737e;"># => [granny]
</span><span>
</span><span>contacts << granny
</span><span style="color:#65737e;"># => [granny, granny]
</span><span>
</span><span>contacts << bill
</span><span style="color:#65737e;"># => [granny, granny, bill]
</span><span>
</span><span style="color:#65737e;"># โฆ
</span><span>
</span><span>contacts.each </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">contact</span><span>|
</span><span> contact.send_campaign </span><span style="color:#65737e;"># oups!
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>You forgot to check for duplicates, you shipped it, and <em>the campaign was sent twice to granny</em>!</p>
<p>You don't like that, and you're right. Indeed, the <strong>code is fragile</strong>: you shouldn't watch for the uniqueness constraint, it should be built in.</p>
<p>If you need a collection with uniqueness guaranteed, use a <a href="http://www.ruby-doc.org/stdlib-2.1.1/libdoc/set/rdoc/Set.html"><code>Set</code></a>:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#8fa1b3;">require </span><span>'</span><span style="color:#a3be8c;">set</span><span>'
</span><span>
</span><span style="color:#65737e;">#...
</span><span>
</span><span>contacts = </span><span style="color:#ebcb8b;">Set</span><span>.</span><span style="color:#8fa1b3;">new
</span><span>
</span><span style="color:#65737e;"># ...
</span><span>
</span><span>contacts << granny
</span><span style="color:#65737e;"># => {granny}
</span><span>
</span><span>contacts << granny
</span><span style="color:#65737e;"># => {granny}
</span><span>
</span><span>contacts << bill
</span><span style="color:#65737e;"># => {granny, bill}
</span><span>
</span><span>contacts.each </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">contact</span><span>|
</span><span> contact.send_campaign </span><span style="color:#65737e;"># yeah!
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>Of course, <code>Array</code> is a fine structure too - if duplicates are allowed or you need to access the n <em>th</em> element. In the end, you should work with classes properly representing your data: they will behave as you expect. In 99%, it's more important than performance consideration, or you'll end with fragile code.</p>
7 daily use cases of Ruby Hash2014-03-14T00:00:00+00:002014-03-14T00:00:00+00:00https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-hash/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>Everyday, you deal with Hashes. We use a lot of them everyday when coding <a href="https://web.archive.org/web/20170923103823/https://www.pullreview.com/">PullReview</a>, from Rails infamous <code>params</code> to the various data we get from the GitHub <code>JSON</code> API.</p>
<p>Creating a new <code>Hash</code> or retrieving an element by its key, are common and simple to do. But when you need to merge 2 nested <code>Hash</code>es or filter some keys from one, you need to think a little about it. In the great <a href="http://ruby-doc.org/">doc</a>, you'll find plenty of explanations for <a href="http://www.ruby-doc.org/core-2.1.0/Hash.html">each method of <code>Hash</code></a>. As it's not case oriented, you won't quickly find how to resolve it. Below, I share 7 common use cases of Hash I met very often and should be useful to you.</p>
<ol>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-hash/#json-to-hash">How to convert a <code>JSON</code> into a <code>Hash</code>?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-hash/#hash-to-json">How to convert a <code>Hash</code> into a <code>JSON</code>?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-hash/#default-value">How to set default value for a nested <code>Hash</code>?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-hash/#merge">How to merge two nested <code>Hash</code>es?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-hash/#filter">How to filter out some keys of a <code>Hash</code>?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-hash/#sort">How to "sort" a <code>Hash</code> by value?</a></li>
<li><a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-hash/#diff">How to find the differences between two <code>Hash</code>es?</a></li>
</ol>
<hr />
<h2 id="json-to-hash">1. How to convert a JSON into a Hash?<a class="zola-anchor" href="#json-to-hash" aria-label="Anchor link for: json-to-hash">๐</a></h2>
<p>You've just retrieved a Twitter profile as a <code>JSON</code>:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>data = "</span><span style="color:#a3be8c;">{
</span><span style="color:#a3be8c;"> 'name': 'Aaron Patterson',
</span><span style="color:#a3be8c;"> 'screen</span><span style="color:#96b5b4;">\_</span><span style="color:#a3be8c;">name': 'tenderlove',
</span><span style="color:#a3be8c;"> 'location': 'Seattle, WA'
</span><span style="color:#a3be8c;">}</span><span>"
</span></code></pre>
<p>You want to transform it as a <code>Hash</code> for easier data manipulation:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#8fa1b3;">require </span><span>"</span><span style="color:#a3be8c;">json</span><span>"
</span><span>
</span><span>profile = </span><span style="color:#ebcb8b;">JSON</span><span>.parse(data)
</span></code></pre>
<p><strong>IRB Output:</strong></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>
</span><span>=> {
</span><span> '</span><span style="color:#a3be8c;">name</span><span>'=>'</span><span style="color:#a3be8c;">Aaron Patterson</span><span>',
</span><span> '</span><span style="color:#a3be8c;">screen\_name</span><span>'=>'</span><span style="color:#a3be8c;">tenderlove</span><span>',
</span><span> '</span><span style="color:#a3be8c;">location</span><span>'=>'</span><span style="color:#a3be8c;">Seattle, WA</span><span>'
</span><span>}
</span></code></pre>
<p><strong>Reference:</strong> <a href="http://www.ruby-doc.org/stdlib-2.1.0/libdoc/json/rdoc/JSON.html#method-i-parse">JSON#parse</a></p>
<hr />
<h2 id="hash-to-json">2. How to convert a Hash into a JSON?<a class="zola-anchor" href="#hash-to-json" aria-label="Anchor link for: hash-to-json">๐</a></h2>
<p>In your web application, you track the number of signups per day for the current week:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>signups_of_the_week = {
</span><span> </span><span style="color:#a3be8c;">monday: </span><span style="color:#d08770;">2</span><span>,
</span><span> </span><span style="color:#a3be8c;">tuesday: </span><span style="color:#d08770;">3</span><span>,
</span><span> </span><span style="color:#a3be8c;">wednesday: </span><span style="color:#d08770;">4</span><span>,
</span><span> </span><span style="color:#a3be8c;">thursday: </span><span style="color:#d08770;">20</span><span>,
</span><span> </span><span style="color:#a3be8c;">friday: </span><span style="color:#d08770;">5</span><span>,
</span><span> </span><span style="color:#a3be8c;">saturday: </span><span style="color:#d08770;">2</span><span>,
</span><span> </span><span style="color:#a3be8c;">sunday: </span><span style="color:#d08770;">5
</span><span>}
</span></code></pre>
<p>You can provide them through an API as JSON data:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#8fa1b3;">require </span><span>'</span><span style="color:#a3be8c;">json</span><span>'
</span><span>
</span><span>signups_of_the_week.to_json```
</span><span style="color:#a3be8c;">
</span><span style="color:#a3be8c;">**IRB Output:**
</span><span style="color:#a3be8c;">
</span><span>```ruby
</span><span>
</span><span>=> "</span><span style="color:#a3be8c;">{</span><span>"monday"</span><span style="color:#a3be8c;">:2,
</span><span style="color:#a3be8c;"> </span><span>"tuesday"</span><span style="color:#a3be8c;">:3,
</span><span style="color:#a3be8c;"> </span><span>"wednesday"</span><span style="color:#a3be8c;">:4,
</span><span style="color:#a3be8c;"> </span><span>"thursday"</span><span style="color:#a3be8c;">:20,
</span><span style="color:#a3be8c;"> </span><span>"friday"</span><span style="color:#a3be8c;">:5,
</span><span style="color:#a3be8c;"> </span><span>"saturday"</span><span style="color:#a3be8c;">:2,
</span><span style="color:#a3be8c;"> x</span><span>"sunday"</span><span style="color:#a3be8c;">:5}</span><span>"
</span></code></pre>
<p><strong>Reference:</strong> <a href="http://www.ruby-doc.org/stdlib-2.1.0/libdoc/json/rdoc/JSON.html#method-i-generate">JSON#generate</a></p>
<p><strong>Side note:</strong> <a href="http://www.ruby-doc.org/stdlib-2.1.0/libdoc/json/rdoc/JSON.html#method-i-pretty_generate">JSON#pretty_generate</a> is really helpful for pretty printing and debugging.</p>
<hr />
<h2 id="default-value">3. How to set default value for a nested Hash?<a class="zola-anchor" href="#default-value" aria-label="Anchor link for: default-value">๐</a></h2>
<p>You have collection of contacts indexed by name, a nested <code>Hash</code>:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>contacts = {
</span><span> "</span><span style="color:#a3be8c;">John</span><span>" => {
</span><span> </span><span style="color:#a3be8c;">name: </span><span>"</span><span style="color:#a3be8c;">John</span><span>",
</span><span> </span><span style="color:#a3be8c;">email: </span><span>"</span><span style="color:#a3be8c;">john@doe.com</span><span>"
</span><span> },
</span><span> "</span><span style="color:#a3be8c;">Freddy</span><span>" => {
</span><span> </span><span style="color:#96b5b4;">name </span><span>"</span><span style="color:#a3be8c;">Freddy</span><span>",
</span><span> </span><span style="color:#a3be8c;">email: </span><span>"</span><span style="color:#a3be8c;">freddy@mercury.com</span><span>"
</span><span> }
</span><span>}
</span></code></pre>
<p>When working with a contact, you don't want to check every time if it exists or not. You just want to write:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>contacts["</span><span style="color:#a3be8c;">Jane</span><span>"][</span><span style="color:#a3be8c;">:email</span><span>] = "</span><span style="color:#a3be8c;">jane@doe.com</span><span>"
</span><span style="color:#96b5b4;">puts</span><span> contacts["</span><span style="color:#a3be8c;">Jane</span><span>"]
</span></code></pre>
<p><strong>IRB Output:</strong></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span> => {</span><span style="color:#a3be8c;">:name</span><span>=>'</span><span style="color:#a3be8c;">Jane</span><span>', </span><span style="color:#a3be8c;">:email</span><span>=>'</span><span style="color:#a3be8c;">jane@doe.com</span><span>'}
</span></code></pre>
<p>You can do it by setting a complex value when creating the <code>Hash</code></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>contacts = </span><span style="color:#96b5b4;">Hash</span><span>.</span><span style="color:#8fa1b3;">new </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">hsh</span><span>, </span><span style="color:#bf616a;">key</span><span>|
</span><span> hsh[key] = {
</span><span> </span><span style="color:#a3be8c;">name:</span><span> key,
</span><span> </span><span style="color:#a3be8c;">email: </span><span>""
</span><span> }
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>or later with</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>contacts.default_proc = </span><span style="color:#ebcb8b;">Proc</span><span>.</span><span style="color:#8fa1b3;">new </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">hsh</span><span>, </span><span style="color:#bf616a;">key</span><span>|
</span><span> hsh[key] = {
</span><span> </span><span style="color:#a3be8c;">name:</span><span> key,
</span><span> </span><span style="color:#a3be8c;">email: </span><span>""
</span><span> }
</span><span style="color:#b48ead;">end
</span></code></pre>
<p><strong>References:</strong> <a href="http://www.ruby-doc.org/core-2.1.0/Hash.html#method-c-new">Hash#new</a>, <a href="http://www.ruby-doc.org/core-2.1.0/Hash.html#method-i-default_proc-3D">Hash#default_proc=</a></p>
<hr />
<h2 id="merge">4. How to merge two nested Hashes?<a class="zola-anchor" href="#merge" aria-label="Anchor link for: merge">๐</a></h2>
<p>In an online shop, you want to merge a wish list with the current basket, both indexed by product id:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>wish_list = {
</span><span> </span><span style="color:#d08770;">8 </span><span>=> {
</span><span> </span><span style="color:#a3be8c;">title: </span><span>'</span><span style="color:#a3be8c;">The Color of Magic</span><span>',
</span><span> },
</span><span> </span><span style="color:#d08770;">42 </span><span>=> {
</span><span> </span><span style="color:#a3be8c;">title: </span><span>'</span><span style="color:#a3be8c;">The Hitch-Hiker"s Guide to the Galaxy</span><span>',
</span><span> </span><span style="color:#a3be8c;">price: </span><span style="color:#d08770;">5
</span><span> }
</span><span>}
</span><span>
</span><span>basket = {
</span><span> </span><span style="color:#d08770;">8 </span><span>=> {
</span><span> </span><span style="color:#a3be8c;">price: </span><span style="color:#d08770;">10
</span><span> },
</span><span> </span><span style="color:#d08770;">1729 </span><span>=> {
</span><span> </span><span style="color:#a3be8c;">title: </span><span>'</span><span style="color:#a3be8c;">Ramanujan: Twelve Lectures on Subjects Suggested by His Life and Work</span><span>',
</span><span> </span><span style="color:#a3be8c;">price: </span><span style="color:#d08770;">28
</span><span> }
</span><span>}
</span></code></pre>
<p>With <code>ActiveSupport</code>, you can simply do it with:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#8fa1b3;">require </span><span>"</span><span style="color:#a3be8c;">active_support/core_ext/hash</span><span>" </span><span style="color:#65737e;"># not necessary if in Rails
</span><span>
</span><span>basket.deep_merge(wish_list)
</span></code></pre>
<p>or without <code>ActiveSupport</code></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">deep_merge</span><span>(</span><span style="color:#bf616a;">h1</span><span>, </span><span style="color:#bf616a;">h2</span><span>)
</span><span> h1.merge(h2) { |</span><span style="color:#bf616a;">key</span><span>, </span><span style="color:#bf616a;">h1_elem</span><span>, </span><span style="color:#bf616a;">h2_elem</span><span>| deep_merge(h1_elem, h2_elem) }
</span><span style="color:#b48ead;">end
</span><span>
</span><span>deep_merge(basket, wish_list)
</span></code></pre>
<p><strong>IRB Output:</strong></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span> => {
</span><span> </span><span style="color:#d08770;">8</span><span>=>{</span><span style="color:#a3be8c;">:price</span><span>=></span><span style="color:#d08770;">10</span><span>, </span><span style="color:#a3be8c;">:title</span><span>=>'</span><span style="color:#a3be8c;">The Color of Magic</span><span>'},
</span><span> </span><span style="color:#d08770;">1729</span><span>=>{</span><span style="color:#a3be8c;">:title</span><span>=>'</span><span style="color:#a3be8c;">Ramanujan: Twelve Lectures on Subjects Suggested by His Life and Work</span><span>', </span><span style="color:#a3be8c;">:price</span><span>=></span><span style="color:#d08770;">28</span><span>},
</span><span> </span><span style="color:#d08770;">42</span><span>=>{</span><span style="color:#a3be8c;">:title</span><span>=>'</span><span style="color:#a3be8c;">The Hitch-Hiker"s Guide to the Galaxy</span><span>', </span><span style="color:#a3be8c;">:price</span><span>=></span><span style="color:#d08770;">5</span><span>}
</span><span>}
</span></code></pre>
<p><strong>References:</strong> <a href="http://www.ruby-doc.org/core-2.1.0/Hash.html#method-i-merge">Hash#merge</a>, <a href="http://api.rubyonrails.org/classes/Hash.html#method-i-deep_merge">Hash#deep_merge</a></p>
<hr />
<h2 id="filter">5. How to filter out some keys of a Hash?<a class="zola-anchor" href="#filter" aria-label="Anchor link for: filter">๐</a></h2>
<p>You've built an histogram of daily sales and stored it in a <code>Hash</code>, the key being the day:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>histogram = {
</span><span> </span><span style="color:#a3be8c;">monday: </span><span style="color:#d08770;">5</span><span>,
</span><span> </span><span style="color:#a3be8c;">tuesday: </span><span style="color:#d08770;">7</span><span>,
</span><span> </span><span style="color:#a3be8c;">wednesday: </span><span style="color:#d08770;">10</span><span>,
</span><span> </span><span style="color:#a3be8c;">thursday: </span><span style="color:#d08770;">18</span><span>,
</span><span> </span><span style="color:#a3be8c;">friday: </span><span style="color:#d08770;">7</span><span>,
</span><span> </span><span style="color:#a3be8c;">saturday: </span><span style="color:#d08770;">2</span><span>,
</span><span> </span><span style="color:#a3be8c;">sunday: </span><span style="color:#d08770;">0
</span><span>}
</span></code></pre>
<p>You want to filter out Saturday and Sunday. With <code>ActiveSupport</code>, you can do it as following</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#8fa1b3;">require </span><span>"</span><span style="color:#a3be8c;">active_support/core_ext/hash</span><span>" </span><span style="color:#65737e;"># not necessary if Rails
</span><span>
</span><span>histogram.except(</span><span style="color:#a3be8c;">:saturday</span><span>, </span><span style="color:#a3be8c;">:sunday</span><span>)
</span></code></pre>
<p>or without <code>ActiveSupport</code></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">filter</span><span>(</span><span style="color:#bf616a;">hsh</span><span>, *</span><span style="color:#bf616a;">keys</span><span>)
</span><span> hsh.</span><span style="color:#96b5b4;">dup</span><span>.</span><span style="color:#96b5b4;">tap </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">h</span><span>|
</span><span> keys.each { |</span><span style="color:#bf616a;">k</span><span>| h.delete(k) }
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span>filter(histogram, </span><span style="color:#a3be8c;">:saturday</span><span>, </span><span style="color:#a3be8c;">:sunday</span><span>)
</span></code></pre>
<p>Another clearer implementation is based on reject (credits to Thiago A.):</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">filter2</span><span>(</span><span style="color:#bf616a;">hsh</span><span>, *</span><span style="color:#bf616a;">keys</span><span>)
</span><span> hsh.reject { |</span><span style="color:#bf616a;">k</span><span>, </span><span style="color:#bf616a;">_</span><span>| keys.</span><span style="color:#96b5b4;">include?</span><span> k }
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>Note that if you deal with large collection you should benchmark your implementation to select the best one.</p>
<p><strong>IRB Output:</strong></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span> => {</span><span style="color:#a3be8c;">:monday</span><span>=></span><span style="color:#d08770;">5</span><span>, </span><span style="color:#a3be8c;">:tuesday</span><span>=></span><span style="color:#d08770;">7</span><span>, </span><span style="color:#a3be8c;">:wednesday</span><span>=></span><span style="color:#d08770;">10</span><span>, </span><span style="color:#a3be8c;">:thursday</span><span>=></span><span style="color:#d08770;">18</span><span>, </span><span style="color:#a3be8c;">:friday</span><span>=></span><span style="color:#d08770;">7</span><span>}
</span></code></pre>
<p><strong>Reference:</strong> <a href="http://api.rubyonrails.org/classes/Hash.html#method-i-except">Hash#except</a>, <a href="http://www.ruby-doc.org/core-2.1.0/Hash.html#method-i-delete">Hash#delete</a>, <a href="http://www.ruby-doc.org/core-2.1.0/Hash.html#method-i-reject">Hash#reject</a>, <a href="http://www.ruby-doc.org/core-2.1.0/Object.html#method-i-dup">Object#dup</a>, <a href="http://www.ruby-doc.org/core-2.1.0/Object.html#method-i-tap">Object#tap</a></p>
<hr />
<h2 id="sort">6. How to "sort" a Hash by value?<a class="zola-anchor" href="#sort" aria-label="Anchor link for: sort">๐</a></h2>
<p>In a dices game, you keep the score per player in a <code>Hash</code>:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>scores = {
</span><span> "</span><span style="color:#a3be8c;">The Lady</span><span>" => </span><span style="color:#d08770;">3</span><span>,
</span><span> "</span><span style="color:#a3be8c;">Fate</span><span>" => </span><span style="color:#d08770;">2</span><span>,
</span><span> "</span><span style="color:#a3be8c;">Death</span><span>" => </span><span style="color:#d08770;">10
</span><span>}
</span></code></pre>
<p>You want to to sort them by scores. You can do it with:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>leaderboard = scores.sort_by { |</span><span style="color:#bf616a;">_</span><span>, </span><span style="color:#bf616a;">score</span><span>| -score }
</span></code></pre>
<p><strong>IRB Output:</strong></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span> => [['</span><span style="color:#a3be8c;">Death</span><span>', </span><span style="color:#d08770;">10</span><span>], ['</span><span style="color:#a3be8c;">The Lady</span><span>', </span><span style="color:#d08770;">3</span><span>], ['</span><span style="color:#a3be8c;">Fate</span><span>', </span><span style="color:#d08770;">2</span><span>]]
</span></code></pre>
<p><strong>Reference:</strong> <a href="http://ruby-doc.org/core-2.1.0/Enumerable.html#method-i-sort_by">Enumerable#sort_by</a></p>
<p><strong>Side note:</strong> <code>Hash</code> enumerates their value in their insertion order.</p>
<hr />
<h2 id="diff">7. How to find the differences between two Hashes?<a class="zola-anchor" href="#diff" aria-label="Anchor link for: diff">๐</a></h2>
<p>You regularly retrieve data from RSS feeds and put them into a <code>Hash</code>:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>entries = {
</span><span> </span><span style="color:#d08770;">1372284000 </span><span>=> '</span><span style="color:#a3be8c;">CVE-2013-4073</span><span>',
</span><span> </span><span style="color:#d08770;">1368482400 </span><span>=> '</span><span style="color:#a3be8c;">CVE-2013-2065</span><span>'
</span><span>}
</span></code></pre>
<p>When doing an update, you get another <code>Hash</code>:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>updated\_entries = {
</span><span> </span><span style="color:#d08770;">1385074800 </span><span>=> '</span><span style="color:#a3be8c;">CVE-2013-4164</span><span>',
</span><span> </span><span style="color:#d08770;">1372284000 </span><span>=> '</span><span style="color:#a3be8c;">CVE-2013-4073</span><span>',
</span><span> </span><span style="color:#d08770;">1368482400 </span><span>=> '</span><span style="color:#a3be8c;">CVE-2013-2065</span><span>'
</span><span>}
</span></code></pre>
<p>You want to spot which entries are new so you can for instance send them by email. You can do it with:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>new_entries = updated_entries.</span><span style="color:#96b5b4;">dup</span><span>.delete_if {|</span><span style="color:#bf616a;">k</span><span>| entries.keys.</span><span style="color:#96b5b4;">include?</span><span> k }
</span></code></pre>
<p><strong>but it's better</strong> and clearer to do with</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>new_entries = updated_entries.reject { |</span><span style="color:#bf616a;">k</span><span>, </span><span style="color:#bf616a;">_</span><span>| entries.</span><span style="color:#96b5b4;">include?</span><span> k }
</span></code></pre>
<p>as you benefit from the fast lookup of <code>Hash</code> (Credits to <a href="http://apeiros.me">apeiros</a>)</p>
<p><strong>IRB Output:</strong></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>=> {</span><span style="color:#d08770;">1385074800</span><span>=>'</span><span style="color:#a3be8c;">CVE-2013-4164</span><span>'}
</span></code></pre>
<p><strong>Reference:</strong> <a href="http://www.ruby-doc.org/core-2.1.0/Hash.html#method-i-delete_if">Hash#delete_if</a>, <a href="http://www.ruby-doc.org/core-2.1.0/Hash.html#method-i-keys">Hash#keys</a>, <a href="http://www.ruby-doc.org/core-2.1.0/Hash.html#method-i-reject">Hash#reject</a>, <a href="http://www.ruby-doc.org/core-2.1.0/Hash.html#method-i-include-3F">Hash#include?</a></p>
<hr />
<h2 id="what-s-your-daily-use-cases-of-hash">Whatโs your daily use cases of Hash?<a class="zola-anchor" href="#what-s-your-daily-use-cases-of-hash" aria-label="Anchor link for: what-s-your-daily-use-cases-of-hash">๐</a></h2>
<p>After the <a href="https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-array/">treasures of Array</a>, I really enjoyed to list those of Hash. Whatโs yours? What are your typical daily use cases of Hash and elegant Ruby to resolve them?</p>
7 daily use cases of Ruby Array2014-02-24T00:00:00+00:002014-02-24T00:00:00+00:00https://ibakesoftware.com/blog/7-daily-use-cases-of-ruby-array/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>Ruby and Ruby on Rails come with great reference documentation (<a href="http://ruby-doc.org/">Ruby doc</a>, <a href="http://api.rubyonrails.org/">Rails doc</a>, or alternatives such as <a href="http://apidock.com/">APIdock</a>, or the recent <a href="http://www.omniref.com/">omniref</a> covering also all gems). But when you need to find how to check if one array has all elements of another, you won't find the answer in the doc because it's not use case oriented. The documentation explains what each piece can do, not how you can use it (and clearly not which you should use for a given use case). Of course, that's the same for tutorial and books. Hopefully, there is StackOverflow. Below, I share 7 common use cases of Array I met very often and should be useful to you.</p>
<h2 id="1-how-to-check-if-one-array-has-all-elements-of-another">1. How to check if one Array has all elements of another?<a class="zola-anchor" href="#1-how-to-check-if-one-array-has-all-elements-of-another" aria-label="Anchor link for: 1-how-to-check-if-one-array-has-all-elements-of-another">๐</a></h2>
<p>You want to check that all imported emails already exist in a contact list.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>imported_emails = [ '</span><span style="color:#a3be8c;">john@doe.com</span><span>', '</span><span style="color:#a3be8c;">janet@doe.com</span><span>' ]
</span><span>existing_emails = [ '</span><span style="color:#a3be8c;">john@doe.com</span><span>', '</span><span style="color:#a3be8c;">janet@doe.com</span><span>' , '</span><span style="color:#a3be8c;">fred@mercury.com</span><span>' ]
</span><span>
</span><span style="color:#96b5b4;">puts </span><span>'</span><span style="color:#a3be8c;">already imported</span><span>' </span><span style="color:#b48ead;">if </span><span>(imported_emails - existing_emails).empty?
</span></code></pre>
<p>IRB Output:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>already imported
</span><span>=> </span><span style="color:#d08770;">nil
</span></code></pre>
<p>Reference: <a href="http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-2D">Array Difference</a></p>
<h2 id="2-how-to-find-what-s-elements-are-common-to-two-arrays">2. How to find what's elements are common to two Arrays?<a class="zola-anchor" href="#2-how-to-find-what-s-elements-are-common-to-two-arrays" aria-label="Anchor link for: 2-how-to-find-what-s-elements-are-common-to-two-arrays">๐</a></h2>
<p>You want to find the common tags of two blog posts.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>tags_post1 = [ '</span><span style="color:#a3be8c;">ruby</span><span>', '</span><span style="color:#a3be8c;">rails</span><span>', '</span><span style="color:#a3be8c;">test</span><span>' ]
</span><span>tags_post2 = [ '</span><span style="color:#a3be8c;">test</span><span>', '</span><span style="color:#a3be8c;">rspec</span><span>' ]
</span><span>
</span><span>common_tags = tags_post1 & tags_post2
</span></code></pre>
<p>IRB Output:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span> => ["</span><span style="color:#a3be8c;">test</span><span>"]
</span></code></pre>
<p>Reference: <a href="http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-26">Set Intersection</a></p>
<h2 id="3-how-to-merge-two-arrays-without-duplicating-entries">3. How to merge two Arrays without duplicating entries?<a class="zola-anchor" href="#3-how-to-merge-two-arrays-without-duplicating-entries" aria-label="Anchor link for: 3-how-to-merge-two-arrays-without-duplicating-entries">๐</a></h2>
<p>You want to get a unique list of twitter accounts id followed by two persons.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>followeds1 = [ </span><span style="color:#d08770;">1</span><span>, </span><span style="color:#d08770;">2</span><span>, </span><span style="color:#d08770;">3 </span><span>]
</span><span>followeds2 = [ </span><span style="color:#d08770;">2</span><span>, </span><span style="color:#d08770;">4</span><span>, </span><span style="color:#d08770;">5 </span><span>]
</span><span>
</span><span>all_followeds = followeds1 | followeds2
</span></code></pre>
<p>IRB Output:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span> => [</span><span style="color:#d08770;">1</span><span>, </span><span style="color:#d08770;">2</span><span>, </span><span style="color:#d08770;">3</span><span>, </span><span style="color:#d08770;">4</span><span>, </span><span style="color:#d08770;">5</span><span>]
</span></code></pre>
<p>Reference: <a href="http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-7C">Set Union</a></p>
<h2 id="4-how-to-sort-an-array-of-hashes">4. How to sort an Array of Hashes?<a class="zola-anchor" href="#4-how-to-sort-an-array-of-hashes" aria-label="Anchor link for: 4-how-to-sort-an-array-of-hashes">๐</a></h2>
<p>You retrieve data from a third party API that returns an <code>Array</code> of <code>Hash</code>es as following:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>data = [
</span><span> {
</span><span> </span><span style="color:#a3be8c;">name: </span><span>'</span><span style="color:#a3be8c;">Christophe</span><span>',
</span><span> </span><span style="color:#a3be8c;">location: </span><span>'</span><span style="color:#a3be8c;">Belgium</span><span>'
</span><span> },
</span><span> {
</span><span> </span><span style="color:#a3be8c;">name: </span><span>'</span><span style="color:#a3be8c;">John</span><span>',
</span><span> </span><span style="color:#a3be8c;">location: </span><span>'</span><span style="color:#a3be8c;">United States of America</span><span>'
</span><span> },
</span><span> {
</span><span> </span><span style="color:#a3be8c;">name: </span><span>'</span><span style="color:#a3be8c;">Piet</span><span>',
</span><span> </span><span style="color:#a3be8c;">location: </span><span>'</span><span style="color:#a3be8c;">Belgium</span><span>'
</span><span> },
</span><span> {
</span><span> </span><span style="color:#a3be8c;">name: </span><span>'</span><span style="color:#a3be8c;">Franรงois</span><span>',
</span><span> </span><span style="color:#a3be8c;">location: </span><span>'</span><span style="color:#a3be8c;">France</span><span>'
</span><span> }
</span><span>]
</span></code></pre>
<p>When displaying those data, you want to sort them by location. You can do it with:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>data.sort_by { |</span><span style="color:#bf616a;">hsh</span><span>| hsh[</span><span style="color:#a3be8c;">:location</span><span>] }
</span></code></pre>
<p>IRB Output:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span> => [
</span><span> {</span><span style="color:#a3be8c;">:name</span><span>=>"</span><span style="color:#a3be8c;">Christophe</span><span>", </span><span style="color:#a3be8c;">:location</span><span>=>"</span><span style="color:#a3be8c;">Belgium</span><span>"},
</span><span> {</span><span style="color:#a3be8c;">:name</span><span>=>"</span><span style="color:#a3be8c;">Piet</span><span>", </span><span style="color:#a3be8c;">:location</span><span>=>"</span><span style="color:#a3be8c;">Belgium</span><span>"},
</span><span> {</span><span style="color:#a3be8c;">:name</span><span>=>"</span><span style="color:#a3be8c;">Franรงois</span><span>", </span><span style="color:#a3be8c;">:location</span><span>=>"</span><span style="color:#a3be8c;">France</span><span>"},
</span><span> {</span><span style="color:#a3be8c;">:name</span><span>=>"</span><span style="color:#a3be8c;">John</span><span>", </span><span style="color:#a3be8c;">:location</span><span>=>"</span><span style="color:#a3be8c;">United States of America</span><span>"}
</span><span> ]
</span></code></pre>
<p>Reference: <a href="http://www.ruby-doc.org/core-2.1.0/Enumerable.html#method-i-sort_by">Enumerable#sort_by</a></p>
<h2 id="5-how-to-keep-objects-in-an-array-that-are-unique-with-respect-to-one-attribute">5. How to keep objects in an Array that are unique with respect to one attribute?<a class="zola-anchor" href="#5-how-to-keep-objects-in-an-array-that-are-unique-with-respect-to-one-attribute" aria-label="Anchor link for: 5-how-to-keep-objects-in-an-array-that-are-unique-with-respect-to-one-attribute">๐</a></h2>
<p>In an online shop, on the home page, you need to show one product per category.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>Product = </span><span style="color:#ebcb8b;">Struct</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#a3be8c;">:id</span><span>, </span><span style="color:#a3be8c;">:category_id</span><span>)
</span><span>
</span><span>products = [
</span><span> </span><span style="color:#ebcb8b;">Product</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">1</span><span>, </span><span style="color:#d08770;">1</span><span>),
</span><span> </span><span style="color:#ebcb8b;">Product</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">2</span><span>, </span><span style="color:#d08770;">2</span><span>),
</span><span> </span><span style="color:#ebcb8b;">Product</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">3</span><span>, </span><span style="color:#d08770;">3</span><span>),
</span><span> </span><span style="color:#ebcb8b;">Product</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">4</span><span>, </span><span style="color:#d08770;">1</span><span>),
</span><span> </span><span style="color:#ebcb8b;">Product</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">5</span><span>, </span><span style="color:#d08770;">3</span><span>),
</span><span> </span><span style="color:#ebcb8b;">Product</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">6</span><span>, </span><span style="color:#d08770;">5</span><span>),
</span><span>]
</span><span>
</span><span>products = products.uniq &</span><span style="color:#a3be8c;">:category_id
</span></code></pre>
<p>IRB Output:</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span> => [
</span><span> #<struct Product id=1, category_id=1>,
</span><span> #<struct Product id=2, category_id=2>,
</span><span> #<struct Product id=3, category_id=3>,
</span><span> #<struct Product id=6, category_id=5>
</span><span> ]
</span></code></pre>
<p>Reference: <a href="http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-uniq">Array#uniq</a></p>
<h2 id="6-how-to-filter-an-array-with-a-string">6. How to filter an Array with a String?<a class="zola-anchor" href="#6-how-to-filter-an-array-with-a-string" aria-label="Anchor link for: 6-how-to-filter-an-array-with-a-string">๐</a></h2>
<p>You've retrieved a list of books and you want to filter them with a <code>String</code>:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>books = [
</span><span> '</span><span style="color:#a3be8c;">The Ruby Programming Language</span><span>',
</span><span> '</span><span style="color:#a3be8c;">Programming Ruby 1.9 & 2.0: The Pragmatic Programmers<pre wp-pre-tag-11=""></pre>#039; Guide (The Facets of Ruby)</span><span>',
</span><span> '</span><span style="color:#a3be8c;">Practical Object-Oriented Design in Ruby: An Agile Primer</span><span>',
</span><span> '</span><span style="color:#a3be8c;">Eloquent Ruby</span><span>',
</span><span> '</span><span style="color:#a3be8c;">Ruby on Rails Tutorial: Learn Web Development with Rails</span><span>'
</span><span>]
</span><span>
</span><span>books = books.grep(/</span><span style="color:#96b5b4;">[Rr]ails</span><span>/)
</span></code></pre>
<p>IRB Output:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span> => ["</span><span style="color:#a3be8c;">Ruby on Rails Tutorial: Learn Web Development with Rails</span><span>"]
</span></code></pre>
<p>Reference: <a href="http://ruby-doc.org/core-2.1.0/Enumerable.html#method-i-grep">Enumerable#grep</a></p>
<h2 id="7-how-to-always-get-an-array">7. How to always get an Array?<a class="zola-anchor" href="#7-how-to-always-get-an-array" aria-label="Anchor link for: 7-how-to-always-get-an-array">๐</a></h2>
<p>In a method you work with products and you eventually return one or several. But when you get only one, it's not an Array. You can deal very smoothly with both cases with <code>Array()</code> or <code>[*]</code>:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">method
</span><span> </span><span style="color:#65737e;"># โฆ
</span><span>
</span><span> [*products]
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>You'll find more explanations in the <a href="http://batsov.com/articles/2013/06/28/the-elements-of-style-in-ruby-number-3-make-sure-something-is-an-array/">Bozhidar Batsov's post</a>.</p>
<p>Reference: <a href="http://www.ruby-doc.org/core-2.1.0/Kernel.html#method-i-Array">Kernel#Array</a>, <a href="http://www.ruby-doc.org/core-2.1.0/doc/syntax/calling_methods_rdoc.html#label-Array+to+Arguments+Conversion">splat operator</a>, <a href="https://github.com/bbatsov/ruby-style-guide">Ruby Style guide</a></p>
<h2 id="what-s-your-daily-use-cases-of-array">What's your daily use cases of Array?<a class="zola-anchor" href="#what-s-your-daily-use-cases-of-array" aria-label="Anchor link for: what-s-your-daily-use-cases-of-array">๐</a></h2>
<p>Ruby is full of treasures. It takes some times to know them and find how you can use them. What's yours? What are your typical daily use cases of Array and beautiful Ruby to resolve them?</p>
<p><strong>Update:</strong> Cesar did the same exercise in Javascript. <a href="https://gist.github.com/cesarandreu/9224890">Look at his Gist, very interesting</a>.</p>
TDD your Rails app without convincing your boss2014-02-20T00:00:00+00:002014-02-20T00:00:00+00:00https://ibakesoftware.com/blog/tdd-your-rails-app-without-convincing-your-boss/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>You've just been hired by a company to work on an existing project. <em>When discovering its code base, you realize the tests are very rare, even totally absent.</em> You don't wait to discuss what you think a big lack with your boss. Unfortunately, you can't convince him whatever the argument you bring.and he digs in his heels: "Why waste time on something that does not add any value for the customer?"</p>
<p><em>If you comply, you will be anxious and scared each time you touch that very fragile app</em>. But you're aware <a href="http://stackoverflow.com/a/67500/831180">of the benefits of</a> <a href="http://programmers.stackexchange.com/a/88370/116940">covering the code with tests</a>, <a href="https://en.wikipedia.org/wiki/Test-driven_development#Benefits">even writing them</a> <a href="https://practicingruby.com/articles/tdd-costs-and-benefits">before the implementation</a>. Not your boss. He hires you to do the job: developing an application. Developing is not only one monolithic task: typing code. It's also writing tests, thinking of design, communicating to write the user story.</p>
<p>Automated tests are an important component of the application, it's not a separate entity. Don't talk about it as a separated task. <strong>When developing, write test, write code as there are a same and unique task of the job.</strong> Your boss doesn't need to know about all the details or why did he hire you for your expertise?</p>
<p>You may say that <strong>it's daunting task to fully cover a pre-existing code base with tests</strong>. In that case, I generally <strong>write tests only for new code and for bugs discovered in pre-existing code base</strong>. It organically increases the test coverage step by step.</p>
<p>In the long run, you'll probably be able to explain the value to your boss - especially if you are actually doing it. One more reason to start today.</p>
Which development editor should I use when developing in Ruby on Rails?2014-02-17T00:00:00+00:002014-02-17T00:00:00+00:00https://ibakesoftware.com/blog/which-development-editor-should-i-use-when-developing-in-ruby-on-rails/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>You've just started to code your first Ruby on Rails application and you're wondering if there isn't a better editor than the one you're using. Maybe you're a beginner and you started with a simple text editor without syntax coloring, or you come from Java world and you use Eclipse, or you're struggled to navigate through your project with Vim.</p>
<p>Then, you start to look for better solution and you find plenty of features comparisons, a lot of discussions, tons of blog posts or other resources, billions of advices or opinions, without mentioning cultural <a href="https://en.wikipedia.org/wiki/Editor_war">editor war</a>. You can spend a whole week to read all of them without finding the best editor. You just wanted to be more productive, to find the perfect tool right away, to be a master of editing-fu.</p>
<p>Do you remind those screencasts and others videos where a developer he's editing like a wizard, navigating through their project at the speed of light, automatically formatting their code? We'd like to be the same. At the beginning you just wanted a better development editor, at the end you struggle with finding a solution and spend a considerable amount of time without improving your situation. That certainly doesn't pay the bills.</p>
<p>The reason behind that profusion of resources is that there is no perfect solution. The tool doesn't make you, it helps you and it takes time to master as any crafts. It needs also constant learning and practice. Maybe your current editor is good enough, but you should learn more about it. The only way to find a better editor is to try other options and give them an honest try of about 2 solid weeks of coding in each. You'll eventually find a comfortable spot.</p>
<p>I'll give you a simple action plan that I used. There are several good editors with people writing Ruby on Rails application every day (lexicographically ordered): <a href="https://web.archive.org/web/20141101143028/http://www.aptana.com/products/radrails">Eclipse/Aptana</a>, <a href="https://www.gnu.org/software/emacs/">Emacs</a>, <a href="https://www.jetbrains.com/ruby/">RubyMine</a>, <a href="http://www.sublimetext.com/">SublimeText</a>, <a href="https://github.com/textmate/textmate">Textmate</a>, <a href="http://www.vim.org/">Vim</a>.</p>
<ol>
<li>Pick one of those. No idea? pick at random.</li>
<li>Use it for two week (put a reminder).</li>
<li>At the end:
<ul>
<li>Happy? Enjoyed? Keep it.</li>
<li>Done.Painful? Repeat.</li>
<li>Not sure? Continue to use it.</li>
</ul>
</li>
</ol>
<p>Otherwise, if you use one since a certain time like about one year, it's time to reinforce your mastering: regularly, like every 2 weeks, reads one resource and apply it (a part of the manual, a point in a tutorial, a blog post).</p>
<p>What about trying another one when you use something since a long time? Well you could, it's never bad, but don't do it to escape what you need to do: <strong>develop and ship!</strong></p>
PullReview: GitHub Status and others2013-12-31T00:00:00+00:002013-12-31T00:00:00+00:00https://ibakesoftware.com/blog/pullreview-update-github-status-and-others/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>First of all, dear reader, I wish you Happy Holidays!</p>
<p>This blog post is about the last release of <a href="https://web.archive.org/web/20130818165309/http://try.pullreview.com/" title="PullReview">PullReview</a>, that includes a few features before the end of the year:</p>
<ul>
<li>Same Actions are grouped for Code Smell, Complexity, Design, and Duplication</li>
<li>Lower severity for issues detected in a test</li>
<li>Tweet your progress</li>
<li>New references & new contents</li>
<li>A few new rules for Code Style and Security</li>
<li>Notification via GitHub Status</li>
</ul>
<hr />
<h2 id="same-actions-grouped-for-some-categories">Same Actions Grouped for some Categories<a class="zola-anchor" href="#same-actions-grouped-for-some-categories" aria-label="Anchor link for: same-actions-grouped-for-some-categories">๐</a></h2>
<p>Actions are now grouped for the following categories: Code Smell, Complexity, Design, and Duplications (and of course Code Style and Documentation).</p>
<p><img src="/blog/images/image02.png" alt="An example of actions grouped for some categories" /></p>
<p>It means that multiple occurrences of a same action is now grouped for those categories. For instance, if 24 times you should consider to refactor complex method, it is now grouped. PullReview will give you of course the locations of each occurrence.</p>
<p>For duplication, the grouping is slightly different as we group the duplication itself not the action. It means that if you have copy-pasted a snippet in two different files, it's one duplication, and one action to take: "Avoid copy/paste".</p>
<hr />
<h2 id="lower-severity-for-issues-detected-in-a-test">Lower severity for issues detected in a test<a class="zola-anchor" href="#lower-severity-for-issues-detected-in-a-test" aria-label="Anchor link for: lower-severity-for-issues-detected-in-a-test">๐</a></h2>
<p>Even if tests are important, they don't require the same convention and quality level than production code. For instance, it's very common to not follow Don't-Repeat-Yourself (DRY) principle for tests because clarity and verbosity come first. For that reason, we have decreased the severity of issues detected in tests. As consequence, they will appear farther in your review and you will focus on what matters first: the code.</p>
<hr />
<h2 id="tweet-your-progress">Tweet your progress<a class="zola-anchor" href="#tweet-your-progress" aria-label="Anchor link for: tweet-your-progress">๐</a></h2>
<p>Each time you push a new commit on a branch, you'll get a new review. But PullReview will also track your progress since the last review. PullReview tell you how many issues you've fixed since the last review and how many you still have.</p>
<p><img src="/blog/images/image03.png" alt="Screenshot of the "Tweet this" link." /></p>
<p>When we fix a good bunch of issues, it's a victory that we might want to share. That's why we added a "Tweet this" link for Open Source project and let you tell the world you've cleaned it up with the help of PullReview.</p>
<hr />
<h2 id="new-references-new-contents">New references & new contents<a class="zola-anchor" href="#new-references-new-contents" aria-label="Anchor link for: new-references-new-contents">๐</a></h2>
<p>As you know, we think it's not enough to underline the problem. It's important to explain you whys and hows. That's why we continue to improve the existing content, and add new ones.</p>
<p>We've added some new references: when you recently meet a problem, you don't read the same way a reference on the topic. Don't forget to share those you think worth to read, I'm sure that it will be appreciated by the other users.</p>
<p>We've also fixed some errors and typos, especially in code snippets.</p>
<p>We don't spoil them, and let you discover them.</p>
<hr />
<h2 id="a-few-new-rules-for-code-style-and-security">A few new rules for Code Style and Security<a class="zola-anchor" href="#a-few-new-rules-for-code-style-and-security" aria-label="Anchor link for: a-few-new-rules-for-code-style-and-security">๐</a></h2>
<p>Each time we can, new rules are added. This time, it's for Code Style and Security.</p>
<p>For Style, a lot of new rules are about spacing and blank lines, but also about global variables, parentheses, branching, etc. For Security, a bunch of new Ruby on Rails CVEs are now detected, especially those fixed by the last <a href="http://weblog.rubyonrails.org/2013/12/3/Rails_3_2_16_and_4_0_2_have_been_released/">releases 3.2.16 and 4.0.2</a>.</p>
<p>Again, we don't spoil them, and let you discover them :).</p>
<hr />
<h2 id="github-status">GitHub Status<a class="zola-anchor" href="#github-status" aria-label="Anchor link for: github-status">๐</a></h2>
<p>With GitHub Status, you will be directly notified in GitHub when a review is ready, and what's its status. This needs a quick setup in your account page:</p>
<p><img src="/blog/images/image05-bis.png" alt="GitHub Status setup: step 1." />]</p>
<p>Simply find the option and enable it by clicking on the button.</p>
<p><img src="/blog/images/image01.png" alt="GitHub Status setup: step 2." /></p>
<p>Then, next time you push some code, you'll find on a GitHub Issue or PullRequest a status of your review attached to the corresponding commit:</p>
<ul>
<li>Success when it's perfect
<img src="/blog/images/image04.png" alt="GitHub Status: Perfect review." /></li>
<li>Failure when there are issues to fix
<img src="/blog/images/image06.png" alt="GitHub Status: Failure." /></li>
<li>Error when there is at least one critical issue
<img src="/blog/images/image00.png" alt="GitHub Status: Error." /></li>
</ul>
<p>If you use a Continuous Integration (e.g. Jenkins, TravisCI, CodeShip) and have enabled GitHub Status for it, it's possible that your CI will override the PullReview status as for the moment GitHub only show the last one.</p>
<p>When PullReview pushes a status, it will check if there is already one. If it's the case, it will merge its status with the last one. For instance, your CI has already pushed an Error before PullReview, PullReview will take it into account when it will push its status:</p>
<p><img src="/blog/images/image07.png" alt="GitHub Status: CI failed." /></p>
<p>That notification will allow you and your colleague to have a quick look of the situation by PullReview. I hope you will enjoy it, as we do.</p>
<hr />
<h2 id="happy-holidays-and-have-a-great-new-year">Happy Holidays and have a great New Year!<a class="zola-anchor" href="#happy-holidays-and-have-a-great-new-year" aria-label="Anchor link for: happy-holidays-and-have-a-great-new-year">๐</a></h2>
<p>I hope you'll spend it with family and friends in a warm place.</p>
<p>If you want to try PullReview, <a href="https://web.archive.org/web/20130818165309/http://try.pullreview.com/" title="Sign up!">just sign up</a> (it's free for Open Source project and there is a 31-days trial for paying plans).</p>
<p>If you have any questions about PullReview or anything else, you can contact us via:</p>
<ul>
<li>our twitter account <code>@8th_color</code></li>
<li>or via email.</li>
</ul>
<p>Best Wishes!</p>
Introducing PullReview - Your Ruby Batmobile for Automated Code Review2013-07-31T00:00:00+00:002013-07-31T00:00:00+00:00https://ibakesoftware.com/blog/introducing-pullreview-your-ruby-batmobile-for-automated-code-review/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p><strong>TL;DR</strong> 8th Color has been around for almost two years now, and our new tool, <a href="https://web.archive.org/web/20130818165309/http://try.pullreview.com/" title="PullReview, an automated Code Review tool for Ruby in Github">PullReview</a>, brings us closer to our goal: helping developers develop themselves. PullReview is an Automated Code Review Tool for Ruby developers using GitHub, and itโs in full preparation.</p>
<p><strong>Introduction: The Road Traveled</strong></p>
<p>July 2013. 8th Color has been in business for close to two years now - <a href="https://ibakesoftware.com/blog/hello-world/" title="Hello world!">and so has our blog</a>. And as our development focus has shifted, so has this blogโs content. For those who did not notice: weโve been writing a lot about Code Review, Ruby on Rails, and <a href="https://ibakesoftware.com/blog/do-not-fall-in-the-learning-curve/" title="Do not fall in the learning curve!">the need to Grow as a Developer.</a></p>
<p>As a returning reader - youโre more than 2000 nowadays - shoutout! - you might ask yourself: why all the fatherly advice? What is 8th Color - what is PullReview - all about?</p>
<p>Allow us to elaborate.</p>
<p>We, thatโs 8th Color. 8th Color, thatโs the founders - <a href="/">Christophe</a> & Martin - and the first knight - Stรฉphan. We are passionate developers and we are passionate about developers.</p>
<p><strong>You - the Saviour of Digital Gotham</strong></p>
<p>We have watched the importance of what we do as a community - programming - grow as we have matured within that same community.</p>
<p>Code drives both the mundane and the disruptive. We program both algorithms for Angry Birds as we develop models to visualize SARS outbreaks. Though the world of (bio)mechanics is still a large part of society, coding intertwines with it - precedes it - and sometimes even replaces it: to put it stark, every time we slip up down, <a href="http://www.newscientist.com/gallery/software-bugs">the world slips up</a>.</p>
<p>While demand for developers as a workforce does <a href="http://www.epi.org/publication/bp359-guestworkers-high-skill-labor-market-analysis/">not necessarily outstrip supply</a>, the speed at which software development evolves creates a constant <a href="http://www.bls.gov/ooh/Computer-and-Information-Technology/Software-developers.htm">tension</a> on the labour market: in general, we should have it <a href="http://qz.com/104135/euro-zone-tech-science-workers-unemployment/">easier</a> finding a job than our peers do - wherever in the world.</p>
<p>This combination of impact and relative scarcity is both an opportunity and a responsibility: as weโre hard to find - and as our projects can have significant impact - we have the implicit duty to be the best we can be. In the words of Uncle Ben: โWith great power... comes great responsibilityโ</p>
<p><strong>8th Color - The Batcave</strong></p>
<p>This is where 8th Color comes in. You - developer - Youโre Bruce Wayne. Youโre ready. You have the skills and the intention to save the good people of Gotham. But you need more to become โthe Batmanโ. You need your gear... 8th Color is your <a href="http://batman.wikia.com/wiki/Lucius_Fox">Lucius Fox</a>. We want to provide the equipment that turns you into the caped crusader.</p>
<p>In decent English: we want to develop the tools to make your coding better and to help you improve as a coder.</p>
<p><strong>Introducing the Batmobile: PullReview</strong></p>
<p>PullReview is a Code Review tool for Ruby developers using GitHub.</p>
<p>Why Code Review? You might have noticed in previous posts: we are convinced - and weโre <a href="https://web.archive.org/web/20200512220555/https://blog.codinghorror.com/code-reviews-just-do-it/">not alone</a> - that code review is indispensable. It improves your code and it educates you as a programmer. It enables you to - consistently - be the best you can be, project delivery after project delivery.</p>
<p>Just like the Batmobile is not just a car, PullReview his not just a tool. In short, PullReview automatically reviews your code and tells you where to go next to make it - and you - better.</p>
<p><strong>An Automated Tool</strong></p>
<p>PullReview is โSAASโ solution: no servers to install, no extra software. In other words, no need to keep you away of what you do best: coding. Click the button, link to GitHub, and PullReview can start reviewing your branches.</p>
<p>Second of all, PullReview is ready when you are: <a href="https://ibakesoftware.com/blog/fixing-the-marriage-between-flow-code-review/" title="Fixing the Marriage Between Flow & Code Review">your flow is leading</a>. Your feedback is ready at the click of a button, without having to sit and wait for a colleague to come and have look.</p>
<p><strong>Telling You Where to Go Next</strong></p>
<p>Most importantly, it does not keep to static analysis. PullReview aggregates several analysis results, and points you to the problems at hand - in order of impact: it tells you what to do to make your code better - and why it is wrong in the first place.</p>
<p>Weโve repeated it a million times: not only does PullReview make your coding more robust, it improves you as a coder. It tells you why best practices are what they are - and where to apply them. Moreover, as you are getting stronger every review, in your own flow, you free up time to discuss the real Gordian knots in the work at hand.</p>
<p>Thatโs where you take the leap from Bruce Wayne to the Dark Knight. Thatโs what PullReview is about, thatโs what 8th Color is about.</p>
<p><strong>Keeping up to Date</strong></p>
<p>At the moment, PullReview is in Alpha test. For those who canโt wait, weโll provide some preview and tell you more about the functionalities in one of our next posts.</p>
<p>Canโt wait to help the good people of Gotham? apply as an Alpha user, and start banging away at the software!</p>
<p>In any case, subscribe to the <a href="ttps://web.archive.org/web/20130818165309/http://try.pullreview.com/" title="Subscribe to PullReview">mailing list</a> or to the blog, and keep up to date on our launch adventure!</p>
<p>Be well, and spread those wings!</p>
Spring cleanup for object creation in Rails2013-07-17T00:00:00+00:002013-07-17T00:00:00+00:00https://ibakesoftware.com/blog/spring-cleanup-for-object-creation-in-rails/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p><strong>TL;DR</strong> A complex object creation can clutter a controller. It's better to move it into a dedicated method of the corresponding model.</p>
<h2 id="introduction">Introduction<a class="zola-anchor" href="#introduction" aria-label="Anchor link for: introduction">๐</a></h2>
<p><img src="http://farm5.static.flickr.com/4021/4420490349_8bf09159dd_m.jpg" alt="Weeds" /></p>
<p>Cut your Weeds asap.</p>
<p>As software grows, what was once good solution can grow to become a small nuisance - like inoffensive weeds at the side of your driveway. Leaving those weeds unchecked, they become a festering plague. Time to act.</p>
<p>Today, I'll cover one of those cases in Rails: the creation of a new resource.</p>
<p>My goal into this post is to underline the responsibility of the controller and to not clutter it with creation concern. I will offer a first simple solution that allows to fix it.</p>
<h2 id="the-set-up">The Set-Up<a class="zola-anchor" href="#the-set-up" aria-label="Anchor link for: the-set-up">๐</a></h2>
<p>The <code>Blog</code> application as the one illustrating the Rails guide. Nothing is complex in the beginning, and the Post controller looks like a scaffold.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">PostController </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">ApplicationController
</span><span> </span><span style="color:#65737e;">#...
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">create
</span><span> @</span><span style="color:#bf616a;">post </span><span>= </span><span style="color:#ebcb8b;">Post</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(params[</span><span style="color:#a3be8c;">:post</span><span>])
</span><span> </span><span style="color:#b48ead;">if </span><span>@</span><span style="color:#bf616a;">post</span><span>.save
</span><span> redirect_to @</span><span style="color:#bf616a;">post
</span><span> </span><span style="color:#b48ead;">else
</span><span> render </span><span style="color:#a3be8c;">action: </span><span>'</span><span style="color:#a3be8c;">new</span><span>'
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#65737e;">#...
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>Nothing exceptional.</p>
<h2 id="a-few-weeks-later">A Few Weeks Later...<a class="zola-anchor" href="#a-few-weeks-later" aria-label="Anchor link for: a-few-weeks-later">๐</a></h2>
<p>The <code>Blog</code> application has grown: to each post, some statistics are attached such as the number of words, and the used language is automatically detected.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">PostController </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">ApplicationController
</span><span> </span><span style="color:#65737e;">#...
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">create
</span><span> @</span><span style="color:#bf616a;">post </span><span>= </span><span style="color:#ebcb8b;">Post</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(params[</span><span style="color:#a3be8c;">:post</span><span>])
</span><span> @</span><span style="color:#bf616a;">post</span><span>.number_of_links = count_links(@</span><span style="color:#bf616a;">post</span><span>.body)
</span><span> @</span><span style="color:#bf616a;">post</span><span>.number_of_chars = count_chars(@</span><span style="color:#bf616a;">post</span><span>.body)
</span><span> @</span><span style="color:#bf616a;">post</span><span>.number_of_words = count_words(@</span><span style="color:#bf616a;">post</span><span>.body)
</span><span> @</span><span style="color:#bf616a;">post</span><span>.language = detect_language(@</span><span style="color:#bf616a;">post</span><span>.body)
</span><span> </span><span style="color:#b48ead;">if </span><span>@</span><span style="color:#bf616a;">post</span><span>.save
</span><span> redirect_to @</span><span style="color:#bf616a;">post
</span><span> </span><span style="color:#b48ead;">else
</span><span> render </span><span style="color:#a3be8c;">action: </span><span>'</span><span style="color:#a3be8c;">new</span><span>'
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#65737e;">#...
</span><span> </span><span style="color:#8fa1b3;">private
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">count_links</span><span>(</span><span style="color:#bf616a;">text</span><span>)
</span><span> </span><span style="color:#65737e;"># โฆ
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">count_chars</span><span>(</span><span style="color:#bf616a;">text</span><span>)
</span><span> </span><span style="color:#65737e;"># โฆ
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">count_words</span><span>(</span><span style="color:#bf616a;">text</span><span>)
</span><span> </span><span style="color:#65737e;"># โฆ
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">detect_language</span><span>(</span><span style="color:#bf616a;">text</span><span>)
</span><span> </span><span style="color:#65737e;"># โฆ
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#65737e;">#...
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>This code wasn't produced in one change. It's the result of several changes - made at different moments. It looked like the natural place to add everything concerning the creation of a new post. One more line didn't seem to be a problem. Now there are 4 - without counting all the lines for the private methods - 4 more reasons to change the code when creating a new post.</p>
<p>The responsibility of your controller is to make sense of the request and to produce the appropriate output (as <a href="http://guides.rubyonrails.org/action_controller_overview.html#what-does-a-controller-do-questionmark">well expressed in the Rails Guides</a>) - not to take care of the dirty details of a post creation.</p>
<h2 id="the-cut-the-cleanup">The Cut - The Cleanup<a class="zola-anchor" href="#the-cut-the-cleanup" aria-label="Anchor link for: the-cut-the-cleanup">๐</a></h2>
<p>A better place to put those details is the Post model. You could, for instance, use one of the <a href="http://guides.rubyonrails.org/active_record_callbacks.html#creating-an-object">Rails callbacks called when creating an object</a>. Even if it is a totally valid option, I don't use it - as it depends on the Rails framework. I prefer to have a model that could live without it - it helps to have a better OO design and faster tests (Avdi Grimm's book <a href="http://objectsonrails.com/">Objects on Rails</a> gives a great overview of that approach).</p>
<p>The idea is to put all the creation details into a same class method that will return an instance ready to be saved:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Post </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">ActiveRecord::Base
</span><span> </span><span style="color:#65737e;">#...
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#8fa1b3;">build</span><span>(</span><span style="color:#bf616a;">params</span><span>)
</span><span> post = </span><span style="color:#ebcb8b;">Post</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(params)
</span><span> post.number_of_links = count_links(post.body)
</span><span> post.number_of_chars = count_chars(post.body)
</span><span> post.number_of_words = count_words(post.body)
</span><span> post.language = detect_language(post.body)
</span><span> post
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#65737e;">#...
</span><span> </span><span style="color:#8fa1b3;">private
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#8fa1b3;">count_links</span><span>(</span><span style="color:#bf616a;">text</span><span>)
</span><span> </span><span style="color:#65737e;"># โฆ
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#8fa1b3;">count_chars</span><span>(</span><span style="color:#bf616a;">text</span><span>)
</span><span> </span><span style="color:#65737e;"># โฆ
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#8fa1b3;">count_words</span><span>(</span><span style="color:#bf616a;">text</span><span>)
</span><span> </span><span style="color:#65737e;"># โฆ
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#8fa1b3;">detect_language</span><span>(</span><span style="color:#bf616a;">text</span><span>)
</span><span> </span><span style="color:#65737e;"># โฆ
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>The Post controller is much simpler now:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">PostController </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">ApplicationController
</span><span> </span><span style="color:#65737e;">#...
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">create
</span><span> @</span><span style="color:#bf616a;">post </span><span>= </span><span style="color:#ebcb8b;">Post</span><span>.build(params[</span><span style="color:#a3be8c;">:post</span><span>])
</span><span> </span><span style="color:#b48ead;">if </span><span>@</span><span style="color:#bf616a;">post</span><span>.save
</span><span> redirect_to @</span><span style="color:#bf616a;">post
</span><span> </span><span style="color:#b48ead;">else
</span><span> render </span><span style="color:#a3be8c;">action: </span><span>'</span><span style="color:#a3be8c;">new</span><span>'
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#65737e;">#...
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>Now, everything about the creation of a Post instance is in one dedicated class method of the model. After all, it's totally the responsibility of the model. This is commonly called a factory method. There is a very common and known method that already does that: the constructor, i.e. the method initialize. Outside of Rails, it's better to put it in the constructor ( <a href="http://stackoverflow.com/a/629216/831180">except for some specific reasons, e.g. giving it a specific name</a>). But this is <a href="http://stackoverflow.com/questions/8804868/why-is-overriding-activerecordbase-initialize-wrong">Rails - and overriding the constructor will get rid of the ActiveRecords magics</a> (yet it's still possible by explicitly reproducing the magics but <a href="https://www.youtube.com/watch?v=DUgckL0pVfc">don't do this at home</a>).</p>
<p>This is the first step to the <a href="http://en.wikipedia.org/wiki/Factory_method_pattern">Factory Method Pattern</a> . Itโs goel is is to isolate complex process of creation from the object itself - especially when it goes beyond its responsibility or could result into different types. As this is not (yet) our case, I won't go develop further on this.</p>
<p>Having said that, we can finish our cleanup by refactoring our private methods. As we are now into the Post model, we can change them into object method.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Post </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">ActiveRecord::Base
</span><span> </span><span style="color:#65737e;">#...
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#bf616a;">self</span><span>.</span><span style="color:#8fa1b3;">build</span><span>(</span><span style="color:#bf616a;">params</span><span>)
</span><span> post = </span><span style="color:#ebcb8b;">Post</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(params)
</span><span> post.calculate_the_text_stats
</span><span> post.detect_language
</span><span> post
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#65737e;">#...
</span><span> </span><span style="color:#8fa1b3;">private
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">calculate_the_text_stats
</span><span> </span><span style="color:#65737e;"># counting chars, words, and links
</span><span> </span><span style="color:#65737e;"># setting the corresponding attributes
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">detect_language
</span><span> </span><span style="color:#65737e;"># detecting the language and setting the eponym attribute
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<h3 id="references">References<a class="zola-anchor" href="#references" aria-label="Anchor link for: references">๐</a></h3>
<p>Some references if you want go beyond.</p>
<ul>
<li><a href="http://stackoverflow.com/questions/4950454/class-static-instance-initializers-i-e-factory-methods-in-ruby">Class Static Instance Initializers, i.e. factory methods, in Ruby (SO)</a></li>
<li><a href="http://stackoverflow.com/questions/628950/constructors-vs-factory-methods/629216#629216">Constructor vs Factory Methods (SO)</a></li>
<li><a href="http://en.wikipedia.org/wiki/Factory_method_pattern">Factory Method Pattern (wikipedia)</a></li>
<li><a href="http://c2.com/cgi/wiki?FactoryMethodPattern">Factory Method Pattern (c2 wiki)</a></li>
<li><a href="http://stackoverflow.com/questions/10505166/how-to-initialize-an-activerecord-with-values-in-rails">How to initialize an ActiveRecord with values in Rais (SO)</a></li>
<li><a href="https://web.archive.org/web/20160305024706/https://practicingruby.com/articles/creational-design-patterns">Creational Design Patterns</a></li>
<li><a href="https://web.archive.org/web/20130622083534/http://designpatternsinruby.com/section01/article.html">Design Patterns in Ruby (first article)</a></li>
</ul>
<h2 id="conclusion">Conclusion<a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">๐</a></h2>
<p><img src="http://farm4.static.flickr.com/3512/3856462751_df7220738a.jpg" alt="Rail track" /></p>
<p>Don't let your Rails overwhelmed by weeds.</p>
<p>When creation becomes <a href="https://ibakesoftware.com/blog/did-you-say-complexity-eh/" title="Did you say Complexity, eh?">complex</a>, it clutters the controller with details that are not its responsibility. It's necessary to move it elsewhere. We've elaborated on one possible solution: dedicating a class method of the model to that complex creation. That method is commonly called a factory method (but it's not a complete implementation of the Factory Method Pattern).</p>
<p><strong>Don't be overwhelmed by the weeds on your coding driveway</strong>. Ask a reviewer to have a look at your code, or use a tool such as <a href="https://github.com/railsbp/rails_best_practices">RailsBestPractices</a> to automatically detect it.</p>
<p><a href="http://www.zemanta.com/?px" title="Enhanced by Zemanta"><img src="http://img.zemanta.com/zemified_e.png?x-id=b77f0336-d7c3-4880-a872-b5b9e29df6e8" alt="Enhanced by Zemanta" /></a></p>
Did you say Complexity, eh?2013-06-25T00:00:00+00:002013-06-25T00:00:00+00:00https://ibakesoftware.com/blog/did-you-say-complexity-eh/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p><strong>TL;DR</strong> After introducing what <strong>complexity</strong> is, how it can be measured, and how to monitor it in <strong>Ruby</strong> - I'll get to the difficult part: how to reduce it in <strong>Ruby</strong>. The post is concluded with some thoughts and recap.</p>
<h2 id="intro">Intro<a class="zola-anchor" href="#intro" aria-label="Anchor link for: intro">๐</a></h2>
<p><img src="https://i.chzbgr.com/maxW500/4805644288/h0079D701/" alt="" /></p>
<p>Even Vader does not know what are those buttons for.</p>
<p>Developing a feature requires some attention on <a href="https://en.wikipedia.org/wiki/Code_quality">code quality</a> - for the sake of reliability, efficiency, security, and maintainability. If you have been following us, you know that we are not satisfied with code that just works - and nor should you be. One of the ways to achieve good quality is keeping the complexity in check. After introducing what complexity is, how it can be measured, and how to monitor it in Ruby - I'll get to the difficult part: how to reduce it in Ruby.</p>
<p><strong>Disclaimer:</strong> As complexity is not a <em>simple</em> topic and deserves to be illustrated - this post is a bit longer than usual - I hope youโll bear with me. Bookmark it, you can always read it in pieces.</p>
<h2 id="easy-isn-t-it-eek">Easy, isn't it? Eek!<a class="zola-anchor" href="#easy-isn-t-it-eek" aria-label="Anchor link for: easy-isn-t-it-eek">๐</a></h2>
<p>Complexity is a term covering several issues - including <a href="https://en.wikipedia.org/wiki/Computational_complexity_theory">time and space complexity of an algorithm</a>. In this case, we're talking about <a href="https://en.wikipedia.org/wiki/Programming_Complexity">code complexity</a> i.e. how complex it is to understand and modify your code. For a machine, it makes no difference. For another human being, the case is entirely different. Complex code is hard to read - hard to modify - and hard to debug (yep, we're writing code for humans). It impacts the maintainability and reliability of the software directly .</p>
<p>As code complexity has many facets, it is not so easy to summarize it with a single measure. Several measures have been developed, each one allowing to grab one aspect of complexity.As an introduction, weโll be covering the Cyclomatic Complexity metric and the ABC metric.</p>
<h3 id="cyclomatic-complexity">Cyclomatic Complexity<a class="zola-anchor" href="#cyclomatic-complexity" aria-label="Anchor link for: cyclomatic-complexity">๐</a></h3>
<p>The most known metric is the <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity">cyclomatic complexity</a> indicator. It measures how many paths of execution are possible through the code. If there is no branch (neither loop nor exception rescue), then there is only one path (i.e. the code is purely sequential) and the complexity equals to 1.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">hello_world
</span><span> </span><span style="color:#96b5b4;">puts </span><span>"</span><span style="color:#a3be8c;">Hello world</span><span>"
</span><span style="color:#b48ead;">end
</span></code></pre>
<p><img src="/blog/images/sQT6xYcRvnZonASI7l_iWGw.png" alt="Cyclomatic Complexity: one path" /></p>
<p>Each time you add a branch or a loop, you create new paths - and complexity increases. For instance, adding one if-clause results in two paths, and a complexity equaling 2.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">hello</span><span>(</span><span style="color:#bf616a;">name</span><span>)
</span><span> </span><span style="color:#b48ead;">if </span><span style="color:#96b5b4;">name
</span><span> </span><span style="color:#96b5b4;">puts </span><span>"</span><span style="color:#a3be8c;">Hello </span><span>#{</span><span style="color:#96b5b4;">name</span><span>}"
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p><img src="/blog/images/s978anLFjQfr4h8T1URtptw.png" alt="Cyclomatic Complexity: 2 paths" /></p>
<p>Its evaluation is easy, especially when considering only one possible exit point, i.e. one return:</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>NB + 1
</span></code></pre>
<p>where <em>NB</em> is the number of branch and loop keywords. If you consider multiple exit points, it is:</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>NB - NR + 2
</span></code></pre>
<p>where <em>NR</em> is the number of returns. For instance, if we're rewriting the previous example with a guard clause, we have now a complexity equals to 1 as we have 2 exit points.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">hello</span><span>(</span><span style="color:#bf616a;">name</span><span>)
</span><span> </span><span style="color:#b48ead;">return unless </span><span style="color:#96b5b4;">name
</span><span> </span><span style="color:#96b5b4;">puts </span><span>"</span><span style="color:#a3be8c;">Hello </span><span>#{</span><span style="color:#96b5b4;">name</span><span>}"
</span><span style="color:#b48ead;">end
</span></code></pre>
<p><img src="/blog/images/ssUQEfA0JIJ_NarZ6ok4cYA.png" alt="Cylomatic Complexity: 2 exit points" /></p>
<p>By nesting more and more branches, weโll get the <a href="http://www.c2.com/cgi/wiki?ArrowAntiPattern">Arrow Anti-Pattern</a> with a high cyclomatic complexity.</p>
<p>Really sizing up its meaning needs some experience. However, <a href="https://web.archive.org/web/20131107130442/http://stackoverflow.com/questions/20702/whats-your-a-good-limit-for-cyclomatic-complexity">according to the community</a> and according to <a href="https://resources.sei.cmu.edu/asset_files/Handbook/1997_002_001_16523.pdf">some</a> <a href="http://www.mccabe.com/pdf/MeasuringSoftwareComplexityUAV.pdf">studies</a>, 11 seems to be a good sanity threshold at a module/class level. This is not just a number, it has been observed that <strong><a href="https://web.archive.org/web/20111010142601/http://www.enerjy.com/blog/?p=198">defects and cyclomatic complexity are correlated</a></strong>!</p>
<h3 id="the-abc-metric">The ABC Metric<a class="zola-anchor" href="#the-abc-metric" aria-label="Anchor link for: the-abc-metric">๐</a></h3>
<p><a href="http://c2.com/cgi/wiki?AbcMetric">ABC</a> is not <em>per se</em> a complexity metric. It is <a href="http://en.wikipedia.org/wiki/Software_quality#Size">a measure of number statements and structures</a>. Still, it is accepted that functional size has an impact on the complexity: a method with a lot of instructions, assignments, calls, branches, and other structures will be more complex and harder to understand - due to its size. ABC is computed as a function distance of the number of: assignments (<em>A</em>), branches (<em>B</em>), and conditions (<em>C</em>):</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>|ABC| = sqrt( A * A + B * B + C * C )
</span></code></pre>
<p>Each language having its peculiarities, the counting of <em>A</em>, <em>B</em>, and <em>C</em> must be adjusted accordingly. Basically, it consists in deciding to which category <em>A</em>, <em>B</em>, and <em>C</em> a keyword and other language structure belongs - and how to count it. It's a good complementary metric to cyclomatic complexity as it takes into account more than just branches.</p>
<p>For instance, if we count unless for 1 as branch, assignment for 1, and function call for 1 as branch, the following code has a ABC metric of <em>sqrt(1ยฒ + 2ยฒ + 0ยฒ) = ~2.2</em>:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">hello</span><span>(</span><span style="color:#bf616a;">name</span><span>)
</span><span> </span><span style="color:#b48ead;">return unless </span><span style="color:#96b5b4;">name
</span><span> greetings = "</span><span style="color:#a3be8c;">Hello </span><span>#{</span><span style="color:#96b5b4;">name</span><span>}"
</span><span> </span><span style="color:#96b5b4;">puts</span><span> greetings
</span><span style="color:#b48ead;">end
</span></code></pre>
<h2 id="you-hoo-gi-me-a-ruler">You-hoo! Gi'me a ruler!<a class="zola-anchor" href="#you-hoo-gi-me-a-ruler" aria-label="Anchor link for: you-hoo-gi-me-a-ruler">๐</a></h2>
<blockquote>
<p>"Give them a tool, the use of which will lead to new ways of thinking." Richard Buckminster Fuller</p>
</blockquote>
<p>Metrics without measuring tools - rulers - are useless. In Ruby, <a href="http://ruby.sadi.st/Flog.html">Flog</a> or <a href="https://github.com/mainmatter/excellent">Excellent</a> are among the best known and most actively used tools.</p>
<h3 id="flog">Flog<a class="zola-anchor" href="#flog" aria-label="Anchor link for: flog">๐</a></h3>
<p><a href="https://github.com/seattlerb/flog">Flog</a> is a kind of extended ABC metrics tool for Ruby. The <em>C</em> stands for call - <em>not condition</em> - in this case - as Flog puts a particular accent on it. For instance, a call to <a href="https://github.com/seattlerb/flog/blob/master/lib/flog.rb#L61">metaprogramming methods</a> <a href="https://github.com/seattlerb/flog/blob/master/lib/flog.rb#L70">has a higher weight</a> than to a normal method.</p>
<p>As with every metric, you need some experience to really <a href="http://jakescruggs.blogspot.be/2008/08/whats-good-flog-score.html">weigh a Flog score</a> for a single method. The range <em>[20, 60]</em> is considered as a gray zone, needing some personal contemplation: it could be due to the business domain - or it's a true candidate for refactoring.</p>
<h3 id="excellent">Excellent<a class="zola-anchor" href="#excellent" aria-label="Anchor link for: excellent">๐</a></h3>
<p><a href="https://github.com/mainmatter/excellent">Excellent</a> is not a single โrulerโ, it's a set of checks and metrics that you can easily apply together on a codebase. As for complexity metrics, it includes <a href="https://github.com/mainmatter/excellent/wiki/AbcMetricMethodCheck">ABC metric</a>, an approximated <a href="https://github.com/simplabs/excellent/wiki/CyclomaticComplexityMethodCheck">cyclomatic complexity</a>, and a <a href="https://github.com/mainmatter/excellent/wiki/FlogMethodCheck">Flog-like score</a>.</p>
<h2 id="aye-it-s-high-but-how-to-reduce-it">Aye! It's high, but how to reduce it?<a class="zola-anchor" href="#aye-it-s-high-but-how-to-reduce-it" aria-label="Anchor link for: aye-it-s-high-but-how-to-reduce-it">๐</a></h2>
<p>A metric (tool) is a way to check and evaluate how critical the situation is. It will get your attention to some piece of code and push you to ask yourself: do I need to refactor? Using tools like Flog and Excellent, this is only the easy part.</p>
<p>A score - while interesting - does not give any clue <em>how</em> to fix your code. One cannot say: when you have a score <em>A</em> you need to do this, and with a score <em>B</em> you have to do that. You need to investigate the situation to understand what's wrong and how you can refactor your code.</p>
<p>To address these doubts it might be useful following common guidelines as the <a href="http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29">SOLID</a> ones. In the next paragraphs, Iโll be offering several solutions in different typical use cases. The examples are intentionally stupid to clearly illustrate the idea.</p>
<h3 id="conditional-execution-of-a-method">Conditional execution of a method<a class="zola-anchor" href="#conditional-execution-of-a-method" aria-label="Anchor link for: conditional-execution-of-a-method">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">buy
</span><span> </span><span style="color:#b48ead;">if</span><span> available?
</span><span> </span><span style="color:#96b5b4;">puts </span><span>'</span><span style="color:#a3be8c;">buy</span><span>'
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#65737e;">#
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">available?
</span><span> </span><span style="color:#d08770;">false
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>buy</code></td><td>2.3</td><td>2</td></tr>
<tr><td><code>available?</code></td><td>0</td><td>1</td></tr>
</tbody></table>
<p>It's impossible to buy a <code>Book</code> if it's not <code>available?</code>. It's very common that a method canโt be run under some conditions - <a href="https://en.wikipedia.org/wiki/Precondition">preconditions</a>. Wrapping the block with an <em>if-clause</em> makes the normal path unclear - especially if there are several ones. In order to isolate business logic and preconditions, it's better to use <a href="http://c2.com/cgi/wiki?GuardClause">guard clauses</a> to stop execution in the beginning if the conditions are met. This can be done with <code>Exception</code> or by directly <code>return</code>.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">buy
</span><span> </span><span style="color:#65737e;"># with Exception
</span><span> </span><span style="color:#8fa1b3;">raise </span><span>'</span><span style="color:#a3be8c;">The book is not available</span><span>' </span><span style="color:#b48ead;">unless</span><span> available?
</span><span> </span><span style="color:#65737e;"># without
</span><span> </span><span style="color:#b48ead;">return unless</span><span> available?
</span><span>
</span><span> </span><span style="color:#96b5b4;">puts </span><span>'</span><span style="color:#a3be8c;">buy</span><span>'
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#65737e;">#
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">available?
</span><span> </span><span style="color:#d08770;">false
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>buy</code> (without exception)</td><td>2.3</td><td>1</td></tr>
<tr><td><code>buy</code> (with exception)</td><td>3.3</td><td>1</td></tr>
<tr><td><code>available?</code></td><td>0</td><td>1</td></tr>
</tbody></table>
<h3 id="conditional-behavior-of-a-method">Conditional behavior of a method<a class="zola-anchor" href="#conditional-behavior-of-a-method" aria-label="Anchor link for: conditional-behavior-of-a-method">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price</span><span>(</span><span style="color:#bf616a;">number_of_copies</span><span>)
</span><span> total = @</span><span style="color:#bf616a;">price
</span><span> </span><span style="color:#b48ead;">if</span><span> number_of_copies > </span><span style="color:#d08770;">50
</span><span> total = @</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">0.75
</span><span> </span><span style="color:#b48ead;">elsif</span><span> number_of_copies > </span><span style="color:#d08770;">20
</span><span> total = @</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">0.85
</span><span> </span><span style="color:#b48ead;">elsif</span><span> number_of_copies > </span><span style="color:#d08770;">10
</span><span> total = @</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">0.95
</span><span> </span><span style="color:#b48ead;">end
</span><span> total
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>price</code></td><td>9.7</td><td>4</td></tr>
</tbody></table>
<p>The <code>price</code> of the <code>Book</code> depends on the number of purchased copies. The method <code>price</code> returns conditionally a value for different special cases. It has been implemented by following the school of <a href="http://c2.com/cgi/wiki?SingleFunctionExitPoint">one single exit point</a>. By doing this, you enforce dealing with multiple cases at the same time. It makes the reading more difficult. <a href="http://stackoverflow.com/questions/4838828/why-should-a-function-have-only-one-exit-point">Sometimes, it's still better to keep a single exit point, other times not</a>. If you can delimit a clear behavioral scope for each special case and assign an exit gate, <a href="http://refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html">directly returning the value</a> will generally make the code clearer and simpler (I let the reader check the impact on cyclomatic complexity). In our case, it's better to exit as soon as the <code>price</code> is calculated.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price</span><span>(</span><span style="color:#bf616a;">number_of_copies</span><span>)
</span><span> </span><span style="color:#b48ead;">return </span><span>@</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">0.75 </span><span style="color:#b48ead;">if</span><span> number_of_copies > </span><span style="color:#d08770;">50
</span><span> </span><span style="color:#b48ead;">return </span><span>@</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">0.85 </span><span style="color:#b48ead;">if</span><span> number_of_copies > </span><span style="color:#d08770;">20
</span><span> </span><span style="color:#b48ead;">return </span><span>@</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">0.95 </span><span style="color:#b48ead;">if</span><span> number_of_copies > </span><span style="color:#d08770;">10
</span><span> @</span><span style="color:#bf616a;">price
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>price</code></td><td>7.8</td><td>1</td></tr>
</tbody></table>
<p>One other option is to extract the condition into a dedicated method <code>get_percentage(number_of_copies)</code> and use a <code>Hash</code> to store the mapping between the percentage and the conditional <code>number_of_copies</code> (I'll use this approach below in the section "Repetitive conditional behavior").</p>
<h3 id="condition-depending-on-types">Condition depending on types<a class="zola-anchor" href="#condition-depending-on-types" aria-label="Anchor link for: condition-depending-on-types">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#b48ead;">end
</span><span style="color:#65737e;">#
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">DVD
</span><span style="color:#b48ead;">end
</span><span style="color:#65737e;">#
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Shop
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">how_much_does_it_cost</span><span>(</span><span style="color:#bf616a;">product</span><span>)
</span><span> price = </span><span style="color:#d08770;">0
</span><span> </span><span style="color:#b48ead;">if</span><span> product.</span><span style="color:#96b5b4;">is_a? </span><span style="color:#bf616a;">Book
</span><span> price = </span><span style="color:#d08770;">5
</span><span> </span><span style="color:#b48ead;">elsif</span><span> product.</span><span style="color:#96b5b4;">is_a? </span><span style="color:#bf616a;">DVD
</span><span> price = </span><span style="color:#d08770;">10
</span><span> </span><span style="color:#b48ead;">end
</span><span> price
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>how_much_does_it_cost</code></td><td>5.2</td><td>3</td></tr>
</tbody></table>
<p>You can buy two kinds of product in the <code>Shop</code>: <code>Book</code> and <code>DVD</code>. That <code>Shop</code> practices a pricing only depending on the kind of product. At first, in the method <code>how_much_does_it_cost</code>, the <code>product</code> type is tested to decide the price. If you add a new <em>product</em> type, you'll need to add other <em>if-clauses</em> and make the method more complex (and lead you to the <a href="https://en.wikipedia.org/wiki/God_object">God Object anti-pattern</a>). In fact, <a href="https://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming">polymorphism</a> is an object oriented mechanism that allows you to exactly do that: implementing different behaviors for different types. Using it helps drastically reducing complexity. In our case, we just need to put the <code>price</code> in the product classes <code>Book</code> and <code>DVD</code>.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price
</span><span> </span><span style="color:#d08770;">5
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span style="color:#65737e;">#
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">DVD
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price
</span><span> </span><span style="color:#d08770;">10
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span style="color:#65737e;">#
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Shop
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">how_much_does_it_cost?</span><span>(</span><span style="color:#bf616a;">product</span><span>)
</span><span> product.price
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>Shop#how_much_does_it_cost</code></td><td>1.1</td><td>1</td></tr>
<tr><td><code>DVD#price</code></td><td>0.3</td><td>1</td></tr>
<tr><td><code>Book#price</code></td><td>0.3</td><td>1</td></tr>
<tr><td><strong>Total</strong></td><td>1.7</td><td>3</td></tr>
</tbody></table>
<h3 id="nil-guard-clause">Nil guard clause<a class="zola-anchor" href="#nil-guard-clause" aria-label="Anchor link for: nil-guard-clause">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#65737e;"># somewhere in you Shop code
</span><span style="color:#65737e;"># โฆ
</span><span style="color:#b48ead;">if</span><span> product
</span><span> </span><span style="color:#96b5b4;">puts</span><span> product.</span><span style="color:#96b5b4;">name
</span><span style="color:#b48ead;">end
</span><span style="color:#65737e;"># โฆ
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>Shop#somewhere</code></td><td>2.6</td><td>2</td></tr>
</tbody></table>
<p>How many times did you not guard a call on a <code>nil</code> object? Whatever the reason, if you have a <code>nil</code> object, you cannot call a method. Each time you can have a <code>nil</code>, it is necessary to guard a call on it.</p>
<p>This could be resolved with the <a href="https://en.wikipedia.org/wiki/Null_object_pattern">Null Object pattern</a> (another option with Ruby on Rails consists in using the method <em><a href="http://apidock.com/rails/Object/try">try</a></em>). The idea is simply to provide a model of the absence of object with a compatible interface with the used type, i.e. calling a method on an instance of it won't throw a <code>NoMethodError</code> exception and won't do anything. You can implement your own or require a Gem providing it such as the excellent <a href="https://github.com/avdi/naught">Naught</a> by Avdi Grimm. Once done, you can remove the guard clauses.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#65737e;"># somewhere in you Shop code
</span><span style="color:#65737e;"># โฆ
</span><span style="color:#96b5b4;">puts</span><span> product.</span><span style="color:#96b5b4;">name
</span><span style="color:#65737e;"># โฆ
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>main</code></td><td>2.2</td><td>1</td></tr>
</tbody></table>
<h3 id="multiple-branches-leading-to-a-same-statement-or-return-value">Multiple branches leading to a same statement or return value<a class="zola-anchor" href="#multiple-branches-leading-to-a-same-statement-or-return-value" aria-label="Anchor link for: multiple-branches-leading-to-a-same-statement-or-return-value">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price
</span><span> </span><span style="color:#b48ead;">if </span><span>@</span><span style="color:#bf616a;">pocket
</span><span> </span><span style="color:#b48ead;">return </span><span style="color:#d08770;">5
</span><span> </span><span style="color:#b48ead;">else
</span><span> </span><span style="color:#b48ead;">if </span><span>@</span><span style="color:#bf616a;">second_hand
</span><span> </span><span style="color:#b48ead;">return </span><span style="color:#d08770;">5
</span><span> </span><span style="color:#b48ead;">else
</span><span> </span><span style="color:#b48ead;">return </span><span style="color:#d08770;">10
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td>price</td><td>2.3</td><td>1</td></tr>
</tbody></table>
<p>For two different conditions ( <em>@pocket</em> and <em>@second_hand</em>), the same <code>price</code> value is returned: 5. This can at least be combined as a single conditional expression thanks to <a href="http://en.wikipedia.org/wiki/Boolean_algebras_canonically_defined">Boolean algebra</a> (this is called <a href="http://www.refactoring.com/catalog/consolidateConditionalExpression.html">ConsolidateConditional</a> refactoring).</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price
</span><span> </span><span style="color:#b48ead;">return </span><span style="color:#d08770;">5 </span><span style="color:#b48ead;">if </span><span>@</span><span style="color:#bf616a;">pocket </span><span>|| @</span><span style="color:#bf616a;">second_hand
</span><span> </span><span style="color:#d08770;">10
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td>price</td><td>2.1</td><td>1</td></tr>
</tbody></table>
<p>It is also a good practice to extract complex Boolean expression into a <a href="http://mestachs.wordpress.com/2012/11/26/through-the-eyes-of-sonar-complexity/">dedicated method</a> (this is called <a href="http://www.refactoring.com/catalog/decomposeConditional.html">DecomposeConditional</a> refactoring). It will be easier to modify and to reuse.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price
</span><span> </span><span style="color:#b48ead;">return </span><span style="color:#d08770;">5 </span><span style="color:#b48ead;">if</span><span> reduced_price?
</span><span> </span><span style="color:#d08770;">10
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#65737e;">#
</span><span> </span><span style="color:#8fa1b3;">private
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">reduced_price?
</span><span> @</span><span style="color:#bf616a;">pocket </span><span>|| @</span><span style="color:#bf616a;">second_hand
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>price</code></td><td>1.8</td><td>1</td></tr>
<tr><td><code>reduced_price?</code></td><td>1.0</td><td>1</td></tr>
<tr><td><strong>Total</strong></td><td>2.8</td><td>2</td></tr>
</tbody></table>
<p>If you need to implement a deep <a href="http://en.wikipedia.org/wiki/Decision_tree">decision tree</a> with multiple conditions and possible outputs (for instance when dealing with taxes in accounting), you'll probably need to use a <a href="https://github.com/jmettraux/rufus-decision#usage">dedicated library</a>.</p>
<h3 id="long-method">Long method<a class="zola-anchor" href="#long-method" aria-label="Anchor link for: long-method">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Shop
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">inventory_missing_products
</span><span> </span><span style="color:#65737e;"># calculates the number of sold
</span><span> nbr_of_sold = </span><span style="color:#96b5b4;">Hash</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">0</span><span>)
</span><span> receipts.each </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">receipt</span><span>|
</span><span> nbr_of_sold[receipt.product.</span><span style="color:#96b5b4;">name</span><span>] += </span><span style="color:#d08770;">1
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#65737e;">#
</span><span> </span><span style="color:#65737e;"># calculates the number of stock
</span><span> nbr_in_stock = </span><span style="color:#96b5b4;">Hash</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">0</span><span>)
</span><span> products_in_stock.each </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">product</span><span>|
</span><span> nbr_in_stock[product.</span><span style="color:#96b5b4;">name</span><span>] += </span><span style="color:#d08770;">1
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#65737e;">#
</span><span> </span><span style="color:#65737e;"># calculate missing products
</span><span> nbr_of_bought.inject(</span><span style="color:#96b5b4;">Hash</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">0</span><span>)) </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">missing_of</span><span>, (</span><span style="color:#bf616a;">name</span><span>, </span><span style="color:#bf616a;">nbr</span><span>)|
</span><span> missing_of[</span><span style="color:#96b5b4;">name</span><span>] = nbr - nbr_of_sold - nbr_in_stock
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>inventory_missing_products</code></td><td>18.6</td><td>4</td></tr>
</tbody></table>
<p>The method <code>inventory_missing_products</code> couldn't calculate the number of missing products without knowing two other amounts <code>nbr_of_sold</code> and <code>nbr_in_stock</code>. In our case, we calculated them in the same method. As you read, we needed to make clear that we have 3 different goals to achieve - by putting comments and adding separation white line. For the sake of clarity, it would be better to <a href="http://refactoring.com/catalog/extractMethod.html">extract those preliminary calculations into dedicated methods</a>. By doing so, we'll have smaller methods - with well defined goal and scope - and lower complexity. Of course, the total complexity won't be reduced (it could even be increased), but the complexity of each method will be now โdecentโ.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Shop
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">inventory_missing_products
</span><span> nbr_of_sold = how_many_sold_products
</span><span> nbr_in_stock = how_many_products_in_stock
</span><span> nbr_of_bought.inject(</span><span style="color:#96b5b4;">Hash</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">0</span><span>)) </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">missing_of</span><span>, (</span><span style="color:#bf616a;">name</span><span>, </span><span style="color:#bf616a;">nbr</span><span>)|
</span><span> missing_of[</span><span style="color:#96b5b4;">name</span><span>] = nbr - nbr_of_sold - nbr_in_stock
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#65737e;">#
</span><span> </span><span style="color:#8fa1b3;">private
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">how_many_sold_products
</span><span> receipts.inject(</span><span style="color:#96b5b4;">Hash</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">0</span><span>)) </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">nbr_of_sold</span><span>, </span><span style="color:#bf616a;">receipt</span><span>|
</span><span> nbr_of_sold[receipt.product.</span><span style="color:#96b5b4;">name</span><span>] += </span><span style="color:#d08770;">1
</span><span> nbr_of_sold
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#65737e;">#
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">how_many_products_in_stock
</span><span> products_in_stock.inject(</span><span style="color:#96b5b4;">Hash</span><span>.</span><span style="color:#8fa1b3;">new</span><span>(</span><span style="color:#d08770;">0</span><span>)) </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">nbr_in_stock</span><span>, </span><span style="color:#bf616a;">product</span><span>|
</span><span> nbr_in_stock[product.</span><span style="color:#96b5b4;">name</span><span>] += </span><span style="color:#d08770;">1
</span><span> nbr_in_stock
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>inventory_missing_products</code></td><td>10.9</td><td>2</td></tr>
<tr><td><code>how_many_sold_products</code></td><td>7.4</td><td>2</td></tr>
<tr><td><code>how_many_products_in_stock</code></td><td>6.0</td><td>2</td></tr>
<tr><td><strong>Total</strong></td><td>25.3</td><td>6</td></tr>
</tbody></table>
<p>This is also valid for branch and loop blocks and their expression. When the block becomes too long or the expression contains too many clauses, it's always better to extract them into a separate method. A method has a great benefit over a block that shouldn't be underestimated: it has a name.</p>
<h3 id="repetitive-conditional-behaviors">Repetitive conditional behaviors<a class="zola-anchor" href="#repetitive-conditional-behaviors" aria-label="Anchor link for: repetitive-conditional-behaviors">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Shop
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">calculate_total_price</span><span>(</span><span style="color:#bf616a;">price</span><span>, </span><span style="color:#bf616a;">country</span><span>)
</span><span> </span><span style="color:#b48ead;">case</span><span> country
</span><span> </span><span style="color:#b48ead;">when </span><span>'</span><span style="color:#a3be8c;">BE</span><span>'
</span><span> </span><span style="color:#b48ead;">return </span><span style="color:#d08770;">0.7 </span><span>* price + price * </span><span style="color:#d08770;">0.21
</span><span> </span><span style="color:#b48ead;">when </span><span>'</span><span style="color:#a3be8c;">FR</span><span>'
</span><span> </span><span style="color:#b48ead;">return</span><span> price + price * </span><span style="color:#d08770;">0.20
</span><span> </span><span style="color:#b48ead;">when </span><span>'</span><span style="color:#a3be8c;">UK</span><span>'
</span><span> </span><span style="color:#b48ead;">return </span><span>[</span><span style="color:#d08770;">0.9 </span><span>* price - </span><span style="color:#d08770;">1.0</span><span>, </span><span style="color:#d08770;">5.0</span><span>].max + price * </span><span style="color:#d08770;">0.20
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>calculate_total_price</code></td><td>14.6</td><td>1</td></tr>
</tbody></table>
<p>The <code>Shop</code> is spread over Europe: this means a different VAT per country. The <code>Shop</code> also applies different promotions depending on the <code>country</code>. There is clearly a pattern common to each country: the <code>price</code> with promo + the VAT (that needs to be applied on the original <code>price</code>). We have <a href="https://ibakesoftware.com/blog/duplication-is-a-rampant-disease/" title="Duplication is a Rampant Disease">duplicated codes</a> and conditionals. We can do better.</p>
<p>If we want to keep the freedom to change the promo rules, we have a good candidate to apply the <a href="http://en.wikipedia.org/wiki/Strategy_pattern">Strategy pattern</a>, i.e. to extract the calculation of the promo as a <a href="http://www.refactoring.com/catalog/replaceMethodWithMethodObject.html">Method Object</a> that could be specialized if needed. In order to illustrate another option, we'll use another similar functional approach: using lambdas. It's especially suited for small functions. Finally, to get rid of the case branches, we'll use a <em>Hash</em>.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Shop
</span><span style="color:#eff1f5;"> </span><span>PROMO_RULE_PER_COUNTRY = {
</span><span> '</span><span style="color:#a3be8c;">BE</span><span>' => ->(price) { price * </span><span style="color:#d08770;">0.7 </span><span>},
</span><span> '</span><span style="color:#a3be8c;">UK</span><span>' => ->(price) { [price * </span><span style="color:#d08770;">0.9 </span><span>- </span><span style="color:#d08770;">1.0</span><span>, </span><span style="color:#d08770;">5.0</span><span>].max }
</span><span> }
</span><span> </span><span style="color:#ebcb8b;">PROMO_RULE_PER_COUNTRY</span><span>.default = ->(price) { price }
</span><span style="color:#65737e;">#
</span><span> VAT_PER_COUNTRY = {
</span><span> '</span><span style="color:#a3be8c;">BE</span><span>' => </span><span style="color:#d08770;">0.21</span><span>,
</span><span> '</span><span style="color:#a3be8c;">FR</span><span>' => </span><span style="color:#d08770;">0.20</span><span>,
</span><span> '</span><span style="color:#a3be8c;">UK</span><span>' => </span><span style="color:#d08770;">0.20
</span><span> }
</span><span> </span><span style="color:#ebcb8b;">VAT_RULE_PER_COUNTRY</span><span>.default = </span><span style="color:#d08770;">0.0
</span><span style="color:#65737e;">#
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">calculate_total_price</span><span>(</span><span style="color:#bf616a;">price</span><span>, </span><span style="color:#bf616a;">country</span><span>)
</span><span> </span><span style="color:#b48ead;">return </span><span style="color:#ebcb8b;">PROMO_RULE_PER_COUNTRY</span><span>[country].call(price) + </span><span style="color:#ebcb8b;">VAT_RULE_PER_COUNTRY</span><span>[country] * price
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<table><thead><tr><th>method</th><th>Flog Score</th><th>Cyclomatic Complexity</th></tr></thead><tbody>
<tr><td><code>calculate_total_price</code></td><td>6.2</td><td>1</td></tr>
<tr><td><code>Shop#constants</code></td><td>8.8</td><td>-</td></tr>
<tr><td><strong>Total</strong></td><td>15.0</td><td>1</td></tr>
</tbody></table>
<h3 id="other-cases">Other cases<a class="zola-anchor" href="#other-cases" aria-label="Anchor link for: other-cases">๐</a></h3>
<p>There are too many possible cases to be broken down in a simple - be it long - blog post like this one - to discuss different design pattern and refactoring methods. Enough material to write ten other posts. We'll surely keep them into our list of potential topics!</p>
<h3 id="some-references">Some References<a class="zola-anchor" href="#some-references" aria-label="Anchor link for: some-references">๐</a></h3>
<ul>
<li><a href="https://web.archive.org/web/20220125105731/https://blog.codinghorror.com/flattening-arrow-code/">Flattening Arrow Code</a> by Jeff Atwood</li>
<li><a href="http://refactoring.com/catalog/">Refactorings catalog</a> maintained by Martin Fowler</li>
<li><a href="http://www.railsinside.com/tutorials/487-how-to-score-your-rails-apps-complexity-before-refactoring.html">How To Score Your Rails App's Complexity Before Refactoring</a> by Eric Davis</li>
<li><a href="http://mestachs.wordpress.com/2012/11/26/through-the-eyes-of-sonar-complexity/">Through the eyes of Sonar: Complexity</a> by Stรฉphan Mestach</li>
<li><a href="https://github.com/thoughtbot/ruby-science">Ruby Science</a> by Thoughtbot</li>
</ul>
<h2 id="closing-thoughts-hmm">Closing Thoughts, hmm.<a class="zola-anchor" href="#closing-thoughts-hmm" aria-label="Anchor link for: closing-thoughts-hmm">๐</a></h2>
<p>Without any external point of view, it's difficult to realize that - while some piece of code seems easy to you - it's complex for others. Indeed, we don't necessarily think in the same way. Even if you take care, your code will become more complex quickly. A code base is a living thing - and evolves through the changes made. What was simple can become progressively complex - one little change after another. A Code Analysis Tool or - better - a Code Review (Tool) can underline the complexity and catch your attention. It is then possible - and necessary - to act.</p>
<table><thead><tr><th>Case</th><th>Refactoring</th></tr></thead><tbody>
<tr><td>conditional execution of a method</td><td><a href="http://c2.com/cgi/wiki?GuardClause">Guard clauses</a></td></tr>
<tr><td>conditional behavior of a method</td><td><a href="http://refactoring.com/catalog/replaceNestedConditionalWithGuardClauses.html">Opportunistic return</a></td></tr>
<tr><td>condition depending on types</td><td><a href="https://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming">Polymorphism</a></td></tr>
<tr><td>nil guard clause</td><td><a href="https://en.wikipedia.org/wiki/Null_object_pattern">Null Object Pattern</a></td></tr>
<tr><td>multiple branches leading to same statement or return</td><td><a href="http://www.refactoring.com/catalog/consolidateConditionalExpression.html">ConsolidateConditional</a> and <a href="http://www.refactoring.com/catalog/decomposeConditional.html">DecomposeConditional</a></td></tr>
<tr><td>long method</td><td><a href="http://refactoring.com/catalog/extractMethod.html">ExtractMethod</a></td></tr>
<tr><td>repetitive conditional behaviors</td><td><a href="http://en.wikipedia.org/wiki/Strategy_pattern">Strategy Pattern</a>, lambda</td></tr>
<tr><td>other cases</td><td><a href="http://refactoring.com/catalog/">Refactoring</a>, <a href="http://en.wikipedia.org/wiki/Design_pattern">Design Pattern</a>, etc.</td></tr>
</tbody></table>
<p>In the end, all those refactoring methods allow to reduce, move, or split the complexity. The goal is to make the work units - like functions, methods, classes, and modules - easier: easier to read - easier to understand - easier to change - easier to debug and to maintain. Sometimes - however - a higher score is better:</p>
<ul>
<li>the tackled business domain is complex - full of exceptions and conditions, or</li>
<li>the <a href="http://jakescruggs.blogspot.be/2008/01/when-you-should-ignore-metrics.html">simpler alternative uses more advanced language structure and libraries</a>, making it more complex.</li>
</ul>
<h2 id="conclusion-whoa">Conclusion. Whoa!<a class="zola-anchor" href="#conclusion-whoa" aria-label="Anchor link for: conclusion-whoa">๐</a></h2>
<blockquote>
<p>"Fools ignore complexity. Pragmatists suffer it. Some can avoid it. Geniuses remove it." <a href="http://en.wikipedia.org/wiki/Alan_Perlis">Alen Perlis</a></p>
</blockquote>
<p>Each metric grabs a different aspect of complexity. In the end, the devs are the only ones that can correctly interpret each case. Anyway, objectively pointing to complex locations is a good way to catch the attention - not only yours but also the code reviewerโs. Complexity is effectively a complex question - bringing you back to the <a href="https://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29">basics</a>. It initiates discussion with the code reviewer. Automated tools and code review are complementary approaches that will significantly help you to control code complexity.</p>
Duplication is a Rampant Disease2013-06-05T00:00:00+00:002013-06-05T00:00:00+00:00https://ibakesoftware.com/blog/duplication-is-a-rampant-disease/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>When your code base is growing, it's very unlikely that you and your devmates won't create any <a href="https://en.wikipedia.org/wiki/Duplicate_code">duplication</a>. There are multiple reasons, but in all cases it's an undesirable situation that you want to get rid off. After briefly recalling some of those reasons - discussing why you should fix it asap - I'll describe some solutions in Ruby and Ruby on Rails.</p>
<h2 id="it-will-infect-you-whatever-precautions-you-take">It will infect you - whatever precautions you take<a class="zola-anchor" href="#it-will-infect-you-whatever-precautions-you-take" aria-label="Anchor link for: it-will-infect-you-whatever-precautions-you-take">๐</a></h2>
<p>The first obvious reason is the copy-paste. For example: while implementing a feature, you need to compute some value derived from model values. You know there are few lines doing exactly that - somewhere in the code. After you have found said lines you just copy-paste them to the location of choice. <strong>A duplication is born, and a kitten dies.</strong></p>
<p>A duplication is born and a kitten dies</p>
<p>This kind of duplication can be avoided by not copy-pasting and directly refactoring the code. However, you can also create duplication and similarities without realizing it, eg.:</p>
<ul>
<li>you're reproducing a well practiced pattern and don't remember that you - or a colleague - have already used it elsewhere,</li>
<li>you're evolving a data structure towards a form very similar to another existing one,</li>
<li>you're implementing a functionality that someone else has already implemented but in another way and totally encapsulated in a class, etc.</li>
</ul>
<p>You can forbid copy-paste, you can know your code base very well, but duplication will still happen - simply because the code is evolving and similarities can be created implicitly.</p>
<h2 id="you-need-external-diagnosis">You need external diagnosis<a class="zola-anchor" href="#you-need-external-diagnosis" aria-label="Anchor link for: you-need-external-diagnosis">๐</a></h2>
<p>That's why the only way to underline duplication is</p>
<p>by using tools capable to identify it. In Ruby, <a href="http://ruby.sadi.st/Flay.html">Flay</a> is probably the best known tool to detect similarities in code. It does a very good job, and not only on <a href="https://www.zenspider.com/ruby/2013/03/fuzzy-duplication-detection-in-flay.html">exact duplicates or syntactical trees</a>. Having the tool is not enough, however. You need to actually run it - regularly. You should run it in sync with your tests, on your continuous integration server, when you commit. <strong>If it's not automatic, you'll forget it</strong>.</p>
<h2 id="fight-duplication-now">Fight duplication - now<a class="zola-anchor" href="#fight-duplication-now" aria-label="Anchor link for: fight-duplication-now">๐</a></h2>
<p><img src="http://farm1.static.flickr.com/77/219575939_79a0b732b6_m.jpg" alt="Zombies Invade San Francisco!" /></p>
<p>Don't let them duplicate. Fight them.</p>
<p><strong>Duplication means that the abstraction mechanisms of the programming language such as methods or classes are not correctly used</strong>. The code is longer what it could be, and more code means more bugs. The code is less maintainable - as multiple places need to be modified when necessary. So, without explicitly tracking your duplications - a hick-up happens quickly. More importantly, it will also affect the understanding of the code base - especially for newcomers. Longer and repetitive code is a good way to obfuscate it - not to make it more readable.</p>
<h2 id="you-ll-need-multiple-treatments">You'll need multiple treatments<a class="zola-anchor" href="#you-ll-need-multiple-treatments" aria-label="Anchor link for: you-ll-need-multiple-treatments">๐</a></h2>
<p>In the following, I'll give several solutions in different typical use cases. The examples are intentionally stupid to clearly illustrate the idea.</p>
<h3 id="same-class-same-method">Same class, same method<a class="zola-anchor" href="#same-class-same-method" aria-label="Anchor link for: same-class-same-method">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#65737e;"># โฆ
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">some_method
</span><span> </span><span style="color:#65737e;"># โฆ
</span><span> total = chapters.</span><span style="color:#96b5b4;">select</span><span>{ |</span><span style="color:#bf616a;">chapter</span><span>| !chapter.title.empty?}.count
</span><span> titles = chapters.</span><span style="color:#96b5b4;">select</span><span>{ |</span><span style="color:#bf616a;">chapter</span><span>| !chapter.title.empty?}.map(&</span><span style="color:#a3be8c;">:title</span><span>)
</span><span> </span><span style="color:#65737e;"># ...
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>Twice, it is needed to <code>select</code> only the <code>chapters</code> with a non empty title. This a very simple duplication case. You just need to extract the select into a local variable <code>chapters_with_non_empty_titles</code> and use it.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span> </span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#65737e;"># โฆ
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">some_method
</span><span> </span><span style="color:#65737e;"># โฆ
</span><span> chapters_with_non_empty_titles = chapters.</span><span style="color:#96b5b4;">select</span><span>{ |</span><span style="color:#bf616a;">chapter</span><span>| !chapter.title.empty?}
</span><span> total = chapters_with_non_empty_titles.count
</span><span> titles = chapters_with_non_empty_titles.map(&</span><span style="color:#a3be8c;">:title</span><span>)
</span><span> </span><span style="color:#65737e;"># ...
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<h3 id="same-class-different-methods">Same class, different methods<a class="zola-anchor" href="#same-class-different-methods" aria-label="Anchor link for: same-class-different-methods">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">html_cover
</span><span> "</span><span style="color:#a3be8c;"><li></span><span>#{title}</span><span style="color:#a3be8c;"> by </span><span>#{author}</span><span style="color:#a3be8c;"></li></span><span>"
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">md_cover
</span><span> "</span><span style="color:#a3be8c;">* </span><span>#{title}</span><span style="color:#a3be8c;"> by </span><span>#{author}"
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>In both methods - <code>html_cover</code> and <code>md_cover</code>, the same code is used to print the book cover page. You need to extract that piece of code and create a dedicated method for it, <em>cover_page</em>. This is called a <a href="https://en.wikipedia.org/wiki/Extract_Method#List_of_refactoring_techniques">Extract Method</a>.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">html
</span><span> "</span><span style="color:#a3be8c;"><li></span><span>#{cover_page}</span><span style="color:#a3be8c;"></li></span><span>"
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">print_cover
</span><span> "</span><span style="color:#a3be8c;">* </span><span>#{cover_page}"
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#8fa1b3;">private
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">cover_page
</span><span> "#{title}</span><span style="color:#a3be8c;"> by </span><span>#{author}"
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<h3 id="sibling-classes">Sibling classes<a class="zola-anchor" href="#sibling-classes" aria-label="Anchor link for: sibling-classes">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Media
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">Media
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">cover_page
</span><span> "#{title}</span><span style="color:#a3be8c;"> by </span><span>#{author}"
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">DVD </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">Media
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">cover_page
</span><span> "#{title}</span><span style="color:#a3be8c;"> by </span><span>#{author}"
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>In both sibling classes <code>Book</code> and <code>DVD</code>, the same <code>cover_page</code> method is used. By putting it in the parent class <code>Media</code>, the duplication is removed. This is called a <a href="https://en.wikipedia.org/wiki/Pull_Up_refactoring">Pull Up</a>.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Media
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">cover_page
</span><span> "#{title}</span><span style="color:#a3be8c;"> by </span><span>#{author}"
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">Media
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">DVD </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">Media
</span><span style="color:#b48ead;">end
</span></code></pre>
<h3 id="different-classes-same-kind-of-type">Different classes, same kind of type<a class="zola-anchor" href="#different-classes-same-kind-of-type" aria-label="Anchor link for: different-classes-same-kind-of-type">๐</a></h3>
<pre data-lang="Ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-Ruby "><code class="language-Ruby" data-lang="Ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">DVD
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>You only had <code>Book</code> type, but you've just added the <code>DVD</code> type. They have same attributes โฆ and they are a same kind of data. You just need to introduce a parent class <code>Media</code> generalizing that type. This is called a <a href="https://en.wikipedia.org/wiki/Generalize_Type">Type Generalization</a>.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Media
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">Media
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">DVD </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">Media
</span><span style="color:#b48ead;">end
</span></code></pre>
<h3 id="different-classes-different-kind-of-type">Different classes, different kind of type<a class="zola-anchor" href="#different-classes-different-kind-of-type" aria-label="Anchor link for: different-classes-different-kind-of-type">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>, </span><span style="color:#bf616a;">price</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> @</span><span style="color:#bf616a;">price </span><span>= price
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price_with_taxes
</span><span> @</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">1.21
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">JournalSubscription
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">name</span><span>, </span><span style="color:#bf616a;">price</span><span>)
</span><span> @</span><span style="color:#bf616a;">name </span><span>= </span><span style="color:#96b5b4;">name
</span><span> @</span><span style="color:#bf616a;">price </span><span>= price
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price_with_taxes
</span><span> @</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">1.21
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>Both classes <code>Book</code> and <code>JournalSubscription</code> have a method to calculate the price with taxes (here Belgian VAT of 21%). For different reasons, they are not considered of the same type: we cannot generalize. One way is to use a <a href="http://en.wikipedia.org/wiki/Mixin">mixin</a> to put the method <code>price_with_taxes</code> in one module <code>Price</code>, that both classes will include. The other way is using a <a href="https://en.wikipedia.org/wiki/Strategy_pattern">Strategy pattern</a> as illustrated in the next section.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">module </span><span>Price
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price_with_taxes
</span><span> @</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">1.21
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#8fa1b3;">include </span><span style="color:#bf616a;">Price
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>, </span><span style="color:#bf616a;">price</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> @</span><span style="color:#bf616a;">price </span><span>= price
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">JournalSubscription
</span><span style="color:#eff1f5;">
</span><span style="color:#eff1f5;"> </span><span style="color:#8fa1b3;">include </span><span style="color:#bf616a;">Price
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">name</span><span>, </span><span style="color:#bf616a;">price</span><span>)
</span><span> @</span><span style="color:#bf616a;">name </span><span>= </span><span style="color:#96b5b4;">name
</span><span> @</span><span style="color:#bf616a;">price </span><span>= price
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<h3 id="different-classes-different-type-different-functionalities">Different classes, different type, different functionalities<a class="zola-anchor" href="#different-classes-different-type-different-functionalities" aria-label="Anchor link for: different-classes-different-type-different-functionalities">๐</a></h3>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>, </span><span style="color:#bf616a;">price</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> @</span><span style="color:#bf616a;">price </span><span>= price
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price_with_taxes</span><span>(</span><span style="color:#bf616a;">country</span><span>)
</span><span> </span><span style="color:#b48ead;">case</span><span> country
</span><span> </span><span style="color:#b48ead;">when </span><span>'</span><span style="color:#a3be8c;">FR</span><span>'
</span><span> @</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">1.07
</span><span> </span><span style="color:#b48ead;">when </span><span>'</span><span style="color:#a3be8c;">BE</span><span>'
</span><span> @</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">1.12
</span><span> </span><span style="color:#b48ead;">else
</span><span> @</span><span style="color:#bf616a;">price
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">JournalSubscription
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">name</span><span>, </span><span style="color:#bf616a;">price</span><span>)
</span><span> @</span><span style="color:#bf616a;">name </span><span>= </span><span style="color:#96b5b4;">name
</span><span> @</span><span style="color:#bf616a;">price </span><span>= price
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price_with_taxes</span><span>(</span><span style="color:#bf616a;">country</span><span>)
</span><span> </span><span style="color:#b48ead;">case</span><span> country
</span><span> </span><span style="color:#b48ead;">when </span><span>'</span><span style="color:#a3be8c;">FR</span><span>'
</span><span> @</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">1.20
</span><span> </span><span style="color:#b48ead;">when </span><span>'</span><span style="color:#a3be8c;">BE</span><span>'
</span><span> @</span><span style="color:#bf616a;">price </span><span>* </span><span style="color:#d08770;">1.21
</span><span> </span><span style="color:#b48ead;">else
</span><span> @</span><span style="color:#bf616a;">price
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>Both classes <code>Book</code> and <code>JournalSubscription</code> have to calculate a price with taxes considering the <code>country</code> where the good is bought. Rather than duplicating the way you can calculate each good, you can put it in a dedicated object <code>PriceWithTaxes</code>. For each <code>country</code>, you add a subclass with the corresponding rule to calculate the price considering a full or reduced VAT. When calling the method <code>price_with_taxes()</code> on a <code>Book</code> instance, you then just need to pass it the good <code>PriceWithTaxes</code> instance, like</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>my_book.price_with_taxes(</span><span style="color:#ebcb8b;">PriceWithTaxesInBE</span><span>.</span><span style="color:#8fa1b3;">new</span><span>)
</span></code></pre>
<p>This is a <a href="https://en.wikipedia.org/wiki/Strategy_pattern">Strategy pattern</a> that will allow you to change at runtime which taxes rule you want to use.</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">PriceWithTaxes
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">total</span><span>(</span><span style="color:#bf616a;">price</span><span>, </span><span style="color:#bf616a;">reduced</span><span>=</span><span style="color:#d08770;">false</span><span>)
</span><span> price
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">PriceWithTaxesInBE
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">total</span><span>(</span><span style="color:#bf616a;">price</span><span>, </span><span style="color:#bf616a;">reduced</span><span>=</span><span style="color:#d08770;">false</span><span>)
</span><span> reduced ? price * </span><span style="color:#d08770;">1.12 </span><span>: price * </span><span style="color:#d08770;">1.21
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">PriceWithTaxesInFR
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">total</span><span>(</span><span style="color:#bf616a;">price</span><span>, </span><span style="color:#bf616a;">reduced</span><span>=</span><span style="color:#d08770;">false</span><span>)
</span><span> reduced ? price * </span><span style="color:#d08770;">1.07 </span><span>: price * </span><span style="color:#d08770;">1.20
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>, </span><span style="color:#bf616a;">price</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> @</span><span style="color:#bf616a;">price </span><span>= price
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price_with_taxes</span><span>(</span><span style="color:#bf616a;">rule_in_country</span><span>)
</span><span> rule_in_country.total(@</span><span style="color:#bf616a;">price</span><span>, </span><span style="color:#d08770;">true</span><span>)
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">JournalSubscription
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">name</span><span>, </span><span style="color:#bf616a;">price</span><span>)
</span><span> @</span><span style="color:#bf616a;">name </span><span>= </span><span style="color:#96b5b4;">name
</span><span> @</span><span style="color:#bf616a;">price </span><span>= price
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price_with_taxes</span><span>(</span><span style="color:#bf616a;">rule_in_country</span><span>)
</span><span> rule_in_country.total(@</span><span style="color:#bf616a;">price</span><span>, </span><span style="color:#d08770;">false</span><span>)
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>A quick note about <code>total()</code> method. As you probably notice, its behavior depends on the boolean <code>reduced</code>. It is not good design: it's like two methods in one. It can be resolved by using specialization and polymorphism. But we'll tackle that topic in a next blog post.</p>
<p>Another implementation would use the block and yield to it as following:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Book
</span><span style="color:#eff1f5;"> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">initialize</span><span>(</span><span style="color:#bf616a;">title</span><span>, </span><span style="color:#bf616a;">author</span><span>, </span><span style="color:#bf616a;">price</span><span>)
</span><span> @</span><span style="color:#bf616a;">title </span><span>= title
</span><span> @</span><span style="color:#bf616a;">author </span><span>= author
</span><span> @</span><span style="color:#bf616a;">price </span><span>= price
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">price_with_taxes</span><span>(&</span><span style="color:#bf616a;">block</span><span>)
</span><span> </span><span style="color:#b48ead;">yield </span><span>@</span><span style="color:#bf616a;">price</span><span>, </span><span style="color:#d08770;">true
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>Then, pass a block to a <code>Book</code> instance <code>my_book</code>:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>my_book.price_with_taxes </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">price</span><span>, </span><span style="color:#bf616a;">reduced</span><span>|
</span><span> reduced ? price * </span><span style="color:#d08770;">1.12 </span><span>: price * </span><span style="color:#d08770;">1.21
</span><span style="color:#b48ead;">end
</span></code></pre>
<h3 id="some-ruby-on-rails-use-cases">Some Ruby on Rails use cases<a class="zola-anchor" href="#some-ruby-on-rails-use-cases" aria-label="Anchor link for: some-ruby-on-rails-use-cases">๐</a></h3>
<p>There are duplication cases specific to Ruby on Rails applications, and there are also solutions for them.</p>
<h4 id="same-content-in-views">Same content in Views<a class="zola-anchor" href="#same-content-in-views" aria-label="Anchor link for: same-content-in-views">๐</a></h4>
<pre data-lang="erb" style="background-color:#2b303b;color:#c0c5ce;" class="language-erb "><code class="language-erb" data-lang="erb"><span># app/views/books/index.html.erb
</span><span>
</span><span><</span><span style="color:#bf616a;">ul</span><span>>
</span><span style="color:#ab7967;"><% </span><span>@</span><span style="color:#bf616a;">books</span><span>.each </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">book</span><span>| </span><span style="color:#ab7967;">%>
</span><span> </span><span style="color:#ab7967;"><%=</span><span> book.html </span><span style="color:#ab7967;">%>
</span><span style="color:#ab7967;"><% </span><span style="color:#b48ead;">end </span><span style="color:#ab7967;">%>
</span><span></</span><span style="color:#bf616a;">ul</span><span>>
</span><span>
</span><span># app/views/dvds/index.html.erb
</span><span>
</span><span><</span><span style="color:#bf616a;">ul</span><span>>
</span><span style="color:#ab7967;"><% </span><span>@</span><span style="color:#bf616a;">dvds</span><span>.each </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">dvd</span><span>| </span><span style="color:#ab7967;">%>
</span><span> </span><span style="color:#ab7967;"><%=</span><span> dvd.html </span><span style="color:#ab7967;">%>
</span><span style="color:#ab7967;"><% </span><span style="color:#b48ead;">end </span><span style="color:#ab7967;">%>
</span><span></</span><span style="color:#bf616a;">ul</span><span>>
</span></code></pre>
<p>Both Views call for the method html on <code>Book</code> and <code>DVD</code> instances. It will be better to put that same way to present them in a <a href="http://guides.rubyonrails.org/layouts_and_rendering.html#rendering-collections">partial to render a collection</a>.</p>
<pre data-lang="erb" style="background-color:#2b303b;color:#c0c5ce;" class="language-erb "><code class="language-erb" data-lang="erb"><span># app/views/books/index.html.erb
</span><span>
</span><span><</span><span style="color:#bf616a;">ul</span><span>>
</span><span style="color:#ab7967;"><%= </span><span style="color:#96b5b4;">render </span><span style="color:#a3be8c;">partial: </span><span>'</span><span style="color:#a3be8c;">medias/index</span><span>', </span><span style="color:#a3be8c;">collection: </span><span>@</span><span style="color:#bf616a;">books</span><span>, </span><span style="color:#a3be8c;">as: :item </span><span style="color:#ab7967;">%>
</span><span></</span><span style="color:#bf616a;">ul</span><span>>
</span><span>
</span><span># app/views/dvds/index.html.erb
</span><span>
</span><span><</span><span style="color:#bf616a;">ul</span><span>>
</span><span style="color:#ab7967;"><%= </span><span style="color:#96b5b4;">render </span><span style="color:#a3be8c;">partial: </span><span>'</span><span style="color:#a3be8c;">medias/index</span><span>', </span><span style="color:#a3be8c;">collection: </span><span>@</span><span style="color:#bf616a;">dvds</span><span>, </span><span style="color:#a3be8c;">as: :item </span><span style="color:#ab7967;">%>
</span><span></</span><span style="color:#bf616a;">ul</span><span>>
</span><span>
</span><span># app/views/medias/_index.html.erb
</span><span>
</span><span style="color:#ab7967;"><%=</span><span> item.html </span><span style="color:#ab7967;">%>
</span></code></pre>
<h4 id="same-logic-in-views">Same logic in Views<a class="zola-anchor" href="#same-logic-in-views" aria-label="Anchor link for: same-logic-in-views">๐</a></h4>
<pre data-lang="erb" style="background-color:#2b303b;color:#c0c5ce;" class="language-erb "><code class="language-erb" data-lang="erb"><span># app/views/books/index.html.erb
</span><span>
</span><span><</span><span style="color:#bf616a;">h1</span><span>>My library</</span><span style="color:#bf616a;">h1</span><span>>
</span><span style="color:#ab7967;"><% </span><span>@</span><span style="color:#bf616a;">books</span><span>.each </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">book</span><span>| </span><span style="color:#ab7967;">%>
</span><span> <</span><span style="color:#bf616a;">h2</span><span>></span><span style="color:#ab7967;"><%=</span><span> book.title.titleize </span><span style="color:#ab7967;">%></span><span> by </span><span style="color:#ab7967;"><%=</span><span> book.author.titleize </span><span style="color:#ab7967;">%></span><span></</span><span style="color:#bf616a;">h2</span><span>>
</span><span style="color:#ab7967;"><% </span><span style="color:#b48ead;">end </span><span style="color:#ab7967;">%>
</span><span>
</span><span># app/views/books/show.html.erb
</span><span>
</span><span><</span><span style="color:#bf616a;">h1</span><span>></span><span style="color:#ab7967;"><%= </span><span>@</span><span style="color:#bf616a;">book</span><span>.title.titleize </span><span style="color:#ab7967;">%></span><span> by </span><span style="color:#ab7967;"><%= </span><span>@</span><span style="color:#bf616a;">book</span><span>.author.titleize </span><span style="color:#ab7967;">%></span><span></</span><span style="color:#bf616a;">h1</span><span>>
</span></code></pre>
<p>In two different <code>Book</code> Views, we're using a same logic to present the <code>title</code> and the <code>author</code> of the book. It will be better to put it into a dedicated helper.</p>
<pre data-lang="erb" style="background-color:#2b303b;color:#c0c5ce;" class="language-erb "><code class="language-erb" data-lang="erb"><span># app/views/books/index.html.erb
</span><span>
</span><span><</span><span style="color:#bf616a;">h1</span><span>>My library</</span><span style="color:#bf616a;">h1</span><span>>
</span><span style="color:#ab7967;"><% </span><span>@</span><span style="color:#bf616a;">books</span><span>.each </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">book</span><span>| </span><span style="color:#ab7967;">%>
</span><span> <</span><span style="color:#bf616a;">h2</span><span>></span><span style="color:#ab7967;"><%=</span><span> headline_of(book) </span><span style="color:#ab7967;">%></span><span></</span><span style="color:#bf616a;">h2</span><span>>
</span><span style="color:#ab7967;"><% </span><span style="color:#b48ead;">end </span><span style="color:#ab7967;">%>
</span><span>
</span><span># app/views/books/show.html.erb
</span><span>
</span><span><</span><span style="color:#bf616a;">h1</span><span>></span><span style="color:#ab7967;"><%=</span><span> headline_of(@</span><span style="color:#bf616a;">book</span><span>) </span><span style="color:#ab7967;">%></span><span></</span><span style="color:#bf616a;">h1</span><span>>
</span><span>
</span><span># app/helpers/books_helpers.rb
</span><span>
</span><span>module BooksHelpers
</span><span> def headline_of(book)
</span><span> "#{book.title.titleize} by #{book.author.titleize}"
</span><span> end
</span><span>end
</span></code></pre>
<h2 id="conclusion">Conclusion<a class="zola-anchor" href="#conclusion" aria-label="Anchor link for: conclusion">๐</a></h2>
<p>A code base lives through all the changes made - and itโs hard to have a clear and perfect knowledge of its state. Some duplications can be avoided, others are more subtle and implicit. Some data type could evolve to a common ground or some similar algorithms used in different places - without realizing their similarities. <strong>Duplication is more about structural similarities than identical code. It's about using similar patterns of type, of function, of abstraction in a least two different places.</strong></p>
<table><thead><tr><th><strong>Where</strong></th><th><strong>Refactoring</strong></th></tr></thead><tbody>
<tr><td>Same method</td><td>Extract Local Variable</td></tr>
<tr><td>Same class</td><td><a href="http://www.refactoring.com/catalog/extractMethod.html">Extract Method</a></td></tr>
<tr><td>Same type</td><td><a href="http://www.refactoring.com/catalog/extractSuperclass.html">Generalization</a>, <a href="http://www.refactoring.com/catalog/pullUpMethod.html">Pull Up</a></td></tr>
<tr><td>Different type</td><td><a href="https://en.wikipedia.org/wiki/Strategy_pattern">Strategy Pattern</a> or <a href="http://en.wikipedia.org/wiki/Mixin">Mixin</a></td></tr>
<tr><td>Same content in Views</td><td><a href="http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials">Partials</a></td></tr>
<tr><td>Same presentation logic in Views</td><td><a href="https://en.wikibooks.org/wiki/Ruby_on_Rails/ActionView/Custom_Helpers">Helpers</a></td></tr>
</tbody></table>
<p>Duplication is a plague that will infect all your codebase if you donโt act to detect and fix it. A tool as Flay will help you a lot, but it's not perfect - as some duplications could exist at a very abstract level. You still need to be careful - to share the knowledge of the code base - to enforce co-ownership, by code review or pair programming. Someone else could then underline some pattern similar to those he has already used elsewhere. But with very large code base, it becomes harder. Automated tool and code review are complimentary approaches that will help you to fight duplications.</p>
Git tips and tricks 22013-05-22T00:00:00+00:002013-05-22T00:00:00+00:00https://ibakesoftware.com/blog/git-tips-and-tricks-2/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>Since the last time I've <a href="https://ibakesoftware.com/blog/git-tips-and-tricks/" title="Git tips and tricks">shared a set of tips and tricks about Git</a>, I've learned new ones that I regularly use. Again, hope they could help you as they helped me. Enjoy!</p>
<h2 id="how-to-show-the-difference-between-two-branches-for-a-same-file">How to show the difference between two branches for a same file?<a class="zola-anchor" href="#how-to-show-the-difference-between-two-branches-for-a-same-file" aria-label="Anchor link for: how-to-show-the-difference-between-two-branches-for-a-same-file">๐</a></h2>
<p>While you're coding into a <code><file></code> on a feature branch <code>feature/mybranch</code>, it is often useful to see exactly what you've changed. It's time to get a diff with the master branch:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> diff master HEAD -- <file>
</span></code></pre>
<p>or simply</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> diff master -- <file>
</span></code></pre>
<p>You suddenly remember that one colleague told you he is also working on the same file in his own branch <code>feature/hisbranch</code>. You're curious to see the changes he made compared with the yours:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> diff feature/hisbranch HEAD -- <file>
</span></code></pre>
<h2 id="how-to-stop-tracking-a-file">How to stop tracking a file?<a class="zola-anchor" href="#how-to-stop-tracking-a-file" aria-label="Anchor link for: how-to-stop-tracking-a-file">๐</a></h2>
<p>An output <code><file></code> is tracked when it shouldn't be. You put it into <code>.gitignore</code>, but it's still there. It's because you need to remove it from the index with</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> rm</span><span style="color:#bf616a;"> --cached </span><span><file>
</span></code></pre>
<p>Then, you just need to commit that change</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> commit
</span></code></pre>
<h2 id="how-to-show-the-diff-with-the-staged-changes">How to show the diff with the staged changes?<a class="zola-anchor" href="#how-to-show-the-diff-with-the-staged-changes" aria-label="Anchor link for: how-to-show-the-diff-with-the-staged-changes">๐</a></h2>
<p>You've staged several changes at different moments, so you're not sure anymore what were your changes exactly. You would like to inspect them before committing. Just type</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> diff</span><span style="color:#bf616a;"> --cached
</span></code></pre>
<h2 id="how-to-pick-only-a-part-of-a-given-commit">How to pick only a part of a given commit?<a class="zola-anchor" href="#how-to-pick-only-a-part-of-a-given-commit" aria-label="Anchor link for: how-to-pick-only-a-part-of-a-given-commit">๐</a></h2>
<p>Someone has just merged a branch containing an important security fix that you would like to apply in your feature branch. But the fix wasn't committed alone. There are other changes that don't interest you. You only want a part of the commit. First of all, you need to cherry pick it and put in stage</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> cherry-pick</span><span style="color:#bf616a;"> -n </span><span><commit>
</span></code></pre>
<p>Then, unstage all the changes</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> reset
</span></code></pre>
<p>Stage only the changes containing the security fix</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> add <file>
</span></code></pre>
<p>Finally commit them.</p>
<h2 id="how-to-dry-run-merge">How to dry run merge?<a class="zola-anchor" href="#how-to-dry-run-merge" aria-label="Anchor link for: how-to-dry-run-merge">๐</a></h2>
<p>You don't like surprises. Before merging master into a feature branch, you would like to dryly run the merge. First you need to retrieve the common ancestor</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> merge-base HEAD master
</span></code></pre>
<p>Then, you can run the merge in memory with git merge-tree</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> merge-tree <sha-obtained-with-merge-base> master HEAD
</span></code></pre>
<p>That will give you the result of a merge without changing the working copy.</p>
<h2 id="how-to-prune-all-your-local-branches-that-track-an-already-deleted-remote-branch">How to prune all your local branches that track an already-deleted remote branch?<a class="zola-anchor" href="#how-to-prune-all-your-local-branches-that-track-an-already-deleted-remote-branch" aria-label="Anchor link for: how-to-prune-all-your-local-branches-that-track-an-already-deleted-remote-branch">๐</a></h2>
<p>You're tracking some remote branches, but you don't know that some of them have been remotely deleted. Git pull won't remove those ones when you pull, you need to delete them with a specific command:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> remote prune origin</span><span style="color:#bf616a;"> --dry-run
</span></code></pre>
<p>will give you a list of staled remote branches. If you're ok with that list, you can effectively prune them without the parameter <code>--dry-run</code></p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> remote prune origin
</span></code></pre>
<p>That's it for today.</p>
<p>Do you have you a git command that you use daily? Donโt hesitate - please share it!</p>
Use your custom Bootstrap icons in your Rails apps2013-05-03T00:00:00+00:002013-05-03T00:00:00+00:00https://ibakesoftware.com/blog/use-your-custom-bootstrap-icons-in-your-rails-apps/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<p>Twitter Bootstrap offers a <a href="http://twitter.github.io/bootstrap/base-css.html#icons">great set of icons provided by Glyphicons</a> that you can use easily in your pages. For instance,</p>
<p><img src="/blog/images/icon-ok.png" alt="icon-ok" /></p>
<pre data-lang="html" style="background-color:#2b303b;color:#c0c5ce;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#bf616a;">i </span><span style="color:#d08770;">class</span><span>="</span><span style="color:#a3be8c;">icon-ok</span><span>"></</span><span style="color:#bf616a;">i</span><span>>
</span></code></pre>
<p>If you don't like those icons, you can use <a href="https://fontawesome.com/">Font Awesome</a> instead of.</p>
<p>But how can you <a href="http://fontello.com/">use other icon sets</a> or even your own icons in your Rails app with the same facility?</p>
<pre data-lang="html" style="background-color:#2b303b;color:#c0c5ce;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#bf616a;">i </span><span style="color:#d08770;">class</span><span>="</span><span style="color:#a3be8c;">myicon-great</span><span>"></</span><span style="color:#bf616a;">i</span><span>>
</span></code></pre>
<p>I'll present you a solution based on the gems <a href="https://github.com/jakesgordon/sprite-factory">sprite-factory</a> and <a href="https://github.com/thomas-mcdonald/bootstrap-sass">bootstrap-sass</a>. It requires your icons to follow a precise specification, a custom stylesheet and a Rake task to generate them.</p>
<h2 id="the-icon-specification">The icon specification<a class="zola-anchor" href="#the-icon-specification" aria-label="Anchor link for: the-icon-specification">๐</a></h2>
<p>The icon dimensions are 60x56 and stored as a SVG file <code>myicon.svg</code> in the directory <code>app/assets/images/icons/</code>. When drawing the icon, try to keep in mind that the icon dimensions will be reduced to 15x14: draw everything as a multiple of 4.</p>
<h2 id="the-stylesheet">The stylesheet<a class="zola-anchor" href="#the-stylesheet" aria-label="Anchor link for: the-stylesheet">๐</a></h2>
<p>The technique of <a href="http://coding.smashingmagazine.com/2009/04/27/the-mystery-of-CSS-sprites-techniques-tools-and-tutorials/">CSS sprites</a> allows you to gather all background images in a single file. You then display only the part you want with a clipping rectangle defined by the dimensions of your block element and the background position. Twitter Bootstrap provides all the icons as is. If you look into the <a href="https://github.com/twbs/bootstrap-sass/blob/2.0-stable/vendor/assets/stylesheets/bootstrap/_sprites.scss">sass-bootstrap stylesheet defining the icons class</a>, you'll find three important parts:</p>
<ul>
<li>the common properties to all icon classes<code>[class^="icon-"], [class*=" icon-"]</code>,</li>
<li>the properties for inverted icon<code>icon-white</code>, and</li>
<li>a sprite for each icon, for instance<code>.icon-glass { background-position: 0 0; }</code>.</li>
</ul>
<p>For our own icons with a class name starting with <code>myicon-</code>, we'll do the first and last part (no inverted version). The properties common to all icons are the following:</p>
<p><strong><code>app/assets/stylesheets/_mysprites.scss</code></strong></p>
<pre data-lang="scss" style="background-color:#2b303b;color:#c0c5ce;" class="language-scss "><code class="language-scss" data-lang="scss"><span style="color:#8fa1b3;">[</span><span style="color:#d08770;">class</span><span>^="</span><span style="color:#a3be8c;">myicon-</span><span>"</span><span style="color:#8fa1b3;">]</span><span style="color:#b48ead;">, </span><span style="color:#8fa1b3;">[</span><span style="color:#d08770;">class</span><span>*="</span><span style="color:#a3be8c;"> myicon-</span><span>"</span><span style="color:#8fa1b3;">] </span><span>{
</span><span> display: inline-block;
</span><span> width: </span><span style="color:#d08770;">15px</span><span>;
</span><span> height: </span><span style="color:#d08770;">14px</span><span>;
</span><span> line-height: </span><span style="color:#d08770;">14px</span><span>;
</span><span> vertical-align: text-top;
</span><span> background-image: </span><span style="color:#96b5b4;">url</span><span>('</span><span style="color:#a3be8c;">icons.png</span><span>');
</span><span> background-position: </span><span style="color:#d08770;">15px 14px</span><span>;
</span><span> background-repeat: no-repeat;
</span><span> margin-top: </span><span style="color:#d08770;">0</span><span>;
</span><span> vertical-align: text-bottom;
</span><span>}
</span></code></pre>
<p>For the last part defining the CSS sprites themselves, we'll use sprite-factory.</p>
<h2 id="the-generation">The generation<a class="zola-anchor" href="#the-generation" aria-label="Anchor link for: the-generation">๐</a></h2>
<p>The gem <a href="https://github.com/jakesgordon/sprite-factory">sprite-factory</a> will help you to pack all icons in one file and generate the corresponding CSS sprites. It can even be used in a Rake task.</p>
<p>First write the dedicated Rake task</p>
<p><strong><code>lib/tasks/resprite.rake</code></strong></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#8fa1b3;">require </span><span>'</span><span style="color:#a3be8c;">sprite_factory</span><span>'
</span><span>
</span><span>namespace </span><span style="color:#a3be8c;">:assets </span><span style="color:#b48ead;">do
</span><span>desc '</span><span style="color:#a3be8c;">recreate sprite images and css</span><span>'
</span><span>task </span><span style="color:#a3be8c;">:resprite </span><span>=> </span><span style="color:#a3be8c;">:environment </span><span style="color:#b48ead;">do
</span><span> </span><span style="color:#65737e;"># your task that we'll describe below
</span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>As we have icons as SVG files, I add first a command using the magic <code>convert</code> command of ImageMagick to transform them into PNG files with dimensions of <code>15x14</code>:</p>
<p><strong><code>lib/tasks/resprite.rake</code></strong></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#65737e;"># ...
</span><span style="color:#ebcb8b;">Dir</span><span>.glob('</span><span style="color:#a3be8c;">app/assets/images/icons/*.svg</span><span>').each </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">svg_file</span><span>|
</span><span> %x(</span><span style="color:#a3be8c;">convert -antialias -background transparent </span><span>#{svg_file}</span><span style="color:#a3be8c;"> -resize 15x14 </span><span>#{</span><span style="color:#ebcb8b;">File</span><span>.dirname svg_file}</span><span style="color:#a3be8c;">/</span><span>#{</span><span style="color:#ebcb8b;">File</span><span>.basename(svg_file).</span><span style="color:#96b5b4;">gsub</span><span>(/</span><span style="color:#96b5b4;">\.svg\z</span><span>/, "</span><span style="color:#a3be8c;">.png</span><span>")} )
</span><span style="color:#b48ead;">end
</span><span style="color:#65737e;"># ...
</span></code></pre>
<p>Then, I set up sprite-factory to use sass-rails helper method <code>image-url</code> to be evaluated by the rails asset pipeline:</p>
<p><strong><code>lib/tasks/resprite.rake</code></strong></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#65737e;"># ...
</span><span style="color:#ebcb8b;">SpriteFactory</span><span>.cssurl = "</span><span style="color:#a3be8c;">image-url('$IMAGE')</span><span>"
</span><span style="color:#65737e;"># ...
</span></code></pre>
<p>I define an array <code>rules</code> of CSS directives that will be used by sprite-factory to generate the stylesheet, and already append to it the definition of common properties to all classes <code>myicon-</code>:</p>
<p><strong><code>lib/tasks/resprite.rake</code></strong></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#65737e;"># ...
</span><span>rules = []
</span><span>rules << <<EOF
</span><span style="color:#a3be8c;">[class^="myicon-"], [class*=" myicon-"] {
</span><span style="color:#a3be8c;">display: inline-block;
</span><span style="color:#a3be8c;">width: 15px;
</span><span style="color:#a3be8c;">height: 14px;
</span><span style="color:#a3be8c;">line-height: 14px;
</span><span style="color:#a3be8c;">vertical-align: text-top;
</span><span style="color:#a3be8c;">background-image: url('icons.png');
</span><span style="color:#a3be8c;">background-position: 15px 14px;
</span><span style="color:#a3be8c;">background-repeat: no-repeat;
</span><span style="color:#a3be8c;">margin-top: 0;
</span><span style="color:#a3be8c;">vertical-align: text-bottom;
</span><span style="color:#a3be8c;">}
</span><span>EOF
</span><span style="color:#65737e;"># ...
</span></code></pre>
<p>Finally, I run sprite-factory with some <a href="https://github.com/jakesgordon/sprite-factory#customization">parameters</a></p>
<p><strong><code>lib/tasks/resprite.rake</code></strong></p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#65737e;"># ...
</span><span style="color:#ebcb8b;">SpriteFactory</span><span>.run!(
</span><span> '</span><span style="color:#a3be8c;">app/assets/images/icons</span><span>',
</span><span> </span><span style="color:#a3be8c;">:style </span><span>=> </span><span style="color:#a3be8c;">:scss</span><span>,
</span><span> </span><span style="color:#a3be8c;">:layout </span><span>=> </span><span style="color:#a3be8c;">:packed</span><span>,
</span><span> </span><span style="color:#a3be8c;">:library </span><span>=> </span><span style="color:#a3be8c;">:chunkypng</span><span>,
</span><span> </span><span style="color:#a3be8c;">:selector </span><span>=> '</span><span style="color:#a3be8c;">.myicon-</span><span>',
</span><span> </span><span style="color:#a3be8c;">:output_style </span><span>=> '</span><span style="color:#a3be8c;">app/assets/stylesheets/_mysprites.scss</span><span>',
</span><span> </span><span style="color:#a3be8c;">:nocomments </span><span>=> </span><span style="color:#d08770;">true
</span><span>) </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">images</span><span>|
</span><span> images.map </span><span style="color:#b48ead;">do </span><span>|</span><span style="color:#bf616a;">name</span><span>, </span><span style="color:#bf616a;">data</span><span>| </span><span style="color:#65737e;"># for each image, we add a CSS sprite
</span><span> rules << "</span><span style="color:#a3be8c;">.myicon-</span><span>#{</span><span style="color:#96b5b4;">name</span><span>}</span><span style="color:#a3be8c;"> { background-position: -</span><span>#{data[</span><span style="color:#a3be8c;">:x</span><span>]}</span><span style="color:#a3be8c;">px -</span><span>#{data[</span><span style="color:#a3be8c;">:y</span><span>]}</span><span style="color:#a3be8c;">px; }</span><span>"
</span><span> </span><span style="color:#b48ead;">end
</span><span> rules.join("</span><span style="color:#96b5b4;">\n</span><span>")
</span><span style="color:#b48ead;">end
</span><span style="color:#65737e;"># ...
</span></code></pre>
<p>Get the final result at that <a href="https://gist.github.com/toch/5508052">Gist</a>.</p>
<h3 id="the-usage">The usage<a class="zola-anchor" href="#the-usage" aria-label="Anchor link for: the-usage">๐</a></h3>
<p>As everything is set up, I can use my Rake task as</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>rake </span><span style="color:#a3be8c;">assets:</span><span>environment
</span></code></pre>
<p>It generates:</p>
<ul>
<li>a PNG file into<code>app/assets/images/icons</code> for each icon SVG file,</li>
<li>a PNG file<code>app/assets/images/icons.png</code> containing all the icons packed into one file,</li>
<li>a stylesheet<code>app/assets/stylesheet/_mysprites.scss</code></li>
</ul>
<p>We can now enjoy it by importing it into the application stylesheet:</p>
<pre data-lang="scss" style="background-color:#2b303b;color:#c0c5ce;" class="language-scss "><code class="language-scss" data-lang="scss"><span style="color:#b48ead;">@import </span><span>'</span><span style="color:#a3be8c;">mysprites</span><span>';
</span></code></pre>
<p>You have no more reason to not go create yours! If you do, let me know (and if we can see them on a page, even better!).</p>
Fixing the Marriage Between Flow & Code Review2013-03-25T00:00:00+00:002013-03-25T00:00:00+00:00https://ibakesoftware.com/blog/fixing-the-marriage-between-flow-code-review/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<h2 id="flow-from-my-first-taste-to-complete-addiction">Flow - From my First Taste to Complete Addiction<a class="zola-anchor" href="#flow-from-my-first-taste-to-complete-addiction" aria-label="Anchor link for: flow-from-my-first-taste-to-complete-addiction">๐</a></h2>
<p>When I was still in school, I quickly discovered <strong>the impact of my attention on my efficiency</strong> - not only in terms of time - in terms of quality also - double strike! The equation was simple: more focus equals less time spent working - equals more leisure time. This was enough to push me to improve it.</p>
<p>Through the years I found a pattern that worked very well for me: work for 45 minutes, then take a break for 15 minutes. This might remind you of the so-called "<a href="http://en.wikipedia.org/wiki/Pomodoro_Technique">Pomodoro technique</a>". I made the same link recently when I discovered it.</p>
<p>Going forward, I have improved my technique and my capabilities, finding new patterns for different kinds of work. The 45/15 method was definitively the best for study. For writing or coding, 90/30 was perfect.</p>
<p><img src="http://farm4.static.flickr.com/3061/2623633694_f99faa1466_m.jpg" alt="Flow" /></p>
<p>Finally, I experienced <strong><a href="https://en.wikipedia.org/wiki/Flow_%28psychology%29">the concept of flow</a></strong>, that wonderful state that can keep you focused during several hours on your work - without being distracted by anything else. Even primary needs such as food, water, or sleep become irrelevant . It isn't necessary a good thing, but it's a wonderful feeling, and it was usually a time when I progressed a lot.</p>
<p>After having tasted the benefits of being fully focused, it's hard to study or work in a noisy environment, where you can get distracted - or interrupted - at any moment when you're trying to get into the flow. It's very painful.</p>
<p>My professional experience reinforced that habit. I coded a lot alone. Even when I was with other persons in the same office, they had the same modus operandi. We had silence periods during which we worked very concentrated, and very noisy periods during which we discussed, joked, and so on.</p>
<p>Now, when I need to work in a noisy environment, or when I'm often interrupted, I can feel the difference. I'm less productive - less creative - less focused. At some point, I don't even want to code anymore, frustrated as I am by my underperformance.</p>
<h2 id="the-cost-of-interruption">The Cost of Interruption<a class="zola-anchor" href="#the-cost-of-interruption" aria-label="Anchor link for: the-cost-of-interruption">๐</a></h2>
<p>As I already mentioned, that state is called the <a href="https://en.wikipedia.org/wiki/Flow_%28psychology%29">flow</a>:</p>
<blockquote>
<p>a deep focus on nothing but the activity โ not even oneself or one's emotions.</p>
</blockquote>
<p>I'm far the first to experience it nor <a href="https://news.ycombinator.com/item?id=3553853">the first to discuss the difficulty reaching it</a>. It's well discussed in the community of developers, a <a href="https://web.archive.org/web/20131104011927/http://michaelochurch.wordpress.com/2012/10/30/what-programmers-want">lot of</a> <a href="https://web.archive.org/web/20170201170438/http://stackoverflow.com/questions/886602/programmers-productive-work-time">thoughts</a> <a href="https://web.archive.org/web/20130322061625/http://programmers.stackexchange.com/questions/94800/best-tactics-for-avoiding-colleague-interruptions">and</a> <a href="https://web.archive.org/web/20170404131430/http://productivity.stackexchange.com/questions/2986/how-to-handle-interruptions-in-developer-work-without-losing-concentration">opinions</a> about the cost of distraction, noise, and interruption. Swizec Teller <a href="https://leanpub.com/nightowls">argues that's why a lot of developers work at night</a>. Even a <a href="http://programmers.stackexchange.com/questions/53453/interrupting-work-productivity-the-name">long compilation time</a> is considered as an annoying interruption.</p>
<p>Paul Graham states <a href="http://www.paulgraham.com/makersschedule.html">that maker and manager don't have the same schedule, because they do not the same job</a>. Jason Fried shared it as a <a href="http://37signals.com/svn/archives2/getting_in_toomuch_touch_interruption_is_not_collaboration.php">gut feeling</a>. It takes time to get in the zone: 15 minutes to one hour. Once you're in that productive zone, all your attention on what you're doing, you don't want to be interrupted. In Getting real, he <a href="https://basecamp.com/gettingreal/07.2-alone-time">reminds us of the importance to lay out โalone timeโ to be creative and productive - because it takes time to get in the zone - to be focused on your work. Interruptions are natural enemies</a>.</p>
<p>Joel Spolsky goes <a href="http://www.joelonsoftware.com/articles/fog0000000043.html">farther</a> and <a href="http://www.joelonsoftware.com/articles/fog0000000068.html">makes the math of the cost</a>. According to Joel - <strong>answering right now will save the blocked developer 30 seconds at the cost of 15 minutes for the answerer</strong>. Of course, that decision depends on the blocking question, and on the real costs of the interruption for a person.</p>
<p>These are not just individual - anecdotic - opinions by famous professionals, or within the community. Scientific researchers have observed it and have tried to <a href="http://www.ics.uci.edu/%7Egmark/CHI2005.pdf">measure that cost</a>. Speech and office noise <a href="http://onlinelibrary.wiley.com/doi/10.1111/j.2044-8295.1998.tb02699.x/abstract">cause a drop of 66% in knowledge workers' productivity</a>. It requires <a href="http://www.amazon.com/dp/0932633439/">more than 15 minutes before get into the flow</a> after or not an <a href="http://www.cc.gatech.edu/%7Evector/papers/sqj.pdf">interruption</a> (broken link), a very critical period during which the worker is very sensitive to noise and interruption.</p>
<p>It seems undeniable that <a href="http://blog.ninlabs.com/2013/01/programmer-interrupted/">interrupting a developer costs him - and his organisation - more than just the interruption time</a>. When someone is stuck, he doesn't necessary realize that cost as he's focusing on his own problem. Some issues or problems are probably worth the interruption cost, but most probably don't as an answer could be found in less than 15 minutes without distracting someone else (using Google, StackOverflow, internal wiki, etc.).</p>
<p>So, interruption is not necessarily the best strategy. As it is a complex question, there are several solutions, for instance: <a href="http://www.infoq.com/news/2008/07/interruption-driven-development">Scrum and its daily standup meeting</a>, <a href="https://web.archive.org/web/20140330021006/http://alistair.cockburn.us/Sacrifice+one+person+strategy">one person sacrifice</a>, <a href="http://craigkerstiens.com/2011/11/07/how-heroku-works-maker-day/">weekly maker's day</a>, <a href="https://basecamp.com/gettingreal/07.2-alone-time">schedule alone time</a>, <a href="http://blog.bufferapp.com/why-we-have-our-best-ideas-in-the-shower-the-science-of-creativity">deep thinking in the shower</a>, or <a href="https://web.archive.org/web/20160722074831/http://productivity.stackexchange.com/questions/201/how-can-i-improve-my-workplace-to-have-less-interruptions">physical setup and consensus</a> (โdon't disrupt me when I'm wearing headphonesโ).</p>
<p>Beyond the productivity loss, there are some activities that needs the action of a peer. There is one important in software development: code review.</p>
<h2 id="flow-vs-code-review">Flow vs Code Review<a class="zola-anchor" href="#flow-vs-code-review" aria-label="Anchor link for: flow-vs-code-review">๐</a></h2>
<p>It's especially a trickier question - as code review affects the flow of two persons: the reviewee and the reviewer.</p>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/6/66/Pair_Programming.jpg/300px-Pair_Programming.jpg" alt="English: Two programmers" /></p>
<p>On one hand, the <strong>reviewee's flow is interrupted at the time he requests a review</strong>. He's forced to wait until the reviewer will review and send it back to him. During the wait, he could do something else, start to implement a new feature or to fix a bug. But the longer the wait is, the more complicated it will be for the reviewee to <a href="http://blog.ninlabs.com/2013/01/programmer-interrupted/">get back into the code</a>.</p>
<p>On the other hand, the <strong>reviewer has to decide when he'll review the code</strong>. Does he interrupt his work asap in order to not answer one week later? When is it the good time? Even if the reviewer finds a good moment, such as when he is finishing to implement a method, the time he will spend to review is a time he will pay to dive back in his own code. It's his flow against the reviewee's one.</p>
<p>The <a href="https://web.archive.org/web/20131229173434/http://www.codinghorror.com/blog/2006/01/code-reviews-just-do-it.html">benefits</a> <a href="https://web.archive.org/web/20140413182556/http://www.altdevblogaday.com/2011/09/13/the-benefits-of-code-review/">of</a> <a href="http://en.wikipedia.org/wiki/Code_review">code review</a> are known, but it costs. <a href="http://softwaremill.com/were-doing-this-a-tool-for-code-reviews-is-needed">It is a daily - and important - task that takes in average more than 30 minutes</a>. It's an important <a href="https://web.archive.org/web/20140109084854/http://www.wired.com/magazine/2011/06/ff_feedbackloop/all/1">feedback loop</a> for the reviewee's learning. The reviewer knows that and takes it into account. But in the worst case scenario, he will start 1 hour after having received the code, spend 15 minutes to read the code, answers trivial comments including <a href="https://www.sonarsource.com/blog/effective-code-review-with-sonar/">team convention or flaws that could be detected by a linter</a>, and spend another 15 minutes to get back to his previous level of focus. The reviewee will wait 2 hours and 15 minutes to get the review, a few minutes to read it, and 15 minutes to get back to his own previous level of focus. What a frustration for both!</p>
<p>It could be even worse if the given review just consists in a simple green light because the reviewer doesn't have the time to do more and has just evaluated the implemented feature is compliant.</p>
<p>In other scenarios, the code review would initiate a discussion leading a better design, a learning, and a great experience of sharing knowledge. That kind of review takes time, but it will be worth it for both! It totally depends on the code to review and the quality of the review against the flow of each other. Finding a good balance is not an easy question!</p>
<h2 id="making-flow-and-code-review-a-happy-couple">Making Flow and Code Review a Happy Couple<a class="zola-anchor" href="#making-flow-and-code-review-a-happy-couple" aria-label="Anchor link for: making-flow-and-code-review-a-happy-couple">๐</a></h2>
<p><strong>There are solutions</strong> such as <a href="http://en.wikipedia.org/wiki/Automated_code_review">automated code review tools</a>, including <a href="http://en.wikipedia.org/wiki/Static_code_analysis">static code analysis tools</a>. They should be used for complexity, style convention, and other simple checks, before any review. But <strong>it cannot replace a human</strong> for different reasons: automated software are aimed at underlining code issues, not toward improving developer capabilities, and are unable to prioritize the tasks (this one is critical for the business), or unable to deal with complex context. However, by using tools, the review can at least be focused on true added value whether in terms of code and design, or knowledge transfer.</p>
<p>At 8th color, each of us deals differently with those questions - due to our respective professional experiences. I'm the more addicted to the flow, where Martin and Stรฉphan are very used to deal with interruptions.</p>
<p><strong>We do not just keep to our respective habits</strong>. We discuss them, we confront our opinions - and we try to come up with solutions. For instance, we've quickly adopted some static code analysis tools in Ruby for the reasons explained previously or a chat software to ask non urgent questions without interrupting each other. More specifically, we're building a structural solution that finds the balance between kick-ass code review and flow - more on that later.</p>
<p><em>We're very interested in others' experience and solutions. What's yours? Do you think automated tools are a good intermediary solution? Do they help you not only to improve your code but also to learn?</em></p>
Do not fall in the learning curve!2013-03-01T00:00:00+00:002013-03-01T00:00:00+00:00https://ibakesoftware.com/blog/do-not-fall-in-the-learning-curve/
<p><strong>This is an archive of blog post I wrote during my third venture (PullReview).</strong></p>
<h2 id="tl-dr">TL;DR;<a class="zola-anchor" href="#tl-dr" aria-label="Anchor link for: tl-dr">๐</a></h2>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/b/b9/Carlos_Sastre_at_Alpe_d%27Huez.jpg/300px-Carlos_Sastre_at_Alpe_d%27Huez.jpg" alt="English: Carlos Sastre climbing up Alpe d'Huez" /></p>
<p>As a software developer, one of the main challenge I've met is to find good resources and feedback to keep my learning curve at a certain level: not steep enough to be frustrating, not low enough to be stalling. There are plenty of ways to do it, especially when it's the first time you learn a new programming language. After a certain level, it becomes far more complex and slow. I had that frustration and tried to find good solutions. I'll share that experience.</p>
<h2 id="my-journey-as-a-c-and-c-developer">My journey as a C and C++ developer<a class="zola-anchor" href="#my-journey-as-a-c-and-c-developer" aria-label="Anchor link for: my-journey-as-a-c-and-c-developer">๐</a></h2>
<p>At the beginning, I started with C. I learned it before the university mainly by reading tutorials on the web. At the university, I started C++. The courses, the projects and the practical works were good sources of learning. They mainly gave me a list of topics to dig and experiment, and the practical works were the best place to have a quick feedback depending on the teaching assistant.</p>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/Programming_language_textbooks.jpg/300px-Programming_language_textbooks.jpg" alt="English: A selection of programming language books" /></p>
<p>During my engineer studies, I read more rigorous articles on the web and the big classics including C Programming Language by Ritchie and Kernighan or C++ Programming Language by Stroustrup.</p>
<p>After my graduation, I reached a learning plateau. I missed someone with a better knowledge in C++ to give me insight and path of progress. Hopefully, I met him at the beginning of my PhD. He advised me books, content, people to read or listen (e.g. Herb Sutter, Scott Meyers), or tools but moreover I had someone to discuss the challenges and potential solutions. Even today, it's still someone I come back when I'm struggling with complex problems in C++ or design. During that period I especially learned the benefits of tooling like linter, static analysis, profiler, not only in terms of code quality but also in terms of learning. They underlines problems I wasn't necessary aware of and give me a point to learn and improve.</p>
<p>The other way I progressed during my PhD was by teaching. When teaching something, you need to clarify and refine your understanding in order to communicate it. Moreover, you need to know the bounds and the exact internal working. It forced me to dig into some topics like the STL.</p>
<p>After my PhD, I worked as a freelancer. In most of my contracts, I was the only developer. Of course, as before, I've still read on the web and googled, but when I was facing a big issue for too long, my best solution was to discuss it with one or another friend C++ developers.</p>
<h2 id="as-a-ruby-developer">As a Ruby developer<a class="zola-anchor" href="#as-a-ruby-developer" aria-label="Anchor link for: as-a-ruby-developer">๐</a></h2>
<p>I've learned and practiced other programming languages such as Java or Python (or BASIC a long long time ago). Roughly one year ago, I've started to develop, notably, in Ruby for 8th color. I've met another kind of learning challenge.</p>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/f/f1/Ruby_logo.png/75px-Ruby_logo.png" alt="Official Ruby logo" /></p>
<p>As a polyglot developer with some substantial experiences and knowledge, I learned the basics quickly. With my level, I'd expected to learn enough knowledge to write not so crappy code. But even if there is a common pattern between programming languages and the algorithmics fundamentals are still the same, the idioms are different, the ecosystem is different, the tools are different, the learning sources are different. I still have a lot to learn and experiment to reach a satisfying level in Ruby.</p>
<p>Even if it exists great active learning resources such as code school or codecademy, once I've finished them, I was far from what I'd expect as minimum level. It took me time to find the good blogs and the good tools. It was interesting but not essential for my progression, I'd have prefered to spend that time to learn about Ruby itself. Hopefully, Martin learned Ruby in a same time and I had someone to discuss and share with.</p>
<h2 id="the-way-to-learn">The way to learn<a class="zola-anchor" href="#the-way-to-learn" aria-label="Anchor link for: the-way-to-learn">๐</a></h2>
<p>From my experiences, I'd summarize the different ways to learn as following:</p>
<ul>
<li>books, blog posts, tutorials, podcasts, conference talks</li>
<li>forum, stack overflow questions, mailing lists</li>
<li>interactive applications (code school, codecademy, robot war)</li>
<li>tools (linter, checker, static analysis, profiler)</li>
<li>close developers (colleagues, friends, coach)</li>
<li>developers (forum, stack overflow, mailing lists)</li>
</ul>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/3/3c/Learning_curve.svg/300px-Learning_curve.svg.png" alt="English: Level/Time of competence when learning" /></p>
<p>All of these participate differently to your learning. If well chosen and used, they have all their utility for any expertise level. For instance, tools and close developers are very good to support active learning, i.e. learning by doing. Interactive applications are certainly the best for a beginner. Books can present very introductory materials as the more advanced, but they're only passive knowledge.</p>
<p>I can probably spend another blog post to describe their benefits and drawbacks, and categorize them according your level. But I'd prefer to underline something else first: having the right feedback at the right moment.</p>
<h2 id="the-learning-challenge-for-a-developer">The learning challenge for a developer<a class="zola-anchor" href="#the-learning-challenge-for-a-developer" aria-label="Anchor link for: the-learning-challenge-for-a-developer">๐</a></h2>
<p>I used to be the typical profile of lone developer: no pair programming, no team, no senior developer. I need to rely on myself and on some close and trustable peers. In learning, it's not an uncommon situation. You cannot rely on someone else to support you and give you good feedback to frame your learning. Sooner or later, you'll inevitably wander in the dark. It could be because the content you've found it's not good enough, or simply because you don't know where to go first. I've experienced it as an experienced C++ developer and as a beginner Ruby developer. It's a big frustration.</p>
<p>It's a kind of situation you can also meet even when you're working in a team, especially during stressful phase with close deadlines. You don't have always someone available to answer you when the question pops out. If it's a stupid one, you probably don't want to interrupt them as the flow is important.</p>
<p>I've discussed that learning challenge with several developers. It's usually accepted that it takes time and having someone helping you is a must. For me, the time is certainly a pain, but my biggest frustration is the loose and inadequate feedback for my level. My best learning experiences are when I'm facing a certain problem, I find the good blog post discussing the problem, and I can finally try it and implement a solution.</p>
<p><em>What are your experiences? Your biggest pain? What are your best learning mean? How do you keep improving year after year ?</em></p>
2012 Recap2013-02-01T00:00:00+00:002013-02-01T00:00:00+00:00https://ibakesoftware.com/blog/2012-recap/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<p>As a new year begins, Martin and I have looked back at 2012 to share our lessons, our disappointments, our good points. That exercise helped us to underline what we didn't like, what we did, and what we learned. I can say 2012 was a great opportunity for us to explore, taste, and test. We were a little bit like children in a candy shop: we wanted to taste everything. It's time to grow, and our biggest decision is simply to come back to our roots, but we'll tell more about that a next time.</p>
<p>During that recap, one thing amazed us is the amount of "things" we did or generated. Let's talk the facts:</p>
<ul>
<li>Emails
<ul>
<li>sent: 2512</li>
<li>received: 13497</li>
</ul>
</li>
<li>Google Talks between Martin and I: 437</li>
<li>Documents:
<ul>
<li>1125 files</li>
<li>1089MB</li>
</ul>
</li>
<li>Contacts: 607</li>
<li>Business Cards: 271</li>
<li>Calendar:
<ul>
<li>48 lunches</li>
<li>6 workshops</li>
<li>141 meetings, skype calls, events, โฆ</li>
</ul>
</li>
<li>Code:
<ul>
<li>5 repositories</li>
<li>713 commits</li>
<li>14579 final ruby lines</li>
</ul>
</li>
<li>Events:
<ul>
<li>8 pitches before large audience (FI graduation, Microsoft Techdays, MIC Boostcamp final, BetaInvest, Innopitch, ICT Spring, Dublin WebSummit, Brussels California mission)</li>
<li>6 Betagroups (as attendees)</li>
<li>2 Brussels MIC Bootcamp final (1 as participant, 1 as jury member)</li>
<li>4 booths at large events (Innopitch, ICT Spring, WebSummit, LeWeb)</li>
<li>15 networking events</li>
<li>1 8th color birthday dinner with 30 attendants</li>
</ul>
</li>
<li>Pilots: 3
<ul>
<li>Number of projects: ~50</li>
<li>Number of developers: ~100</li>
</ul>
</li>
<li>15 web applications</li>
<li>blog
<ul>
<li>55 posts</li>
<li>~35k visits</li>
</ul>
</li>
<li>11 business update newsletter to 25 subscribers</li>
<li>1 photo shoot with us and friends as actors</li>
</ul>
<p>Those are just some numbers to give you an idea. They are certainly others. Some are preferable to not be counted like the working hours and sleepless nights.</p>
<p>I wish you and your family all the best for 2013.</p>
Novice or Master, what should it mean for a developer?2012-11-27T00:00:00+00:002012-11-27T00:00:00+00:00https://ibakesoftware.com/blog/novice-or-master-what-should-it-mean-for-a-developer/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<h2 id="learning-model">Learning Model?<a class="zola-anchor" href="#learning-model" aria-label="Anchor link for: learning-model">๐</a></h2>
<p>In the field of education and learning, some models have been elaborated. One well known is the <a href="http://en.wikipedia.org/wiki/Dreyfus_model_of_skill_acquisition">Dreyfus model of skill acquisition</a>. It describes how students acquire skills through formal instruction and practicing. As we address the question of development skills with Sybil, it's for us an interesting point of view and inspiration</p>
<p>The original model consists in five distinct stages: novice, advanced beginner, competent, proficient, and expert. When acquiring and developing a skill, the person goes through those 5 stages by learning some principles on which he takes decision. When at the beginning, those principles mainly consist in rigid and explicit rules, they evolve to tacit knowledge, i.e. principles that are simply internalized.</p>
<h2 id="the-5-stages">The 5 stages<a class="zola-anchor" href="#the-5-stages" aria-label="Anchor link for: the-5-stages">๐</a></h2>
<p>A <strong>novice</strong> will rigidly apply taught rules or plans without judgment.</p>
<p>An <strong>advanced beginner</strong> has developed a limited perception of the situation. He still addresses the different aspects of a task or a problem independently without any priority.</p>
<p>A <strong>competent</strong> accumulates information and can deal with multiple aspects in the same time. That allows him to understand the consequences of his actions on the goals. At that moment, he can build and plan a procedure to tackle a problem or reach a goal.</p>
<p>A <strong>proficient</strong> has a global overview of the situation, understands the importance of different aspects to deal with, and prioritizes them. He perceives how he needs to deviate from the normal pattern to apply, and he follows not only local rules or guidelines, but also maxims with an application variating with the addressed situation</p>
<p>An <strong>expert</strong> has developed a tacit and deep knowledge thanks to his huge practical experience. He doesn't need anymore to directly and explicitly rely on rules, guidelines, or maxims. When he faces a problem, he knows intuitively what is possible, and how to approach the situation. He also feels when it is a new kind of problem that he never meets before. He then follows an analytical approach.</p>
<p>Let's try to apply those definitions to the acquisition of a given first programming language <strong>X</strong> without considering its ecosystem of libraries for the sake of simplicity.</p>
<h2 id="the-novice">The Novice<a class="zola-anchor" href="#the-novice" aria-label="Anchor link for: the-novice">๐</a></h2>
<p><img src="http://upload.wikimedia.org/wikipedia/en/thumb/d/d2/AtariBasicError.png/300px-AtariBasicError.png" alt="What happens when a line containing a syntax e..." /></p>
<p>A novice had learned to recognize the most important common keywords and syntax rules allowing him to tell if they belong to <strong>X</strong> or not. He can also copy some very small snippet of code in <strong>X</strong> that seems correct to him syntactically but not really understand its meaning. He can also compile and run the program (or just interpret it), and tell if the output is an error or not, but not interpret it.</p>
<h2 id="the-advanced-beginner">The Advanced Beginner<a class="zola-anchor" href="#the-advanced-beginner" aria-label="Anchor link for: the-advanced-beginner">๐</a></h2>
<p>An advanced beginner recognizes expressions and other language structures in <strong>X</strong> such as arithmetical expression or loop, and he understands their meaning, i.e. he can expect they produce a certain output when used appropriately. By doing so, he can modify them in order to change their output as he thinks it would. He also understands simple directives that the compiler or the interpreter gives when an error occurs such as a syntax error or the line number where the error has occurred.</p>
<h2 id="the-competent">The Competent<a class="zola-anchor" href="#the-competent" aria-label="Anchor link for: the-competent">๐</a></h2>
<p>A competent is finally capable to write simple programs achieving a whole goal. He recognizes if the output is the expected one, and he can corrects it if not. He starts also to apply some patterns such as the common way to iterate over a collection.</p>
<h2 id="the-proficient">The Proficient<a class="zola-anchor" href="#the-proficient" aria-label="Anchor link for: the-proficient">๐</a></h2>
<p>A proficient can plan how he will write a complex program by splitting it in several parts or subprograms. He follows general maxims such as <a href="http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29">SOLID</a> if <strong>X</strong> allows to do object oriented programming. When he has to meet some requirements such as using a collection offering rapid read access, he knows which solution to apply.</p>
<h2 id="the-expert">The Expert<a class="zola-anchor" href="#the-expert" aria-label="Anchor link for: the-expert">๐</a></h2>
<p>After programming in <strong>X</strong> on a daily basis, an expert writes code to obtain an expected output without thinking explicitly to syntax rules or expression grammar. When the program stops on an error, he knows what he should correct and where. When he faces something new, he returns to an explicit approach.</p>
<h2 id="a-model-of-skill-progression-in-software-development">A model of skill progression in software development<a class="zola-anchor" href="#a-model-of-skill-progression-in-software-development" aria-label="Anchor link for: a-model-of-skill-progression-in-software-development">๐</a></h2>
<p>It's an interesting model that gives a way to categorize the different skill levels. The difficulty is to apply their definition to a certain domain. It is possible to translate them, but the development of metrics is not straightforward and certainly debatable.</p>
<p>I'm not the first one (for instance check the <a href="http://www.indiangeek.net/wp-content/uploads/Programmer%20competency%20matrix.htm">programmer competency matrix</a>), and even some web sites try to capture those levels in some way (<a href="http://stackoverflow.com">stackoverflow.com</a>, <a href="http://coderwall.com">coderwall.com</a>). But as a developer, I'd like to have a measure of my skills that helps me to understand how I progress, what I need to improve, where I need to go, as a teacher or coach can do.</p>
<p><em>And you what's your opinion?</em></p>
<p>Some related reading:</p>
<ul>
<li><a href="http://pragprog.com/book/ahptl/pragmatic-thinking-and-learning">Pragmatic Thinking and Learning: Refactor Your Wetware</a> by Andy Hunt (pragprog.com)</li>
<li><a href="http://www.skorks.com/2009/08/building-software-development-expertise-using-the-dreyfus-model/">Building Software Development Expertise โ Using The Dreyfus Model</a> (skorks.com)</li>
<li><a href="http://www.markhneedham.com/blog/2009/08/10/dreyfus-model-more-thoughts/">Dreyfus Model: More thoughts</a> (markhneedham.com)</li>
<li><a href="http://lizkeogh.com/2009/08/13/building-experts-using-the-dreyfus-model/">Building experts using the Dreyfus Model</a> (lizkeogh.com)</li>
<li><a href="https://web.archive.org/web/20200921042445/https://blog.codinghorror.com/level-5-means-never-having-to-say-youre-sorry/">Level 5 means never having to say you're sorry</a> (codinghorror.com)</li>
</ul>
The Devengers2012-11-16T00:00:00+00:002012-11-16T00:00:00+00:00https://ibakesoftware.com/blog/the-devengers/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<blockquote>
<p>"And there came a day, a day unlike any otherโฆ when Earthโs mightiest heroes found themselves united against a common threatโฆ <strong>to fight the foes no single superhero could withstand</strong>โฆ on that day, The Avengers were born."</p>
<p><img src="http://upload.wikimedia.org/wikipedia/en/3/33/Avengers_2010.jpg" alt="The "Heroic Age" roster of the Avengers" /></p>
</blockquote>
<p>As you probably know, weโre developing with <a href="http://asksybil.com">Sybil</a> a way to capture what makes a developer, at least from the technical point of view. In that context, Martin and I are addressing several related questions such as which skills does the developer need to master.</p>
<p>This is not an easy question as the job of developer is a dense and variate job. Moreover, there are many developer jobs: the specs, the quality, the management of the project and the team, the design, the support, the interaction with the user, the collaboration with other developers, and so on. It's very reductive to think there is only one job. <strong>As there are multiple jobs, there are multiple types of developers.</strong></p>
<p>At a certain point, certain moment, developing a software is a daunting task. It couldn't be supported by only one lone developer because he's alone, because he doesn't have all the skills. It's necessary to form a team constituted by developers with complementary classes. <strong>Alone they can't, together they'll do.</strong></p>
<h2 id="natalia-the-jack-of-all-trades"><a href="http://en.wikipedia.org/wiki/Black_Widow_%28Natalia_Romanova%29">Natalia</a>, The Jack-Of-All-Trades<a class="zola-anchor" href="#natalia-the-jack-of-all-trades" aria-label="Anchor link for: natalia-the-jack-of-all-trades">๐</a></h2>
<p><img src="http://i.annihil.us/u/prod/marvel//universe3zx/images/c/c2/BlackWidow.jpeg" alt="Natalia Romanova" /></p>
<p>Itโs probably one of the most common developer class. She implements features, fixes bugs, reports them, coaches coworkers, documents her <a href="http://stackoverflow.com/questions/2773761/armchair-linguists-code-vs-codes-or-why-i-write-code-and-my-manager-ask">code</a>, refactor othersโ code, helps for devops, etc. <strong>She may be the best at nothing, but can do everything</strong>. Her asset is her average skills in anything.</p>
<blockquote>
<p>"Don't think I'm helpless, just because I'm soft and cuddly!"</p>
</blockquote>
<p>Due to her wide set of skills, sheโs flexible, and she can replace and interact with any other team member. She has good learning and social aptitude. For that reason, sheโs a necessary backbone of a development team. Sheโs probably not the one who will fix a very complex problem that needs very sharp skills, but sheโs certainly the one who will help that guy. She can become a very good team leader.</p>
<h2 id="logan-the-expert"><a href="http://en.wikipedia.org/wiki/Wolverine_%28comics%29">Logan</a>, The Expert<a class="zola-anchor" href="#logan-the-expert" aria-label="Anchor link for: logan-the-expert">๐</a></h2>
<p><img src="http://i.annihil.us/u/prod/marvel//universe3zx/images/d/df/Jstephens--Wolverine_James_detail.jpg" alt="Logan" /></p>
<p>He is the master in a certain technical language such as C++ meta-programming, advanced algorithmic, concurrent programming, distributed programming and network, etc. in that domain, heโs THE reference in his team, very productive and sharp, he reviews the code of others, his opinion is strong and weighs, and <strong>nobody can do better than him in that domain</strong>.</p>
<blockquote>
<p>"I'm the best there is at what I do, but what I do best isn't very nice"</p>
</blockquote>
<p>Heโs a member of the team because a few technical points of the product are critical. Due to his level of skill, heโs usually the only one to work on that critical parts. But as important and critical is his presence, heโs a single point of failure. For the team, itโs very important that he chooses and trains a padawan to assist him.</p>
<h2 id="edwin-the-maintainer"><a href="http://en.wikipedia.org/wiki/Edwin_Jarvis">Edwin</a>, The Maintainer<a class="zola-anchor" href="#edwin-the-maintainer" aria-label="Anchor link for: edwin-the-maintainer">๐</a></h2>
<p><img src="http://i.annihil.us/u/prod/marvel//universe3zx/images/3/34/Jarvis.jpg" alt="Edwin Jarvis" /></p>
<p><strong>He's there since long</strong>. He has maintained the project for long years, with some random guy like you showing up with crazy new ideas each three years. He's still there, the project is still running. He can remind old decisions made before you arrived and helps everybody to understand the reasons behind that design choice or that technology choice.</p>
<blockquote>
<p>"As soon as my rehabilitation is finished, I should like to report back to work. You should know better than most, sir. Things really can't go on without me, now can they?"</p>
</blockquote>
<p>He may be advert to new ideas, but not from an ideological point of view: he just wants to know what are the real gains and how complicated it will be to maintain when you'll be left. He'll bore you, but with the voice of reason.</p>
<h2 id="bruce-the-tester"><a href="http://en.wikipedia.org/wiki/Hulk_%28comics%29">Bruce</a>, the Tester<a class="zola-anchor" href="#bruce-the-tester" aria-label="Anchor link for: bruce-the-tester">๐</a></h2>
<p><img src="http://i.annihil.us/u/prod/marvel//universe3zx/images/f/fe/Hulk13.jpg" alt="Bruce Banner" /></p>
<p>He makes any perfectly working application crashes, can reproduces it, and documents it. He do think the same way as most people, <strong>he has a weird approach to torture the software</strong>. He has a very good understanding of how the things that do not work help him to use the software in unexpected cases. He has also good skills to build benchmark and tests in order to automate those use cases and avoid future regression.</p>
<blockquote>
<p>"Puny" software</p>
</blockquote>
<p>Heโs one of the most important user of the issue tracking system. He reports, he answers, he supports the developers and challenge them. Quality is a useless word without him.</p>
<h2 id="jonas-the-documentalist"><a href="http://en.wikipedia.org/wiki/Vision_%28Marvel_Comics%29">Jonas</a>, The Documentalist<a class="zola-anchor" href="#jonas-the-documentalist" aria-label="Anchor link for: jonas-the-documentalist">๐</a></h2>
<p><img src="http://upload.wikimedia.org/wikipedia/en/0/0d/Youngvisionx.png" alt="Jonas" /></p>
<p>Maybe he knows it is useful, maybe he likes to write things down, maybe he's just sort of maniac, but he gets every aspect of his work nicely written down. From code documentation to wiki pages, from detailed design to user manual, without forgetting issue conversations.</p>
<blockquote>
<p>"Unlike most humans, I prefer not to speak unless I have something to say!"</p>
</blockquote>
<p>He takes time to make things, but you'll appreciate in one day, when a search will show of a very old manuscript or a code comment revealing the reason of that wretched design you are fighting with. <strong>Without him, the project will be full of cruft</strong>.</p>
<h2 id="tony-the-architect"><a href="http://en.wikipedia.org/wiki/Iron_Man">Tony</a>, The Architect<a class="zola-anchor" href="#tony-the-architect" aria-label="Anchor link for: tony-the-architect">๐</a></h2>
<p><img src="http://i.annihil.us/u/prod/marvel//universe3zx/images/f/f5/IronMan_Head.jpg" alt="Tony Stark" /></p>
<p>He is the one who thinks globally. He sees the design needed to make a better product and <strong>he sees the wheels behind the clock</strong>. He has usually a good previous experience of software development that gives him a good taste of common issues. He has the vision of what the product could be. Sometimes, he sees too far and loses himself in an abstract world.</p>
<blockquote>
<p>"Yeah, I can fly."</p>
</blockquote>
<p>He watches the work of the team to detect synergies and possible needs of tools. He fights the technical debt. He extracts the knowledge of the work and produces the technical documentation. Heโs the evangelist.</p>
<h2 id="matt-the-user-voice"><a href="http://en.wikipedia.org/wiki/Daredevil_%28Marvel_Comics%29">Matt</a>, The User Voice<a class="zola-anchor" href="#matt-the-user-voice" aria-label="Anchor link for: matt-the-user-voice">๐</a></h2>
<p><img src="http://i.annihil.us/u/prod/marvel//universe3zx/images/7/7f/Daredevil.jpg" alt="Matt Murdock" /></p>
<p>Whether self appointed or not, <strong>he makes his own crusade to speak for those that cannot: the users</strong>. When confronted with a new feature or even worse, a refactor, he simply asks "What is the ROI there? How will this make the life of the users easier?". He's be on your back, but his message is basically the good one.</p>
<blockquote>
<p>"Just doing my duty"</p>
</blockquote>
<h2 id="steve-the-team-leader"><a href="http://en.wikipedia.org/wiki/Captain_America">Steve</a>, the Team Leader<a class="zola-anchor" href="#steve-the-team-leader" aria-label="Anchor link for: steve-the-team-leader">๐</a></h2>
<p><img src="http://i.annihil.us/u/prod/marvel//universe3zx/images/f/fc/Ultimate_cap_hed.jpg" alt="Steve Rogers" /></p>
<p>He supports the team and gives it direction. He supports collaboration and prioritizes work. He listens, follows, and decides. <strong>Heโs the captain: ready to sacrifices if he can save the team and the project</strong>.</p>
<p>"Captain America is not here to lead the country. Iโm here to serve it. If Iโm a captain, then Iโm a soldier."</p>
<p>He has very good human skills because his main job is to guarantee that the team works together. He wants that each team member progresses and the work is done. Heโs usually the one contact point with the team and, the most important point, he avoids that his team is interrupted/annoyed by others.</p>
<h2 id="the-team-power">The team power<a class="zola-anchor" href="#the-team-power" aria-label="Anchor link for: the-team-power">๐</a></h2>
<p>There are certainly other classes and most of us are multi-classed. Depending on the team, the context, our experience, and our taste, we are not of one caricature class.</p>
<p>Defining those classes is important. It underlines that the team needs those roles. If the team leader doesn't know the weakness and the strength of each team member, he cannot correctly decide. <strong>As with the Avengers, there is a day a threat cannot be addressed by one of the Earth's mightiest heroes, but together, the Avengers can</strong>.</p>
<p><em>And you, what's your team?</em></p>
<p><em>You can also <a href="http://news.ycombinator.com/item?id=4793293">discuss this post on Hacker News</a>.</em></p>
8 lessons from my first year as an entrepreneur2012-10-30T00:00:00+00:002012-10-30T00:00:00+00:00https://ibakesoftware.com/blog/8-lessons-from-my-first-year-as-an-entrepreneur/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<h2 id="in-a-few-months-you-can-learn-a-lot">In a few months, you can learn a lot.<a class="zola-anchor" href="#in-a-few-months-you-can-learn-a-lot" aria-label="Anchor link for: in-a-few-months-you-can-learn-a-lot">๐</a></h2>
<p>Last Thursday, I was invited to be a member of jury of the final of the <a href="https://web.archive.org/web/20121218201003/http://blog.mic-brussels.be:80/category/bootcamp/">startup boostcamp</a> organized by the <a href="https://web.archive.org/web/20221021103555/https://mic-brussels.be/en/">Brussels Microsoft Innovation Center</a>. About seven months ago, we pitched in the previous session in March 2012. It was very interesting to pass the other side and listen to young entrepreneurs presenting their ideas. With a mix of surprise and obviousness, I find myself able to judge. Indeed, it forced me to realize the path I've made. Even in a so short time, I've learned a lot only because we've experienced a lot.</p>
<p>One year ago, Martin and I started to follow the <a href="http://fi.co">Founder Institute</a> program and built our business. It's a good time to crystallize some lessons. Below, the ones that resonate the most from that whole year of experience.</p>
<h2 id="listen-apply-but-don-t-follow">Listen, apply, but don't follow.<a class="zola-anchor" href="#listen-apply-but-don-t-follow" aria-label="Anchor link for: listen-apply-but-don-t-follow">๐</a></h2>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/9/9a/Closeup_of_a_human_ear.jpg/160px-Closeup_of_a_human_ear.jpg" alt="Closeup of a human ear" /></p>
<p>As a inexperienced entrepreneur starting his first startup, it was <strong>obvious to listen people that are more experienced</strong>. Sometimes, the advices and feedback were not convincing. But I listened and I tried to apply them. Most of the times, by applying, I learned something new and I progressed.</p>
<p>Sometimes, by applying, Martin and I realized it wasn't good for us. We have opinions and 8th is our business. We are the ultimate judges, the only persons that can decide what is worth doing, what is not. But that doesn't mean we don't listen others. In fact, listening others and trying helps us to forge our own opinions and build our business.</p>
<h2 id="pitching-concisely-helps-you-to-build-a-better-business">Pitching concisely helps you to build a better business.<a class="zola-anchor" href="#pitching-concisely-helps-you-to-build-a-better-business" aria-label="Anchor link for: pitching-concisely-helps-you-to-build-a-better-business">๐</a></h2>
<p>At first, I sincerely didn't realize that pitching was also good for your business. As a pitch needs to be concise, we were forced to focus on the important and critical parts of the business: a problem, a customer target, and a solution with a differentiator. They are the core of the business model. <strong>Without clearly expressing them, it's impossible to build on top</strong>. It's impossible to explain to others: advisors, mentors, potential customers, providers, potential employees, investors, friends, and family. When you cannot explain your business, you cannot expect any useful feedback and advices. That also means that the chance are good that your customers will not understand it either. It's certainly not a good start if you want them to pay for something you cannot even explain.</p>
<h2 id="get-out-of-the-building-or-don-t-assume">Get out of the building or don't assume.<a class="zola-anchor" href="#get-out-of-the-building-or-don-t-assume" aria-label="Anchor link for: get-out-of-the-building-or-don-t-assume">๐</a></h2>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/b/b8/Interesting_office_building_-_geograph.org.uk_-_55882.jpg/75px-Interesting_office_building_-_geograph.org.uk_-_55882.jpg" alt="English: Interesting office building." /></p>
<p>That one is probably very obvious and common for people aware of the <strong>customer development approach</strong>. Knowing it is one thing, experiencing it is another. It's simply based on the fact that you cannot know what other persons think about you, your idea, and so on. We have learned so much by talking to others, by meeting potential customers, and by asking why when we've got a "no". It freaked us to ask when people answered "we're not interested". But we did politely, and they answer us nicely. Same to meet people, at worse they decline. It's exactly the same result you obtain by not asking.</p>
<h2 id="you-cannot-expect-who-you-can-meet">You cannot expect who you can meet.<a class="zola-anchor" href="#you-cannot-expect-who-you-can-meet" aria-label="Anchor link for: you-cannot-expect-who-you-can-meet">๐</a></h2>
<p>There are so many events to attend, that I can spend half my time in events if I want. We can't afford a such waste of time. On the other hand, the topics could be interesting because it's exactly the issue we're addressing at that time. But events are not only about topics, they are also about people to meet. Networking is probably one of the most difficult task to manage in terms of time spending. But from my experience, I select events not so much based on the interest I have in the topic but for the audience, the people attending (or presenting).</p>
<p>At the beginning, I did chat with people, but it didn't necessarily give me a direct outcome. Anyway, I met interesting persons, gave my feedback or advices when asked, and pitched as often as I could. Sometimes, I met a potential customer that suggested us to run a pilot. An acquaintance introduced me to a person that helped us on a specific topic such as finance. I received the contact of an expert that gave us very interesting feedback on our product.</p>
<p>In my honest opinion, you cannot expect the outcome. But as gardening, if you honestly and gently take care, people will recognize you and at some point you just have to harvest when it flourishes.</p>
<blockquote>
<p><strong>Eighty percent of success is showing up</strong>.</p>
<p>Woody Allen</p>
</blockquote>
<h2 id="lack-of-resources-is-a-good-thing">Lack of resources is a good thing.<a class="zola-anchor" href="#lack-of-resources-is-a-good-thing" aria-label="Anchor link for: lack-of-resources-is-a-good-thing">๐</a></h2>
<p><img src="http://farm5.static.flickr.com/4045/4644606033_c4c8bc47ff_s.jpg" alt="TIME FLIES" /></p>
<p>We're still bootstrapping by doing consultancy on the side. It takes time, but it delivers the money, i.e. the mean, to build Sybil. It also force us to focus. Our time being limited, we cannot do what we want, we need to choose and decide. This is really a good thing. A few days ago, one person told me it was unfair to be a spin-off because they're in protected situation with a lot of money. I answered that I think <strong>we are in unfair situation because we're forced to focus on the business</strong>. We don't have the resources to waste, and it's a very good thing. We need to decide and progress. That really helps us to keep the pace and step forward.</p>
<h2 id="software-development-is-not-all">Software development is not all.<a class="zola-anchor" href="#software-development-is-not-all" aria-label="Anchor link for: software-development-is-not-all">๐</a></h2>
<p>We're techies, and we thought that the development of the product will take some time, but certainly not all our time. We would like, I would like. The reality is that <strong>a product is nothing without a customer with a problem</strong>, and without a business allowing to support its development. They are so many tasks that we need to take care, without wasting too much our time. At each step of our progression, we needed to balance our time between the different task in order to reach intermediary business milestone. That's it.</p>
<h2 id="having-a-cofounder-is-a-big-strength">Having a cofounder is a big strength.<a class="zola-anchor" href="#having-a-cofounder-is-a-big-strength" aria-label="Anchor link for: having-a-cofounder-is-a-big-strength">๐</a></h2>
<p>Every week day, Martin and I discuss and decide. Every single week day. Sometimes, even during weekend or holidays. Sometime, we agree, others we don't. When we don't, we listen each other, and we try to not be stuck is a disagreement. Each time, we learn something and the final decision is each time better that our respective positions.</p>
<p>Sometimes, we don't know what to do. We discuss, and we settle on a plan to find a solution. Sometimes, we're just sharing ideas and opinions, and it gives food for thought that helps the other one to come with another interesting idea another day. Sometimes, we are a little bit angry about the other opinion. We talk, we listen, we grow.</p>
<p>In my opinion, it's probably the best advice I can give: create <strong>a team with people able to discuss and exchange</strong>. Even if you have an overlapping expertise, it's better than being alone.</p>
<p><em>Have you experienced the same lessons? What's yours?</em></p>
<p><em>You can also <a href="http://news.ycombinator.com/item?id=4717179">discuss this post on Hacker News.</a></em></p>
<h6 id="related-articles">Related articles<a class="zola-anchor" href="#related-articles" aria-label="Anchor link for: related-articles">๐</a></h6>
<ul>
<li><a href="http://www.businessinsider.com/entrepreneurs-have-to-seek-veterans-in-their-field-2012-9">It's Essential For First-Time Founders To Meet With Other Entrepreneurs</a> (businessinsider.com)</li>
<li><a href="http://www.whiteboardmag.com/the-founder-institute-expands-in-europe-worlddomination-interview-with-adeo-ressi/">"The very idea of VC money is at odds with the success of the founder." Interview with Founder Institute founder Adeo Ressi.</a> (broken link whiteboardmag.com)</li>
<li><a href="https://web.archive.org/web/20121030212002/http://news.ycombinator.org/item?id=4685928">Startups: never have so many understood so little about the statistics of variance present in the outcomes of small samples.</a> (confluence, Hacker News)</li>
<li><a href="https://web.archive.org/web/20121102002051/http://www.thenextwomen.com/2012/10/29/startup-diary-dont-fear-negative-feedback-learn-love-it">Startup Diary: Don't Fear Negative Feedback, Learn to Love It!</a> (thenextwomen.com)</li>
<li><a href="http://blog.latentflip.com/post/33902095607/startup-lessons-learned">Startup lessons learned after two and a half years</a> (blog.latentflip.com)</li>
</ul>
Git tips and tricks2012-10-23T00:00:00+00:002012-10-23T00:00:00+00:00https://ibakesoftware.com/blog/git-tips-and-tricks/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<p>Today, I would like to share some tips and tricks I've learned about Git. There are cases I meet often, and they gave me a better understanding of Git. It's certainly not a deep coverage of the topic, but it could help you as it helped me. Enjoy!</p>
<h2 id="how-to-track-an-existing-remote-branch">How to track an existing remote branch?<a class="zola-anchor" href="#how-to-track-an-existing-remote-branch" aria-label="Anchor link for: how-to-track-an-existing-remote-branch">๐</a></h2>
<p>First of all, you can <a href="http://git-scm.com/book/en/Git-Basics-Working-with-Remotes#Inspecting-a-Remote"><strong>inspect the remote</strong> to check which branches are untracked</a></p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> remote show origin
</span></code></pre>
<p>The untracked branches are listed below "New remote branches". You need to <strong>fetch</strong> in order to store them in remotes/origin.</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> fetch
</span></code></pre>
<p>Finally, you explicitly <a href="http://git-scm.com/book/en/Git-Branching-Remote-Branches#Tracking-Branches"><strong>track the remote branch</strong> by doing</a></p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> checkout</span><span style="color:#bf616a;"> -t</span><span> origin/remote-name
</span></code></pre>
<p>If you want to <strong>set it up with another name</strong>, youโll rather do</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> checkout</span><span style="color:#bf616a;"> -b</span><span> local-name origin/remote-name
</span></code></pre>
<h2 id="how-to-clone-a-private-github-repository-without-prompting-username-and-password">How to clone a private Github repository without prompting username and password?<a class="zola-anchor" href="#how-to-clone-a-private-github-repository-without-prompting-username-and-password" aria-label="Anchor link for: how-to-clone-a-private-github-repository-without-prompting-username-and-password">๐</a></h2>
<p>The typical use case is when the clone is triggered by another software and you just have the username and password (and no SSH keys). To do that, you can use the HTTPS URI including the authentication information as following:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> clone https://username:password@github.com/id/repo
</span></code></pre>
<p>Notice that if you want to use your SSH key, you have to use the ssh URL or the scp-like format.</p>
<h2 id="how-to-migrate-a-repository-from-subversion-to-git">How to migrate a repository from Subversion to Git?<a class="zola-anchor" href="#how-to-migrate-a-repository-from-subversion-to-git" aria-label="Anchor link for: how-to-migrate-a-repository-from-subversion-to-git">๐</a></h2>
<p>I'm talking here about the case of one-shot migration, not a mirror. It exists <a href="https://github.com/alloy/git-svn-mirror">tool to set up a Git mirror of a Subversion repository</a>.</p>
<p>First, retrieve a <a href="http://svnbook.red-bean.com/en/1.7/svn.ref.svnadmin.c.dump.html"><strong>full dump</strong> of your Subversion repository</a></p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">svnadmin</span><span> dump /server/pathto/repo > full.dump
</span></code></pre>
<p>If you don't have directly access to the repository directory, <a href="http://svnbook.red-bean.com/en/1.7/svn.reposadmin.maint.html#svn.reposadmin.maint.replication">you can use svnsync</a> if you have the necessary credentials to remotely access to it.</p>
<p>Second, <strong>load your dump into a local repository</strong> (you can skip that step if you've replicated your repository with svnsync):</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">svnadmin</span><span> create /local/pathto/repo
</span><span style="color:#bf616a;">svn</span><span> admin load /local/pathto/repo < full.dump
</span></code></pre>
<p>Third, <strong>import</strong> your Subversion repository into a Git one</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> svn clone file:///local/pathto/repo /local/pathto/git-repo</span><span style="color:#bf616a;"> -no-metadata -T</span><span> trunk
</span></code></pre>
<p>If you want <strong>also import the tags and the branches</strong>, you can do the following (but beware, it will drastically increase the import time if you have a lot of them)</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> svn clone file:///local/pathto/repo /local/pathto/git-repo</span><span style="color:#bf616a;"> -no-metadata -t</span><span> tags</span><span style="color:#bf616a;"> -b</span><span> branches</span><span style="color:#bf616a;"> -T</span><span> trunk
</span></code></pre>
<p>If you want to <strong>map your Subversion users to Git ones</strong>, you can create a text file in which each line defines a mapping with the following format:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">svn-username</span><span> = Firstname Lastname <email@domain.com>
</span></code></pre>
<p>Then, you just have to provide that file, for instance users.txt, while importing from SVN to Git:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> svn clone file:///local/pathto/repo /local/pathto/git-repo</span><span style="color:#bf616a;"> -no-metadata -A</span><span> users.txt</span><span style="color:#bf616a;"> -T</span><span> trunk
</span></code></pre>
<h2 id="how-to-count-the-number-of-change-sets">How to count the number of change sets?<a class="zola-anchor" href="#how-to-count-the-number-of-change-sets" aria-label="Anchor link for: how-to-count-the-number-of-change-sets">๐</a></h2>
<p>You can <strong><a href="http://git-scm.com/docs/git-log/1.7.5">log all change sets with an empty line</a></strong> with the following:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> log</span><span style="color:#bf616a;"> --pretty</span><span>=format:''
</span></code></pre>
<p>After you just need to <strong>count the lines</strong> with some pipe and bash:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> log</span><span style="color:#bf616a;"> --pretty</span><span>=format:'' | </span><span style="color:#bf616a;">wc -l
</span></code></pre>
<h2 id="how-to-cancel-a-commit-or-a-staging">How to cancel a commit or a staging?<a class="zola-anchor" href="#how-to-cancel-a-commit-or-a-staging" aria-label="Anchor link for: how-to-cancel-a-commit-or-a-staging">๐</a></h2>
<p><img src="/blog/images/sxjVlQKow-gfi3iJkn4K49Q.png" alt="Git stages" /></p>
<p>Before answering that question, I need to get back to the <strong>Git workflow</strong> through working tree, index, and commit areas.</p>
<p>When you're working on tracked files, you make changes, you're working into the <strong>working tree</strong>. When you add your changes, you put them in the staging area for commits or the <strong>index</strong>. When you commit the staged changes, you froze those changes into the <strong>commit</strong> area. The changes set is stored in the repository graph and indexed with a SHA.</p>
<h3 id="put-back-changes-to-index">Put back changes to index<a class="zola-anchor" href="#put-back-changes-to-index" aria-label="Anchor link for: put-back-changes-to-index">๐</a></h3>
<p>So let say <strong>you've just committed</strong> a change you made in a file. You have then the following situation in terms of commits graph:</p>
<p><img src="/blog/images/sefyvjT30z1cWDlbQBIBDeA.png" alt="Git HEAD tag" /></p>
<p>But <strong>you want to cancel and put it back in staging area</strong> (index), you do:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> reset</span><span style="color:#bf616a;"> --soft</span><span> HEAD^
</span></code></pre>
<p>and you have then</p>
<p><img src="/blog/images/s7Gyi6Sg4b6TFXvtsdkUvuw.png" alt="Git HEAD tag reset" /></p>
<p>with all your changes still in the staging area.</p>
<h3 id="remove-changes-from-index">Remove changes from index<a class="zola-anchor" href="#remove-changes-from-index" aria-label="Anchor link for: remove-changes-from-index">๐</a></h3>
<p>If then you want to <strong>remove those changes from the staging area</strong>, you can do:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> reset HEAD
</span></code></pre>
<p>If you want to do the both steps in one, you can do</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> reset HEAD^
</span></code></pre>
<p>In both cases, you don't destroy the commit C, you've just moved the HEAD pointer. That means you can go back to C by doing</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> checkout C
</span></code></pre>
<h3 id="cancel-and-destroy-a-commit-and-all-local-changes">Cancel and destroy a commit and all local changes<a class="zola-anchor" href="#cancel-and-destroy-a-commit-and-all-local-changes" aria-label="Anchor link for: cancel-and-destroy-a-commit-and-all-local-changes">๐</a></h3>
<p><img src="/blog/images/ssbzpivyY6NAtppk7aWMvnQ.png" alt="Summary of moving between stages with Git commands" /></p>
<p>When <strong>you cancel a commit, if you also want to destroy it</strong>, you can do a hard reset:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">git</span><span> reset</span><span style="color:#bf616a;"> --hard
</span></code></pre>
<p>That one also modifies your working tree and index as it gets rid of all local changes.</p>
<p><em>If you have any other tips related to those, please tell me. Same if I make any mistake.</em></p>
<p>Can also <a href="http://news.ycombinator.com/item?id=4687459">discuss that post on Hacker News</a></p>
Sybil is in Dublin tomorrow!2012-10-16T00:00:00+00:002012-10-16T00:00:00+00:00https://ibakesoftware.com/blog/sybil-is-in-dublin-tomorrow/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<h2 id="tonight-the-sybil-team-flies-to-dublin">Tonight the Sybil team flies to Dublin<a class="zola-anchor" href="#tonight-the-sybil-team-flies-to-dublin" aria-label="Anchor link for: tonight-the-sybil-team-flies-to-dublin">๐</a></h2>
<p><img src="http://farm3.static.flickr.com/2324/2389684977_dbe5061259_m.jpg" alt="Crรฉpuscule sur Dublin" /></p>
<p>We're proud to have been selected amongst the world's top 100 startup finalists of the Spark of Genius competition at the <a href="https://web.archive.org/web/20121029185004/http://www.websummit.net/">Dublin Web Summit</a>, when more than 1000 companies have applied to it.</p>
<p>We'll pitch <a href="http://asksybil.com">Sybil</a> on stage 2 in the category Enterprise on Wednesday afternoon 14:42.</p>
<p><strong>We'll be also at the stand 263. Come see us pitch or visit us at our booth, we'll give you a demo, more info about Sybil, and some Belgian surprises.</strong></p>
<h2 id="a-brand-new-website-for-sybil">A brand new website for Sybil<a class="zola-anchor" href="#a-brand-new-website-for-sybil" aria-label="Anchor link for: a-brand-new-website-for-sybil">๐</a></h2>
<p>When your company does software development for whatever reason, much of the capital lies in their developers' expertise. Their talents are important. If you don't not already know, <strong>Sybil is a developer talent management software</strong> that doesn't need any manual input. Give her a source code repository of one of your companyโs project, and she'll tell you your developers' talents.</p>
<p>We want to use the opportunity of a big event such as the <a href="https://web.archive.org/web/20121029185004/http://www.websummit.net/">Dublin Web Summit</a> to launch our brand new offering and website for Sybil. You'll find there all the necessary information about Sybil, so don't hesitate to contact us if you're interested or for any question. Weโll be happy to hear from you.</p>
<p><em>See you in Dublin!</em></p>
Arrrrcamp 2012: Pirates on Rails2012-10-08T00:00:00+00:002012-10-08T00:00:00+00:00https://ibakesoftware.com/blog/arrrrcamp-2012-pirates-on-rails/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<h2 id="why">Why?<a class="zola-anchor" href="#why" aria-label="Anchor link for: why">๐</a></h2>
<p><img src="http://b.vimeocdn.com/ts/217/145/217145900_295.jpg" alt="arrrrcamp flag" /></p>
<p>As a developer, I think it's important to attend some tech event for several reasons: to be in touch with the community, to meet other developers, to see again some acquaintances or friends, to learn something new from known tech leaders, to discuss and debate some technical topics.</p>
<p>As a founder, in addition to all of the previous reasons, it is a situation that forces you to dig into the technical part of the job, with no or few interruption. The fresh air is welcome.</p>
<p>Last Thursday and Friday, we were at <a href="https://web.archive.org/web/20121130092228/http://arrrrcamp.be/">Arrrrcamp, the Belgian conference about Ruby, Rails, and other related topics in software and web development (and pirates!)</a>. As I'm not so a veteran in those technologies, it's the opportunity to confirm I've learned this year. It's also an occasion to present Sybil to some speakers and get feedback.</p>
<h2 id="what">What?<a class="zola-anchor" href="#what" aria-label="Anchor link for: what">๐</a></h2>
<p>This year, the Arrrcamp was organized on 2 days and aligned an impressive bunch of speakers such as Yehuda Katz, Steve Klabnitz, Roy Tomeij, or Konstantin Haase. The event was still very well organized at a nice location and with good catering with the coffee and the sweeties. Two tracks of talk were available in parallel, that means you could attend 6 talks per day. After each day, you could take a beer, or two, at a networking event, chill out, meet new persons, and talk tech.</p>
<h2 id="the-talks">The talks<a class="zola-anchor" href="#the-talks" aria-label="Anchor link for: the-talks">๐</a></h2>
<p>Generally, the quality of the talks has improved since the previous session. But I would like less introduction in talks, and more sharp and high technical contents. With 40 minutes, it's a hard exercise, but possible. I also expect some strong motivated opinion from speakers because they are food for thoughts even if you don't agree. The humor is also a good component, and I have to admit there were fun and humor in lot of talks.</p>
<p>I've attended the following talks:</p>
<ul>
<li><a href="http://vimeo.com/album/2121090/video/51898267">Y Not? Adventures in Functional Programming</a> by <a href="http://onestepback.org/">Jim Weirich</a>,</li>
<li><a href="http://vimeo.com/album/2121090/video/51529599">Dealing with Scale at Yammer: Caching and Services</a> by <a href="http://blog.harakys.com/">Yann Armand</a>,</li>
<li><a href="https://speakerdeck.com/u/rkh/p/we-dont-know-http">We don't know HTTP</a> ( <a href="http://vimeo.com/album/2121090/video/51903877">video</a>) by <a href="http://rkh.im/">Konstantin Haase</a>,</li>
<li><a href="http://vimeo.com/album/2121090/video/51903878">Crying over spilt cruft</a> by <a href="http://yehudakatz.com/">Yehuda Katz</a>,</li>
<li><a href="https://speakerdeck.com/u/rodreegez/p/bug-requests-and-pull-reports-2-dot-0">Bug Requests and Pull Reports</a> ( <a href="http://vimeo.com/album/2121090/video/51528462">video</a>) by <a href="http://rodreegez.com/">Adam Rogers</a>,</li>
<li><a href="http://daveworth.github.com/ATLRUG_04_2012-BrakemanPresentation/">Static analysis and detecting security vulnerabilities in Rails</a> ( <a href="http://vimeo.com/album/2121090/video/51635385">video</a>) by <a href="https://github.com/daveworth">Dave Worth</a>,</li>
<li><a href="https://github.com/newhavenrb/conferences/wiki/Using-Rails-without-Rails">Using Rails without Rails</a> ( <a href="http://vimeo.com/album/2121090/video/51903882">video</a>) by <a href="http://piotrsarnacki.com/">Piotr Sarnacki</a>,</li>
<li><a href="http://roy.io/ac12">Modular & reusable front-end code with HTML5, Sass and CoffeeScript</a> ( <a href="http://vimeo.com/album/2121090/video/51529598">video</a>) by <a href="http://roytomeij.com/">Roy Tomei</a> j,</li>
<li><a href="http://vimeo.com/album/2121090/video/51898265">RubyMotion: Ruby in your pocket</a> by <a href="http://chopine.be">Laurent Sansonetti</a>,</li>
<li><a href="https://speakerdeck.com/u/steveklabnik/p/why-should-i-care-about-rails-4">Why should I care about Rails 4</a> ( <a href="http://vimeo.com/album/2121090/video/51898266">video</a>) by <a href="http://steveklabnik.com/">Steve Klabnik</a>, and</li>
<li><a href="http://vimeo.com/album/2121090/video/51634446">Therapeutic Refactoring</a> by <a href="http://kytrinyx.com/">Katrina Owen</a>.</li>
</ul>
<p>I won't go through all the content (and will link the titles with the slides when published/provided, most of the current linked presentations are not given at Arrrrcamp). I rather share some thoughts about some of those topics.</p>
<h2 id="showcase-is-good-numbers-are-better">Showcase is good, numbers are better<a class="zola-anchor" href="#showcase-is-good-numbers-are-better" aria-label="Anchor link for: showcase-is-good-numbers-are-better">๐</a></h2>
<p><img src="http://farm4.static.flickr.com/3441/3931901057_41d0f6a84d_s.jpg" alt="Number - 4" /></p>
<p>A showcase is always interesting because it demonstrates what's possible. The scalability experience at Yammer shared by Yann Armand is really interesting. Yes, the solutions are classic, but you know that if you have to serve about 6M users you could do it with that approach. But as <a href="http://blog.steveklabnik.com/posts/2012-09-27-seriously--numbers--use-them-" title="Seriously numbers use them">Steve Klabnik discussed</a>, you couldn't advocate for one or another solution only on hypothetical reasons. You should test and measure. That's the only way.</p>
<p>In practice, a system could vary from another one in so many ways that it's impossible to predict the result only from a canonical test case. The intertwining interactions between the different elements of a running environment are now so complex that you cannot embrace them all. You cannot predict the effect of an optimization without testing it, measure it, and understand it in a specific case.</p>
<h2 id="cache-is-not-always-the-solution">Cache is not always the solution<a class="zola-anchor" href="#cache-is-not-always-the-solution" aria-label="Anchor link for: cache-is-not-always-the-solution">๐</a></h2>
<p>I've especially liked Konstantin's talk. He came back to the definition of the HTTP protocol and explain how it could be leveraged to make your application more scalable or secure. Before thinking about how to improve on the results, you should start asking yourself if you are using the protocol properly. Clearly understanding the elements you're building on top helps you to design better architectures. You just have to think them in terms of request, resource, and representation.</p>
<h2 id="help-others-to-help-you-and-collaboration-could-happen">Help others to help you, and collaboration could happen<a class="zola-anchor" href="#help-others-to-help-you-and-collaboration-could-happen" aria-label="Anchor link for: help-others-to-help-you-and-collaboration-could-happen">๐</a></h2>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/6/67/Collaboration_logo_V2.svg/320px-Collaboration_logo_V2.svg.png" alt="Collaboration logo." /></p>
<p>Even if Adam focused on open source projects, I think he put the finger on a very important point for collaboration even in corporate environment. When there is a bug to fix, even if you know and can fix it, you shouldn't always do it especially if it was reported by someone else. Indeed, by doing it so, you waste an opportunity to help a person to learn and collaborate. Instead, it would be better to start a discussion and guide her to resolve the issue.</p>
<p>It's the same in company environment, code are not just the sum of subparts maintained by different and lone developers. As Martin said, the culture emerge because of the interaction of developers over the same pieces of code. That's why Martin and I frequently swapped our code assignations. That does use some time, but it's not a waste because it allows you to learn and progress thanks to shared point of view and discussions.</p>
<h2 id="reasons-are-more-interesting-than-the-resulting-choices">Reasons are more interesting than the resulting choices<a class="zola-anchor" href="#reasons-are-more-interesting-than-the-resulting-choices" aria-label="Anchor link for: reasons-are-more-interesting-than-the-resulting-choices">๐</a></h2>
<p>The choices or advices are always interesting, but explaining them even more so. It's relevant concerning talk but also code. When you just present your choice, you don't give to your reader or spectator the power to understand it or to apply the same path in similar situations.</p>
<p>Yehuda has very well underlined that problem with cruft. The cruft are usually results of choices supported by very good reasons. They resolved some edge cases or simply the mirror of the complexity of the real world and the human being. If you don't track those cruft and document them, i.e. providing the assumptions and reasons behind, you don't give the power to a future developer to understand why they are there. It's a big risk to not transfer that knowledge.</p>
<p>What's certainly true for weird choices is also for good choices. When Roy taught us his modularity approach in front-end development, he has always motivated his choices. Whatever the reason (e.g. maintainability, low coupling, factual performance, coherence), there was one. You may not agree (at least when the reason is not supported by fact), but you can at least think about it.</p>
<h2 id="don-t-tell-show">Don't tell, show.<a class="zola-anchor" href="#don-t-tell-show" aria-label="Anchor link for: don-t-tell-show">๐</a></h2>
<p>It's probably obvious and standard, but it's enough to restate it. It could be about functional programming, static analysis in Ruby, new features in a next release of Rails, or refactoring. Demonstrating it, it's concrete and easy to remind. Add some emotional element as humor or great Ross' paintings, and I'll remind it better. Thanks you Arrrrcamp speakers !</p>
<h2 id="arrrr">Arrrr<a class="zola-anchor" href="#arrrr" aria-label="Anchor link for: arrrr">๐</a></h2>
<p><img src="http://farm1.static.flickr.com/65/160807760_99dd54bef6_m.jpg" alt="Pirate deck at Club Earl" /></p>
<p>Beyond the talks, we've also demonstrated Sybil to some speakers (Yann, Yehuda, Konstantin, Roy, and Steve) and got interesting feedback from them. We've exchanged opinions or experiences with other participants during the coffee breaks. We've enjoyed the lightning talks ( <a href="http://encycl.opentopia.com/term/Ook!_programming_language">Big kudo for the new programming language: librarian</a>). Definitively a good event, weโll attend again next year. You should too. Arrrr!</p>
<p>You can also <a href="http://news.ycombinator.com/item?id=4626475">discuss that post on Hacker News</a>.</p>
Startup of the month featured on MIC Brussels blog2012-10-05T00:00:00+00:002012-10-05T00:00:00+00:00https://ibakesoftware.com/blog/startup-of-the-month-featured-on-mic-brussels-blog/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<p>Martin has recently shared with the <a href="https://web.archive.org/web/20221021103555/https://mic-brussels.be/en/">MIC Brussels</a> our experiences as founders of 8th color. <a href="https://web.archive.org/web/20150514063025/http://blog.mic-brussels.be/2012/10/03/8thcolor-founders-christophe-philemotte-martin-van-aken/">They've just published it, go take a look</a>.</p>
Do you want to play?2012-09-28T00:00:00+00:002012-09-28T00:00:00+00:00https://ibakesoftware.com/blog/do-you-want-to-play/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<h2 id="once-upon-a-time">Once upon a time<a class="zola-anchor" href="#once-upon-a-time" aria-label="Anchor link for: once-upon-a-time">๐</a></h2>
<p>Last Wednesday, I visited one of our Pilot to run Sybil on another of their projects. The project is developed on another site, that means another environment, new deployment challenge. <a href="https://ibakesoftware.com/blog/the-unexpected-reality-of-deployment/" title="The unexpected reality of deployment">I won't dig into the technical issues I've met</a>, but I'll rather share a personal experience and feeling.</p>
<h2 id="the-journey">The journey<a class="zola-anchor" href="#the-journey" aria-label="Anchor link for: the-journey">๐</a></h2>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/6/6d/Super_Mario_Bros._logo.png" alt="Super Mario Bros, one of the best selling video" /></p>
<p>When I need to go in town, my motorcycle is the best way to move. Whatever the typical morning traffic jam, I know I'll be there on time. It makes me feeling like a game character that runs, jumps, and bounces to reach its goal and earn some bonus. <strong>My mission? Show off The Great Sybil whatever the dangers</strong>. My destrier? My motorcycle to flight over the lava. My weapon and my shield? My laptop and my smartphone to counter attacks and obstacles. My laptop is the toolbelt that makes me ready to adapt and improvise. You cannot expect to have an access to a correct computer with a decent OS. My smartphone is my preferred spell. It gives me access to Internet thanks to tethering. You cannot expect that where you go you'll be able to access the Internet. When you need to improvise, it's an unbelievable source of information and means. Do I need a tool to do something? No problem, I can <em>aptitude install</em> that tool. The tortoise may have its home on its back - I got my whole company on mine.</p>
<p>Why I'm feeling like a adventurer? Because I enjoy it. Because I like that kind of challenges. Because I want to provide a great product to my customer and help them. As when you're a child, you imagine some situation and you enjoy it. That's exactly the same. I really live and enjoy it. It's a great feeling.</p>
<h2 id="the-joy">The joy<a class="zola-anchor" href="#the-joy" aria-label="Anchor link for: the-joy">๐</a></h2>
<p>So what? I realize that it's important and it's the feeling that pushed me to start 8th color and build Sybil with Martin. Yes, as any adventure, it's sometimes hard because the risk, the long hours, the money (or lack of), the unexpected future, the uncertainty. Yes, it's hard. It's also a part of the joy. If it was easy, it would be less fun. It would taste less like an adventure. That feeling is something very important because it drives me. I want to continue, to reach each mission, to meet each challenge.</p>
<p><strong>I'm not sure I would be capable to do the same without the same enjoyment</strong>. I can't imagine spending most of my time to do boring things. Yes, sometimes, you have to for good reasons. But I'm not sure there is any kind of good reason to stay with boring things if you can change for something that really enjoy and drives you.</p>
<h2 id="which-level-easy-normal-hard">Which level? Easy, Normal, Hard<a class="zola-anchor" href="#which-level-easy-normal-hard" aria-label="Anchor link for: which-level-easy-normal-hard">๐</a></h2>
<p><img src="http://anothersidequest.files.wordpress.com/2012/02/36500-500-312.gif" alt="Wolfenstein 3D difficulty level" /></p>
<p>Some will advocate that money is a very good reason. I would answer it's more a constraint, another challenge. Even, it could help you to focus and not waste your time and money on things that are not worth it. Other will say that family is another one. I would answer it's again a good thing. It's a marathon, you're a human with feelings and emotions. You cannot forget what makes you, including your family and friends. It probably reminds you that there is a life aside your startup or project. It will recall you that even if it is sometimes necessary to work long hours, it would be better to not work too much. You cannot be efficient, creative, and productive when you're exhausted. To be honest, Martin and I sometimes work about 80 hours per a week (and I'm sure some have done more). Each time, we try to relax the next week and chill out. It's hard when you're workaholic - or driven or just a bit too enthusiast.</p>
<p>But <strong>each time, this is a constraint that helps us to continue, to keep the joy to do it, and to stay creative (and productive)</strong>. It's maybe counter-intuitive, but it's not because you work more or play more, that you produce more or play well.</p>
<h2 id="try-again">Try again?<a class="zola-anchor" href="#try-again" aria-label="Anchor link for: try-again">๐</a></h2>
<p>That's a great feeling, and it makes me really addicted to the process of a startup and building a company. I didn't know before I could enjoy so much the development of a product that addresses real problem of real persons. It's a very great experience, and I cannot avoid to think about other possible realization of ideas even in industries that I donโt know about. The technical part is not the only fun. The development of a business is really an interesting and fun aspect. We made a joke of it:</p>
<blockquote>
<p><strong>If the product works, weโll push it and make another one. If it doesnโt, weโll make another one.</strong></p>
</blockquote>
<p>With my bike, my laptop, and my smartphone, I'll be on the road and drive to live another adventure. But now, the <strong>8th color</strong> one is a great one.</p>
<p><em>Do you want to play?</em></p>
<p>You can also <a href="http://news.ycombinator.com/item?id=4585031">discuss the post on HackerNews</a>.</p>
Bootstrapping Design Review: All you have to do is practice2012-09-21T00:00:00+00:002012-09-21T00:00:00+00:00https://ibakesoftware.com/blog/bootstrapping-design-review-all-you-have-to-do-is-practice/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<h2 id="a-few-thoughts-about-user-interface-design">A few thoughts about user interface design<a class="zola-anchor" href="#a-few-thoughts-about-user-interface-design" aria-label="Anchor link for: a-few-thoughts-about-user-interface-design">๐</a></h2>
<p>There is something very strange about design. People commonly think that it's a task reserved to a kind of persons mastering graphical art. <strong>It's like you cannot be a designer if you're not good at drawing</strong>. This is a common misconception. There are different kind of designers, and even software developers have their design process. The common ground between those different categories is the role of finding the best way to serve a purpose while respecting some constraints. You have to be creative to deal with the constraints while keeping the purpose.</p>
<p><a href="http://xkcd.com/689/"><strong>As engineer or software developer, it's a process that we do everyday</strong></a>. It could be at a high scale when designing an infrastructure or a whole application or at a very microscopic scale when designing a simple programming function. We're trying to address different constraint such as performance, readability, maintenance, reliability, and producing an implementation that really answers the purpose.</p>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Wrap_Rage_Example.jpg/300px-Wrap_Rage_Example.jpg" alt="An example of wrap rage." /></p>
<p>But when it's time to design an user interface (<a href="http://en.wikipedia.org/wiki/User_interface" title="User interface">UI</a>), it seems that it's a forbidden land for the developers, at least that some still think. It's probably because it involves, while realizing it, different graphical components that they cannot produce. A design of UI is more than the sum of its graphical components. <strong>It's about allowing the user to use the application functions</strong>. It's more about understanding how the user will interact with the application, what is his perception, what does he expect to find, etc. It's not about drawing shiny and pretty buttons, even if that could participate to the whole. If you're a beginner in design, you'll probably not find a lot of good resources that will help you to do it. Rather, you'll find a lot of advanced and complicated contents discussing principles that are sometimes far too much elaborated to be understood (or useful!) at your level. This really miss to all people that would like to step forward in that domain and want to learn. This is no more the case.</p>
<h2 id="the-book">The book<a class="zola-anchor" href="#the-book" aria-label="Anchor link for: the-book">๐</a></h2>
<p><img src="/blog/images/bootstrappingdesign_cover.jpg" alt="Cover of the book Bootstrapping Design" /> In his book, <a href="http://bootstrappingdesign.com/">Bootstrapping Design</a>, <a href="http://blog.studiofellow.com/">Jarrod Drysdale</a> will allow you to design your own UI by following a clear and simple process. He debunks a lot of myths about design and introduces enough the fundamental principles such as proximity or color. The book is split in three main parts: Mentality, Principles, and Practice. <strong>The first part</strong> explains to whom the book is addressed and that it exists a design process good enough for beginners.</p>
<blockquote>
<p>We are starting businesses not pandering for design awards.</p>
</blockquote>
<p><strong>The second part</strong> introduces the most important fundamentals necessary to accomplish design.</p>
<blockquote>
<p>My intent is to emphasize design basics rather than to reduce the whole of design to a bag of tricks.</p>
</blockquote>
<p><strong>The last and third part</strong> describes a process, a methodology to design the UI of your application. In the end, as developing software, designing an UI is all about practice and iteratively improving the results.</p>
<blockquote>
<p>Anyone can be a great designer with practice. Itโs both at once liberating and frightening: your future as a designer depends only on how hard youโre willing to work</p>
</blockquote>
<p>I don't want to be a professional of design right now, but I want to do design. <strong>In my honest opinion, this is a very good book on the topic for people like me that want to design their own UI, to understand what they do, and to have a process to start.</strong> The book illustrates most of the concepts with clear and simple examples. It presents only a simple, practical, and affordable way to do design. Even if you won't design, I think it's a good book to get the necessary elements to interact with a designer, especially the terminology. Finally, if you want to go farther, Jarod provides at the end of each chapter enough good references to do the next step.</p>
<p>Beyond its goodness, I miss a real concrete exercise, that allows me to learn by doing in a kind of pair designing, as the books in the <a href="http://www.pragprog.com/" title="The Pragmatic Programmer">Pragmatic Programmers</a> edition usually provide. It's true that you can follow the last chapter in order to do your own project, but there is definitely a plus when you can compare your output with someone that knows better than you.</p>
<p>I'll finish with the following quote:</p>
<blockquote>
<p><strong>No magic knowledge hidden away in design books, blogs, or classes will teach you to be a great designer. <a href="http://blog.8thcolor.com/2012/09/an-exercise-in-boldness/" title="An exercise in boldness">All you have to do is practice.</a> Learning design is that simple</strong></p>
</blockquote>
<p>And you what have thought about the book? Have you others books, blogs to advice in the same vein?</p>
Beer + Sybil + 4 Geeks = Tech Brew podcast2012-09-10T00:00:00+00:002012-09-10T00:00:00+00:00https://ibakesoftware.com/blog/beer-sybil-4-geeks-tech-brew-podcast/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<p>A few months ago, <strong><a href="https://web.archive.org/web/20180812015255/http://techbrew.be/2012/09/tech-brew-episode-17-sybil/">we were invited</a> by <a href="http://twitter.com/blueclock">Gilbert West</a> and <a href="http://twitter.com/massin">Andrew Matheson</a> in Tech Brew</strong>. <a href="http://techbrew.be/about-techbrew/">Tech Brew</a> shows to the world the Belgian tech startup scene through podcasts powered by Belgian Beers. A whole program. They are like our local Robert Scoble, but it's better: there are good <a href="http://en.wikipedia.org/wiki/Beer_in_Belgium" title="Beer in Belgium">Belgian beers</a>. Honestly, if you're interested in tech startup, you should listen <a href="https://web.archive.org/web/20190503051610/http://techbrew.be/">their podcasts</a>, it gives you a good idea of what is emerging in Belgium.</p>
<p>For us, it was the first time we were recorded for a podcast. We had a very good chat allowing us to present Sybil and our way to build it. We enjoyed it a lot. <strong><a href="https://web.archive.org/web/20180812015255/http://techbrew.be/2012/09/tech-brew-episode-17-sybil/">Tech Brew have just released our interview, so go take a look and listen</a></strong>. Tell us what you think!</p>
The unknown taxonomy of development skills2012-08-27T00:00:00+00:002012-08-27T00:00:00+00:00https://ibakesoftware.com/blog/the-unknown-taxonomy-of-development-skills/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<h2 id="my-path">My path<a class="zola-anchor" href="#my-path" aria-label="Anchor link for: my-path">๐</a></h2>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/2/2c/Remi_turtlegrafik.png/300px-Remi_turtlegrafik.png" alt="Example Output of Logo (turtle graphic)" /></p>
<p>I started to program aged 4 with <a href="http://en.wikipedia.org/wiki/Logo_%28programming_language%29">Logo</a>. I then learned <a href="http://en.wikipedia.org/wiki/Batch_file">Batch</a> and <a href="http://en.wikipedia.org/wiki/BASIC">BASIC</a> at about 10, and built basic games and <a href="http://en.wikipedia.org/wiki/IRC_bot">IRC bots</a>. During my software engineering cursus, I followed several <a href="https://en.wikipedia.org/wiki/Programming_language_theory">pure computer</a> <a href="https://en.wikipedia.org/wiki/Computational_complexity_theory">science courses</a>, did programming and sysadmin works during internship and student jobs, and started some personal projects. Once graduated as a software engineer, I started a <a href="http://theses.ulb.ac.be/ETD-db/collection/available/ULBetd-11052008-122223/">PhD in AI</a> and taught several topics: <a href="http://en.wikipedia.org/wiki/Object-oriented_programming">Object-Oriented Programming</a>, <a href="http://en.wikipedia.org/wiki/The_C%2B%2B_Programming_Language">C++</a>, <a href="http://en.wikipedia.org/wiki/Java_%28programming_language%29">Java</a>, and <a href="http://en.wikipedia.org/wiki/Natural_computing">AI techniques</a>.</p>
<p>My <a href="http://rd.springer.com/article/10.1007/s11047-012-9317-x">PhD in the pocket</a>, I started to work as <a href="http://be.linkedin.com/in/christophephilemotte">a freelance software and infrastructure engineer</a>. One year ago, I've really started to <a href="http://rubyonrails.org/">learn</a> <a href="http://www.w3.org/TR/2011/WD-html5-20110525/">the</a> <a href="http://www.w3.org/TR/CSS/">web</a> <a href="http://www.codecademy.com">technologies</a>. Tomorrow will be another opportunity to learn and practice something new. I've still a long way before me.</p>
<h2 id="what-i-miss">What I miss<a class="zola-anchor" href="#what-i-miss" aria-label="Anchor link for: what-i-miss">๐</a></h2>
<p>In my opinion, <strong>software development implies a lot of different skills and knowledge, and a good aptitude to learn new ones</strong>. It cannot be summarized to a bunch of keywords, as the ones we put on our resume. It's more than that: my software development capabilities is the sum of all the skills I've learned and practiced among different projects and cases.</p>
<p>Beyond recruitment and job seeking, I'm interested in that information in order <strong>to follow my progress and my learning</strong>, but also to know what I miss in my profile to participate to a given project, or simply compare me with others or profile patterns. It's all about my personal development.</p>
<p><strong>It's also about communication.</strong> If I don't have a clear structure to organize my skills with a hierarchical semantic, I can't expect that a non programmer (e.g. <a href="http://en.wikipedia.org/wiki/Human_resource_management" title="Human resource management">Human Resource Manager</a>, Project Manager, your wife) could really understand what it's involving in my job. I'm sure that some very experienced managers have developed some kind of implicit feeling and understanding of the job, but it's not enough. We can only expect considerations of what we do only if we clearly explain it, and not with a bunch of unrelated keywords.</p>
<p>For those reasons, I would like to keep an eye on the skills I have developed and effectively used. <strong>I really miss that tracking</strong>. Because a skill is only proved with its effective usage on a real project, I would also like to track the projects I've participated, and which kind of domain business they were about. <strong>It's my portfolio</strong> like the one of a photograph or a cabinet maker: without realizations, you're not a developer, whatever long is your skill set.</p>
<h2 id="where-to-start">Where to start?<a class="zola-anchor" href="#where-to-start" aria-label="Anchor link for: where-to-start">๐</a></h2>
<p>To start somewhere, I could certainly detail some parts, list the libraries I master and the ones I've just used once, and describe the projects in which I was involved. But it's a tedious work you generally do only when you're updating your resume. At that moment, even if you manage to remember a lot of details - and I'll personally forget several ones - putting them all on your resume as it will prove any real capability, except that you can throw a bunch of buzzwords in a document. Personally, I'm trying to organize my skills in different categories. But I'm not happy with that process and format for several reasons such as:</p>
<ol>
<li>it's tedious, I've got the feeling I'm wasting my time;</li>
<li>even if a resume needs all the details, I would like to have them to follow my progression;</li>
<li><strong>a standard <a href="https://en.wikipedia.org/wiki/Taxonomy_%28general%29">taxonomy</a> of skills is missing</strong></li>
</ol>
<p>I'm very concerned by the last one. I think a proper taxonomy would be the first step for a better learning, but also a better communication of what software development consists in (and not reducing it to a bunch of non related keywords).</p>
<h2 id="the-unknown-taxonomy">The unknown taxonomy<a class="zola-anchor" href="#the-unknown-taxonomy" aria-label="Anchor link for: the-unknown-taxonomy">๐</a></h2>
<p>There are very different possible ways to structure the skills and knowledge of software development, depending on the point of view. The <a href="https://en.wikipedia.org/wiki/ACM_Computing_Classification_System">ACM Computing Classification</a> System is a subject classification system for computer science, interesting but not adequate to software development. The <a href="https://en.wikipedia.org/wiki/Portal:Computer_programming">Wikipedia portal 'computer programming'</a> is a better start, but it doesn't include for instance specific libraries or deals with knowledge that are not related to development skills such as the <a href="https://en.wikipedia.org/wiki/Category:Computer_programmers">Wikipedia category of 'computer programmers'</a>. The <a href="http://en.wikipedia.org/wiki/Skills_Framework_for_the_Information_Age">Skills Framework for the Information Age</a> is a model to describe the the skills of ICT professionals. It's certainly a better start point, but it's too wide since it tries to address any profession in ICT including business and management ones. As a consequence, its granularity is not enough for my purpose. Building this kind of taxonomy is not an easy task, especially because there are so many concepts to consider.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Programming_language">programming languages</a> could be organized by <a href="https://en.wikipedia.org/wiki/Programming_paradigm">paradigm</a> (e.g. procedural, object oriented, functional), but also by <a href="http://en.wikipedia.org/wiki/Type_system">kind of typing</a> (e.g. weak, strong, static, dynamic) or <a href="https://en.wikipedia.org/wiki/Programming_language#Semantics">semantics</a> (e.g. static, dynamic). The <a href="https://en.wikipedia.org/wiki/Programming_library">libraries</a> can be organized by programming languages, but also by tackled domain (e.g. security, network). There are also other languages such as <a href="https://en.wikipedia.org/wiki/Markup_language">markup languages</a> (e.g. HTML, XML). If you consider <a href="https://en.wikipedia.org/wiki/Database">database</a>, you have to consider different <a href="https://en.wikipedia.org/wiki/Database#Database_type_examples">types</a> (e.g. graph, unstructured, object, relational), <a href="https://en.wikipedia.org/wiki/Database_language">languages</a> (e.g SQL, XQuery), and <a href="https://en.wikipedia.org/wiki/Database_management_system">DBMSes</a> (e.g. PostgreSQL, Neo4J). We cannot forget the kind of <a href="http://en.wikipedia.org/wiki/Software_development_methodologies">development methodology</a> you can follow (e.g. waterfall, agile), some specific development topics (e.g. <a href="http://en.wikipedia.org/wiki/Embedded_system">embedded system</a>, <a href="http://en.wikipedia.org/wiki/Concurrent_programming">concurrent programming</a>, <a href="http://en.wikipedia.org/wiki/Distributed_programming">distributed programming</a>, <a href="http://en.wikipedia.org/wiki/Artificial_intelligence">AI techniques</a>). or the <a href="http://en.wikipedia.org/wiki/Programming_tool">development tools</a> (e.g. RCS, test and integration, profiling, issue tracking).</p>
<p>It's not something I can just list. I need a real taxonomy to organize those skills.</p>
<h2 id="how">How?<a class="zola-anchor" href="#how" aria-label="Anchor link for: how">๐</a></h2>
<p>So, I need to build this taxonomy. In fact, we're already building it with Sybil. But <strong>we don't want a taxonomy that is only the result of our point of view</strong>. We have already started to discuss it with several developers (friends, ex-colleagues, and of course the companies where Sybil is in beta). <strong>We would like more, we would like your opinions</strong> (here or on <a href="http://news.ycombinator.com/item?id=4438600">Hacker News dicussion</a>):</p>
<ol>
<li>what will be the perfect taxonomy for you?</li>
<li>which categories do you expect?</li>
</ol>
<h6 id="related-articles">Related articles<a class="zola-anchor" href="#related-articles" aria-label="Anchor link for: related-articles">๐</a></h6>
<ul>
<li><a href="http://bencoe.tumblr.com/post/29289419142/software-development-is-an-apprenticeship">Software Development is an Apprenticeship</a> (bencoe.tumblr.com)</li>
<li><a href="https://ibakesoftware.com/blog/skills-management-4-csc-belgium-case/">Skills Management #4: CSC Belgium case</a> (8thcolor.com)</li>
<li><a href="http://www.javacodegeeks.com/2012/08/whats-your-geek-number-my-points-system.html">What's Your Geek Number? My Points System To Rate Software Engineers</a> (javacodegeeks.com)</li>
<li><a href="https://web.archive.org/web/20210620054540/http://www.readysetrails.com:80/index.php/181/this-is-why-learning-rails-is-hard/">This is why learning Rails is hard</a> (readysetrails.com)</li>
<li><a href="http://www.codeofhonor.com/blog/marketing-yourself-as-a-programmer">Marketing yourself as a programmer</a> (codeofhonor.com)</li>
</ul>
The unexpected reality of deployment2012-08-03T00:00:00+00:002012-08-03T00:00:00+00:00https://ibakesoftware.com/blog/the-unexpected-reality-of-deployment/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<h2 id="the-task">The task<a class="zola-anchor" href="#the-task" aria-label="Anchor link for: the-task">๐</a></h2>
<p>Three months ago, another company interested in <a href="https://web.archive.org/web/20121218132837/http://asksybil.com:80/index.html">Sybil</a> accepted to be a pilot. Very quickly, <strong>the question of installation came</strong>, and we had to plan it. First of all, we met with the company again in order to learn about their technical environment. We had even already tested some configurations in the application itself, such as the connection to the repository. We decided with the customer that the best option was to provide them a full <a href="http://en.wikipedia.org/wiki/Virtual_machine" title="Virtual machine">VM</a>, to be independent of any local circumstances. As first list of constraints, we had then:</p>
<ul>
<li>no access from outside, even through a<a href="http://en.wikipedia.org/wiki/Virtual_private_network" title="Virtual private network">VPN</a>,</li>
<li>the deployment of Sybil made thanks to a VM,</li>
<li>an old server with Microsoft Windows 2003 as host for the VM, and</li>
<li>a machine with access to this server.</li>
</ul>
<p>We then planned a visit to really install Sybil.</p>
<h2 id="the-run">The run<a class="zola-anchor" href="#the-run" aria-label="Anchor link for: the-run">๐</a></h2>
<p>On paper, the VM was ready. I was confident, but from my experience I knew that everything could happen. Indeed, <strong>our first knowledge of the technical environment was incomplete</strong> as we discovered when installing Sybil.</p>
<p>First of all, we tested the VM on my laptop. We bumped into several problems due to the fact that Internet access was only possible through a proxy. We asked the necessary information to use the proxy and we quickly adapted, well to be correct Martin hacked the application to play with the proxy. We ran the first analysis. We then met other minor problems, we investigated and fixed them. After about 1 hour, we collected a list of bugs and other issues allowing us to go further.</p>
<p>A this point, the VM was ready to be deployed. I needed to copy the VM on the server. That took me a zillion of seconds. Yes, the <a href="http://en.wikipedia.org/wiki/Local_area_network" title="Local area network">LAN</a> wasn't a top notch one. After 30 minutes of data transfer, we installed <a href="http://en.wikipedia.org/wiki/VirtualBox" title="VirtualBox">Virtual Box</a>, configured the network and the port forwarding, and ran the VM.</p>
<p>We then checked the application. Everything seemed ok. We reset the data and ran the indexing and analyses. We waited a few minutes to check if everything seemed ok. During this time we showed how to access the application and how to use it. At the end, we left the office after 2 hours and half.</p>
<h2 id="a-priori-information-are-never-complete">A priori information are never complete<a class="zola-anchor" href="#a-priori-information-are-never-complete" aria-label="Anchor link for: a-priori-information-are-never-complete">๐</a></h2>
<p>It wasn't so easy even if we had the hand on the VM. At the end, the technical environment wasn't the one expected according our first visit. Indeed, we discovered the following other constraints during the installation:</p>
<ul>
<li>access to Internet only through a secured proxy,</li>
<li>access to the server only thanks to Remote Desktop,</li>
<li>data transfer to the server through a shared network drive, and</li>
<li>a very low LAN bandwidth.</li>
</ul>
<p>We expected some problems with the deployment into a customer infrastructure, but we were anyway surprised by the nature of them. Even if we prepared the installation with a previous meeting, we only got the details that our contact knew about. It is simply due to the fact that <strong>the person didn't know our application, so he couldn't figure out exactly which details we needed.</strong></p>
<p>You can always argue that we knew and we couldn't ask correct question. But an application is developed in a controlled environment. It's not put in a situation that allows to learn what are its exacts requirements. Yes, we knew it in someway, but it was not enough explicit in our mind, not enough to be communicated to our contact when we needed the details about the infrastructure. This is simply due that a today application involves a lot of implicit requirements. No amount of preparation can make it appear out of nowhere.</p>
<h2 id="reality-is-an-opportunity-to-improve">Reality is an opportunity to improve<a class="zola-anchor" href="#reality-is-an-opportunity-to-improve" aria-label="Anchor link for: reality-is-an-opportunity-to-improve">๐</a></h2>
<p>From my point of view, it's not a fatality, it's reality. It's an opportunity to build a rigorous approach to deploy our application and control all its requirements. I can also develop a better understanding of what I need to take care of. If I take care, I can improve the application but also my development. As system administrator, I always try to replicate the kind of environments I've met in order to test the deployment and the integration of the application. <strong>It allows to underline the weaknesses in the application</strong>, especially the ones built on top of strong assumptions. I can then make it workable, probably the most important for us.</p>
<h2 id="where-your-application-really-exists">Where your application really exists<a class="zola-anchor" href="#where-your-application-really-exists" aria-label="Anchor link for: where-your-application-really-exists">๐</a></h2>
<p><a href="http://commons.wikipedia.org/wiki/File:Human_brain_in_a_vat.jpg"><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/8/89/Human_brain_in_a_vat.jpg/300px-Human_brain_in_a_vat.jpg" alt="English: a human brain in a jar" /></a></p>
<p>Beyond those considerations, what I think is interesting is that the development of an application it's not just developing it, but also running it in an environment. Even if I can control it, there will always be some parts, for instance an user directory, beyond my control. Those parts will be in someone else's hands. With or without their help, <strong>I'll need to find a way to run the application in their environment, not in my warm and comfy development one.</strong> The production is the only place where the application really exists.</p>
<p>That's why I think it's so important to build load tests, and to mimic production environment, based on my assumptions, but also my learning when deploying and running the application in production. It's different, it has to be managed differently.</p>
<p>For the final words, it makes me think to <a href="https://ibakesoftware.com/blog/developer-the-modern-architect-and-general-contractor/" title="Developer, the modern architect and general contractor">my analogy of the architect and general contractors</a>. The application is built and run. The reality in my mind is not the real one.</p>
Developer, the modern architect and general contractor2012-07-23T00:00:00+00:002012-07-23T00:00:00+00:00https://ibakesoftware.com/blog/developer-the-modern-architect-and-general-contractor/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<h2 id="building-a-new-digital-house">Building a new digital house<a class="zola-anchor" href="#building-a-new-digital-house" aria-label="Anchor link for: building-a-new-digital-house">๐</a></h2>
<p>Developing a new software is like building a new house. You design an ideal plan in your head. The plan consists in realizing a purpose, where each part has its role to play. You even think about it in an aesthetic way. You see its inherent beauty because it fulfills its purpose in a genuine and simple approach that makes totally sense. But when you start to implement it, realize it, build it, the reality punches you back without any warning. Welcome into the real world.</p>
<p>The analogy is very interesting, in my opinion, because it helps non-developers understand why it is so difficult to anticipate the difficulties of implementation. A little disclaimer before I'll develop it. I'm not an <a href="http://en.wikipedia.org/wiki/Architect" title="Architect">architect</a> or <a href="http://en.wikipedia.org/wiki/General_contractor" title="General contractor">general contractor</a> myself. It's then only my personal view. But in a way, it serves my argument because it's very close to a common point of view of the job.</p>
<h2 id="the-architect-s-plan">The architect's plan<a class="zola-anchor" href="#the-architect-s-plan" aria-label="Anchor link for: the-architect-s-plan">๐</a></h2>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/c/c8/Montagu_House_-_plan_from_Vitruvius_Britannicus.jpg/300px-Montagu_House_-_plan_from_Vitruvius_Britannicus.jpg" alt="Montagu House - plan from Vitruvius Britannicus" /></p>
<p>An <strong>architect</strong> should imagine an use of the available space to serve some purpose and by respecting some constraints. Outside money consideration, the available space is defined by the terrain where you can build the house or the building, and the technology that you can use to delimit that volume above this terrain (or below).</p>
<p>Those constructions could have different purposes. It could be a familial house, an open space dedicated to offices of an IT company, a shop, a factory, etc. But this is still a very general purpose, when you go in details, it is split itself in different parts with different goals. Together they form the whole.</p>
<p>The constraints are the money, the technology, the available materials, the availability of skilled workers, the time, the imagination of the architect, and the capacity of the customer to express what he wants (in other words, the capacity of the architect to help the customer to express what he wants).</p>
<h2 id="a-plan-is-not-the-reality">A plan is not the reality<a class="zola-anchor" href="#a-plan-is-not-the-reality" aria-label="Anchor link for: a-plan-is-not-the-reality">๐</a></h2>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/Woodframe-concrete_structure.jpg/300px-Woodframe-concrete_structure.jpg" alt="English: Combined concrete/timber framed structure" /></p>
<p>Even if the architect has a great experience of the implementation of his <strong>plans</strong>, even if he knows the kind of difficulties to face, he cannot totally anticipate the very tiny details that depend on other persons or the environment. Even if he can go really far in the details of the building such as considering the dimensions of <a href="http://en.wikipedia.org/wiki/Hollow-core_slab" title="Hollow-core slab">hollow core slabs</a>, he cannot be sure that at the time of building, they'll be still valid for any reasons (the workers don't place correctly them, the provider has changed them, the engineer has calculated that it's not enough solid). He cannot really manage the whole complexities of the system without building it. He has to be realistic and design a house or whatever the building is in a reasonable time that answers the needs or asks of his customer. He has to understand that the plan won't be exactly implemented as he has drawn it. <strong>A plan is just a plan</strong>. Its goal is to find a good arrangement of rooms according their functions and the will of the customer. Add the tastes above ... and you can understand it's not an easy exercise.</p>
<h2 id="the-surprises-of-the-reality">The surprises of the reality<a class="zola-anchor" href="#the-surprises-of-the-reality" aria-label="Anchor link for: the-surprises-of-the-reality">๐</a></h2>
<p>After different variations and iterations, a final plan is achieved, the construction can start, and the real problems can begin.</p>
<p>The realization will be lead by a <strong>general contractor</strong> and his workers. Maybe some sole proprietorships has to be involved. The materials will be provided by a lot of different providers depending on their nature, the taste of the architect and the customer. The weather could enter in the game. The neighborhood. The city. A provider could do bankrupt, and you have to find another one. This is no more in the mind of one or a few architects. It is in the hands of several dozens of people that have to interact together. Worse, the customer can finally and really understand what the architect has drawn for him, and don't like it โฆ</p>
<h2 id="where-the-analogy-stops">Where the analogy stops<a class="zola-anchor" href="#where-the-analogy-stops" aria-label="Anchor link for: where-the-analogy-stops">๐</a></h2>
<p>I think in a way, it's totally the same in <strong>software development</strong>. At the design stage, you have a general purpose incarnated as the application. The application is formed by different features and functionalities. You have constraints, technological ones, money, time, available skilled people.</p>
<p>The <strong>designer cannot go very far into the details</strong> because it cannot really manage the whole complexities of the system without building it. The reasons are numerous. It could be a question of tools, developers, statement of the problem, team management, available expertise, unknown or hidden technological challenge, etc. At the end, you have to build it to face the problems ... and maybe review or change the plan. You can even do it several times. It's not unfeasible, it's even become a mainstream way to develop software: iterate often, stay agile.</p>
<p>This is the biggest difference between those two worlds. The analogy stops there. Software is a virtual world where you have more <strong>flexibility</strong>. It's easier to unmake or destroy than in the real world. This is an opportunity in terms of productivity and development process that the architect and the general contractor cannot benefit. Imagine if we could apply agile methodology to construction, we could build a first very simple 0.1 version of the house โฆ in two weeks. You can show it to the user, he can experience it, and give you feedback if it corresponds to his needs. You can test some ideas and see if they really work. You will face the problems very early and understand what does it mean in terms of implementation challenge. From those learnings, you can iterate and build a next version โฆ in two another weeks. And test it again.</p>
<p>This is <strong>the true power of software development</strong>, you can build the software and design it nearly in the same time. It gives you in flexibility. Besides, it helps you to really realize what your idea means in terms of real code source to write and run. This is a real opportunity. As software developer, we should take advantage from this difference and not waste it.</p>
Pitching: One year on2012-07-13T00:00:00+00:002012-07-13T00:00:00+00:00https://ibakesoftware.com/blog/pitching-one-year-on/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<p><img src="https://res.cloudinary.com/crunchbase-production/image/upload/c_lpad,h_170,w_170,f_auto,b_white,q_auto:eco,dpr_1/v1501016658/hdw3xgfgjew8yvffpxzc.jpg" alt="Image representing Founder Institute" /></p>
<p>Last Wednesday, I've attended the <a href="http://fi.co/e/1534/blog">Founder Institute Brussels Startup Pitch Bootcamp</a>. The speakers were <a href="http://about.me/FilipTack">Filip Tack</a>, a FI mentor, and <a href="http://be.linkedin.com/in/duboisp">Pieter Dubois</a>, a former FI graduate. It was the occasion to look behind and observe how far Iโve come since my first pitch lesson in June 2011 (which was incidentally also at a FI Bootcamp.</p>
<h2 id="practice-always">Practice, always.<a class="zola-anchor" href="#practice-always" aria-label="Anchor link for: practice-always">๐</a></h2>
<p>Filipโs presentation was similar to the one I've saw last in September 2011. Same advices, same good examples, same honest sharing of personal experiences. But this time, I've listened to him with another ears: "I repeated my pitch all the time, even in my car." I did that, too, as the only way to become good is to <strong>practice, repeat, rehearse, again and again</strong>. You become good by pitching, not by hoping it would happen. The first time I pitched, I was very bad, people didn't understand what I was trying to communicate. Today, I'm still practicing, it's never finished. As Filip said, you're still learning even after 10 years of practice.</p>
<p>That means it's important to repeat often, but also to practice in real conditions. So, anytime I have the opportunity to do it, I pitch, especially if it's not a crucial moment: for instance, with friends, or friendly experienced entrepreneur. It's the opportunity to train my pitch, to try some variations, and to refine it by getting feedback.</p>
<h2 id="get-attention-first-then-ask">Get attention first, then ask.<a class="zola-anchor" href="#get-attention-first-then-ask" aria-label="Anchor link for: get-attention-first-then-ask">๐</a></h2>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/b/bd/Panneau_attention_large.jpg/75px-Panneau_attention_large.jpg" alt="English: Attention" /></p>
<p>As Filip explained, the purpose of pitching is to communicate a message and <strong>getting attention</strong> about it to go one step forward with your interlocutor. <strong>You want to ask</strong> him something. Depending on who, when, and where, it could be simply to get his business card (and if you do well the job, he'll give it to you by himself), to get lunch together, or to give a call.</p>
<p>I pitch when I'm explaining to my family or my friends what I'm doing, when I'm selling, when I'm introducing my project to some organization that could support us, when I'm looking for a loan, when I'm simply meeting someone that wants to know what we're doing. Iโll certainly pitch when Iโll be hiring. It's about communicating my project precisely and concisely with a clear purpose and by respecting some constraints (time, noise environment, location). And when it's especially noisy, I'm doing my best to use simple words, speak slowly and loudly.</p>
<h2 id="you-re-not-pitching-your-product">You're not pitching your product.<a class="zola-anchor" href="#you-re-not-pitching-your-product" aria-label="Anchor link for: you-re-not-pitching-your-product">๐</a></h2>
<p>Because you're the one pitching, <strong>you're the vitrine</strong>, you're pitching yourself, as Pieter has well explained. You want people to remember you and your project, but you're the first and only thing he gets up front. If you seems boring, they will not want to know more: your project will seem boring, not exciting.</p>
<p>For this reason, I've worked a lot on the flow, the tone, and the attitude when pitching. The only way for me to practice this, it's to learn it by heart, and rehearse before a mirror or to record a video. After I'm more confident to improvise and focus on the performance. I don't forget that it's just not acting, I'm really putting me in a mind state where I'm feeling the belief into my project.</p>
<p>When I'm sincere, I'm smiling, I'm really enjoying it, and itโs communicative. In the end, it's all about people.</p>
<h2 id="target-your-audience">Target your audience.<a class="zola-anchor" href="#target-your-audience" aria-label="Anchor link for: target-your-audience">๐</a></h2>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/6/6d/Pitching_motion.jpg/300px-Pitching_motion.jpg" alt="English: The pitching motion of the Quebec Cit..." /></p>
<p>You are not pitching a wall. It's important to not forget your interlocutor, as Filip reminded us. You don't pitch a business angel as you pitch a potential cofounder. You may need to adapt if someone interrupts you with: "ho, it's just like <a href="http://vooza.com/">Vooza</a>". Better, you want to use this information to show you're also listening.</p>
<p>Pitching is not about pitching, <strong>it is about creating a conversation</strong>. It's like when <a href="http://scobleizer.com/2006/07/05/business-card-best-practices/">sharing business cards</a>, it is not about sharing cards, except if you need them to warm your home. The pitch is only the first part of the conversation, so if it starts, do not break it!</p>
<p>That's why after a certain time, I've started to build pitch blocks: small pieces of texts, introductions or sentences that fit a particular audience or circumstance. Those blocks help me to build my pitch on the moment depending on the audience, and how they react or answer me. Again, I test those blocks only by practicing. But it's something I started when I had already pitched a lot, a few months ago, and I had at least one good sentence pitch.</p>
<h2 id="the-fallback-pitch">The fallback pitch.<a class="zola-anchor" href="#the-fallback-pitch" aria-label="Anchor link for: the-fallback-pitch">๐</a></h2>
<p>The one sentence pitch, as the <a href="http://vimeo.com/16447520">very good one Adeo Ressi has designed</a>, is the first version you have to elaborate. It's simple and short, and contains enough information to create interest in most situations even if it's a <a href="http://en.wikipedia.org/wiki/Sales_pitch" title="Sales pitch">sales pitch</a>. It is tried and true, and I know <strong>I can always fall back to it.</strong></p>
<p>For instance, recently I decided to improvise, using a totally new pitch. I've obtained: "Sorry, I don't understand it at all". I've honestly apologized and quickly switched to the one sentence version. The person finally understood it and asked me some interesting questions.</p>
<h2 id="sharpen-your-pitch-and-design-your-business">Sharpen your pitch and design your business.<a class="zola-anchor" href="#sharpen-your-pitch-and-design-your-business" aria-label="Anchor link for: sharpen-your-pitch-and-design-your-business">๐</a></h2>
<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/1/10/Business_Model_Canvas.png/300px-Business_Model_Canvas.png" alt="Business Model Canvas Poster" /></p>
<p>Beyond that, the one sentence pitch is built with all the important parts composing your <a href="http://en.wikipedia.org/wiki/Business_model" title="Business model">business model</a>: the target, the problem, the solution, and your unique value proposition that differentiates you from others. <strong>If you're unable to build a good and coherent one sentence pitch, maybe your business is not clear enough, even for you.</strong> In my honest opinion, it's totally in the philosophy of the <a href="http://en.wikipedia.org/wiki/Nicolas_Boileau-Despr%C3%A9aux" title="Nicolas Boileau-Desprรฉaux">Nicolas Boileau</a>'s quote:</p>
<blockquote>
<p>Whatever is well conceived is clearly said, And the words to say it flow with ease.</p>
</blockquote>
<p>It's really a great tool that I used to test our business model at the beginning and challenging it with peers, advisors, or other mentors. That's why, I've realized, it's important to be concrete and specific, because the pitch is the communication of our business model. It doesn't have to embrace the whole vision, it has to help the interlocutor to get a good representation of the business.</p>
<p>Those are my learnings for this first year of pitching practice. What are yours?</p>
Unconventional Innovator Award2012-06-28T00:00:00+00:002012-06-28T00:00:00+00:00https://ibakesoftware.com/blog/unconventional-innovator-award/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<p>As we told you 3 days ago, Martin has pitched at the <a href="https://web.archive.org/web/20120918012657/http://myeyif.ning.com:80/page/innopitch">InnoPitch Competition</a> with 5 other finalists.</p>
<p><img src="/blog/images/IMG_7295.jpg" alt="Martin on stage" /></p>
<p>We've got interesting questions and feedbacks from the judges, Matthias Ummenhofer (Head of Equity and Risk Finance, European Investment Fund), Anne Glover (Co-founder and CEO of Amadeus Capital Partners), and Carlos Eduardo Espinal (Partner, Seedcamp), but also from the audience. When you're defend your project before people, the things become concrete, it's always a great feeling.</p>
<p>Today was the second and last day of the first Unconvention and the Innopitch winners were announced. The European Young Innovator of the Year 2012 was <a href="http://hu.linkedin.com/pub/tam%C3%A1s-haidegger/5/5a0/560">Tamรกs Haidegger</a> with <a href="http://www.handinscan.com/">Hand In Scan</a>, an easy way to check hand hygiene in medical environment. Honestly, this project is far mature than the others, and it is about health: it can directly saves life. A great innovation.</p>
<p>We <a href="https://twitter.com/EYIF/status/217987112228753408">won the audience unconventional Innovator award</a>.</p>
<p><img src="/blog/images/J8tL.jpg" alt="Unconventional Innovator Award" /></p>
<p>Due to very tight score, a second one was awarded to Wishareit, a social network to buy the perfect gifts.</p>
<p>It was a interesting experience, and it was especially great to be supported by the audience. Thanks to our supporters, it was very nice to meet you. Tomorrow, we'll be back to business and development ... the most important things to make <a href="https://web.archive.org/web/20121218132837/http://asksybil.com:80/index.html">Sybil</a> a success.</p>
Skills Management #4: CSC Belgium case2012-05-29T00:00:00+00:002012-05-29T00:00:00+00:00https://ibakesoftware.com/blog/skills-management-4-csc-belgium-case/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<h2 id="summary">Summary<a class="zola-anchor" href="#summary" aria-label="Anchor link for: summary">๐</a></h2>
<p><a href="http://www.csc.com/be">CSC Belgium</a> provides IT services and custom software development. They make a point to tackle challenges and succeed thanks to the developers they employ. The management of their skills is then a part of their assets.</p>
<h2 id="preliminary">Preliminary<a class="zola-anchor" href="#preliminary" aria-label="Anchor link for: preliminary">๐</a></h2>
<p>We continue to schedule meetings with key people at companies developing software in order to observe and learn how they currently manage the skills of their developers. Three weeks ago, Martin and I went to CSC Belgium to meet Yves Jonckheere, Senior Consultant and coordinator of the development center. Here are some of his insights and challenges in skills management.</p>
<h2 id="csc-belgium">CSC Belgium<a class="zola-anchor" href="#csc-belgium" aria-label="Anchor link for: csc-belgium">๐</a></h2>
<p>Honestly, before meeting its BeLux managing director, <a href="http://be.linkedin.com/pub/philippe-jaeken/0/a9a/586">Philippe Jaeken</a>, we didn't know much about <a href="http://en.wikipedia.org/wiki/Computer_Sciences_Corporation">CSC</a>. We quickly did our homeworks to learn more about them. To summarize, CSC seems as big as IBM from our point of view. On their website, they explain what they do as " <a href="http://www.csc.com/about_us/ds/29505-company_profile">we do amazing things</a>". After reading about the kind of projects they have led, and more so after meeting them, we can believe that. Precisely, CSC Belgium provides customers in the industry and government with solutions crafted to meet their strategic goals and enable them to profit from the advanced use of technology.</p>
<p>Currently, CSC Belgium employs about than 500 persons. They manage several projects in different technologies such as .Net, or Delphi, but their main focus is <a href="http://en.wikipedia.org/wiki/Java_EE">Java EE</a>, that they use in many projects for different customers from federal administrations or ministries to insurances and banks.</p>
<h2 id="developer-profiling-is-not-an-option">Developer profiling is not an option<a class="zola-anchor" href="#developer-profiling-is-not-an-option" aria-label="Anchor link for: developer-profiling-is-not-an-option">๐</a></h2>
<p>When they discuss with their customers, CSC needs to know exactly what the developers can achieve. They even provide the developers' resumes to their customers. But having up to date resumes in not only useful for sales, it is also an intern knowledge base to know who to call when they needs specific expertise.</p>
<p>Practically, a competency manager keeps tracks of the developers' skills and their participation to projects in a database. The tracking is based on their resumes, each person being responsible to keep his own up to date. The competency manager is then a contact point for all project managers needing a specific profile, or specific technical skills.</p>
<p>While the competency manager is in a central position, heโs not the only reference. There are the common de facto hub persons who are there from a long time and a kind of living references. Developers naturally turn to them when they're looking for an expert on some topics.</p>
<h2 id="java-community">Java Community<a class="zola-anchor" href="#java-community" aria-label="Anchor link for: java-community">๐</a></h2>
<p>The human hub is a natural strategy of skills management but it is a kind of single point of failure. That's why CSC has developed an official hub: the Java community. The community allows developers active on very different project (and in different location) to meet with others using the same technology.</p>
<p>The community is composed of the developers themselves. It is led by one developer in charge of the organization of the events, during which developers meet and exchange knowledge. They are usually organized around a few topics presented by the developers. They are also the prefered moments to detect possible synergies between the different projects and teams.</p>
<h2 id="personal-development">Personal Development<a class="zola-anchor" href="#personal-development" aria-label="Anchor link for: personal-development">๐</a></h2>
<p>The community is very adequate to initiate knowledge transfer, but it is not a training program in itself. It doesn't allow a developer to completely develop a new skill. To support the personal development of developers, CSC has put in place a whole strategy composed of training, coaching and assessment.</p>
<h3 id="training">Training<a class="zola-anchor" href="#training" aria-label="Anchor link for: training">๐</a></h3>
<p>Each developer has the freedom to follow a few days of training around the topic of its choice each year, in compliance with a general personal development plan. When some projects require very specific skills, an ad-hoc program is then organized for the developers assigned to those projects.</p>
<h3 id="coaching">Coaching<a class="zola-anchor" href="#coaching" aria-label="Anchor link for: coaching">๐</a></h3>
<p>By CSC, everybody is followed by a coach, a person outside of its direct hierarchy. A coach follows several coachees in a same time. It is a person of reference with whom the coachee can discuss about its personal development or any other topic (technicals or not).</p>
<h3 id="assessment">Assessment<a class="zola-anchor" href="#assessment" aria-label="Anchor link for: assessment">๐</a></h3>
<p>Twice a year, an assessment of the developer work on the project is done by his project manager. The coach get the results of the appraisal, and can then setup with the developer a set of actions to resolve any lack of knowledge (for example by setting up a training plan).</p>
<h2 id="tomorrow">Tomorrow<a class="zola-anchor" href="#tomorrow" aria-label="Anchor link for: tomorrow">๐</a></h2>
<p>CSC wants to develop further their current skills management and provides to their developers a way to keep track of their evolution in order to:</p>
<ul>
<li>increase their learning capacity,</li>
<li>make it easier to keep the resumes up to date</li>
<li>improve their coaching follow-up,</li>
<li>increase the knowledge transfer between the developers, and</li>
<li>improve risk mitigation.</li>
</ul>
<p>Those challenges are totally in the philosophy of the company and its motto, as doing โamazing things" requires investing in skilled and motivated persons.</p>
<p>We would like to extend our thanks to Philippe and Yves for their insights on CSC Belgium skills management.</p>
Just a game2012-04-16T00:00:00+00:002012-04-16T00:00:00+00:00https://ibakesoftware.com/blog/just-a-game/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<p><strong>TL;DR</strong> When you face a problem, don't overthink. Just do it.</p>
<p>During my PhD, I fell several times in <strong>a very annoying spirit, totally messing up my critical thinking and my creativity</strong>. I was unable to progress and go beyond the issues I then faced. My productivity dropped and the caused unproductivity just reinforced this bad spirit. It was a very bad feeling. I was just demoralized, and it could have been worse. It was impossible to progress like that, and I tried to find a solution.</p>
<p>First, I realized the basic reasons behind: <strong>the project became too personal</strong>. It was at a point that I mixed up my personal development with the project achievement . It was not so illogical. I spent most of my time on the project, even having some thoughts running in background during my "free" time. Second, I wasn't alone to experience this: other PhD students, but also simply other persons involved in creation or development. This simply helped me to play down. I just needed to step back, took some distance. But how?</p>
<p>I was and I'm still a frequent player of any kind of games, especially board and video ones. It is usual to experience hard situation, in other words hard to resolve or to win. But well, it is always easier when it is not about real life. Moreover, it's just a game. <strong>I simply enjoyed it and tried to do my best play</strong>. It inspired me. I've tried to do the same with my personal situation. And it worked.</p>
<p>It helps me to step back and take a better perspective on my work. The most important, I've realized that anyway you can experience something bad, it just doesn't help you to prematurely think too much about. At the end of the most of the cases, <strong>the consequences are not so terrible and you've probably learned something by doing it</strong>.</p>
<p>It worked and it still works. As a young startup, we have our own set of questions and challenges, from cash flow to market validation. I see this way of thinking helps: see what you can do, do not delve too much into the multiple possible outcomes and act. I don't overthink the consequences, and I just focus on the problem, considering it as a challenge, a game to resolve. As Yoda said:</p>
<blockquote>
<p><strong>Do ... or do not! There is no try.</strong></p>
</blockquote>
<p>And you, how are you coping with this kind of bad spirit?</p>
<p><strong>Update:</strong> About the same topic, there is a more developed blog post <a href="http://bhorowitz.com/2011/04/01/what%e2%80%99s-the-most-difficult-ceo-skill-managing-your-own-psychology/" title="Whatโs The Most Difficult CEO Skill? Managing Your Own Psychology">Whatโs The Most Difficult CEO Skill? Managing Your Own Psychology</a></p>
Skills management praxis #1: Emakina case2012-01-30T00:00:00+00:002012-01-30T00:00:00+00:00https://ibakesoftware.com/blog/skills-management-praxis-1-emakina-case/
<p><strong>This is an archive of blog post I wrote during my second venture (Sybil).</strong></p>
<h2 id="tl-dr">TL;DR<a class="zola-anchor" href="#tl-dr" aria-label="Anchor link for: tl-dr">๐</a></h2>
<p>Considering the nature of its business demanding a wide range of expertises and a good flexibility, Emakina has specifically set up several strategies of skills management. Those strategies have a clear impact on the organization of the developers and their works and allows to improve the knowledge transfer, the collaboration, and the improvement of each other.</p>
<h2 id="preliminary">Preliminary<a class="zola-anchor" href="#preliminary" aria-label="Anchor link for: preliminary">๐</a></h2>
<p>As you probably know, we will release Sybil, a skill profile search engine dedicated to software companies and department. But a product is nothing if it is not what people really want. That's why we have started to meet key people at software companies in order to observe how they actually manage the skills of their developers and learn. A few weeks ago, Martin an I have met <a href="http://www.brice.org/" title="Brice Le Blรฉvennec">Brice Le Blรฉvennec</a> at <a href="http://emakina.com/" title="Emakina">Emakina</a>. This post presents you how Emakina deals with different use cases related to the management of developers' skills.</p>
<h2 id="emakina">Emakina<a class="zola-anchor" href="#emakina" aria-label="Anchor link for: emakina">๐</a></h2>
<p><a href="http://emakina.com/" title="Emakina">Emakina</a>, an European network of digital agencies, deals with about 1600 projects per year, most of them lasting about two weeks. Those projects are realized by more than 100 developers in very different technologies from .NET, Java, PHP to Unity, Sharepoint, Facebook Apps.</p>
<h2 id="what-are-the-developers-skills">What are the developers' skills?<a class="zola-anchor" href="#what-are-the-developers-skills" aria-label="Anchor link for: what-are-the-developers-skills">๐</a></h2>
<p>This question is usually addressed by project and HR managers:</p>
<ul>
<li>planning managers to decide who to assign to a given project, and</li>
<li>recruitment managers have to evaluate the developers' skills for recruitment or performance assessment.</li>
</ul>
<p>Without close following of the developers, it is hard to keep up to date a directory of developers' skills. Sometimes the only available sources are the developers' resumes, that are updated occasionally and difficult to be understood by people who don't really understand what's behind technological keywords.</p>
<p>By Emakina, the developers are organized in <strong>core teams</strong> defined around a main technology such as PHP/Drupal, .NET/Sharepoint or Java. Each core team is then composed from 10 to 20 developers, project managers and designers.</p>
<p>The <strong>very short development cycle</strong> benefits to the managers that get immediate feedback on their developers' works. If something goes wrong or well, they quickly know it. This information is not lost and allows managers maintaining the developers' profiles especially in terms of skills.</p>
<p>As for development of new skills, Emakina has implemented its own <strong>e-learning</strong> platform: you can learn something new and validate it by passing some quizzes. Each developer can decide how to develop and build his own expertise and manager can know how he's doing well.</p>
<p>The <strong>profile of a developer</strong> is at the end the sum of those different inputs (evaluation by it's manager and team, evaluation by customers of projects on which they contributed, achievements, and new skills) and is used of the annual evaluations. This really creates a reward loop based on real and quite objective assessments allowing the developers to be engaged in a culture of learning, developing and transferring skills.</p>
<h2 id="who-can-help">Who can help?<a class="zola-anchor" href="#who-can-help" aria-label="Anchor link for: who-can-help">๐</a></h2>
<p>One common use case in a development team is to find someone that have the required skills to help you to go through an obstacle and teach you something new. But a developer doesn't necessary think to find someone to help him because of a lack of skills directory or of collaboration and communication culture.</p>
<p>Emakina has setup a combination of different strategies to address this use case: a knowledge management platform, several human hubs, an open space yelling and mailing lists, and some competency centers.</p>
<p>As said previously, developers are organized in core teams around one technology. Those project teams double as <strong>competency centers</strong>. The managers are then responsible of both the project development and the skills management of their developers.</p>
<p>Each competency center has a space on Emakina's <strong>knowledge management platform</strong>, running on Confluence, a rich wiki tool by Atlassian. The technology experts have a mission of contributing and updating best practices, tools, codes snippets, documentation, and learnings on this platform.</p>
<p>Emakina has improved on the " <strong>yelling part</strong>" by setting up mailing lists dedicated to each important technology, allowing developer to exploit the company knowledge on this subject and provide his own expertise in a controlled and non invasive way.</p>
<p>For the strategy of <strong>human hubs</strong>, several have been put in place:</p>
<ul>
<li>coach of newcomer, a senior developer selected to coach a freshly arrived developer;</li>
<li>expert, selected as the reference of a technology and responsible to manage and keep up to date the know-how about this technology; and</li>
<li>the managers of core teams, mentioned in the previous section.</li>
</ul>
<p>When a developer is stuck, he has then a very precise order of contact person to get help:</p>
<ol>
<li>he asks to his coach (if he is a newcomer),</li>
<li>he asks to his neighbors,</li>
<li>he checks the documentation on the knowledge management platform,</li>
<li>he sends an email on the adequate mailing list,</li>
<li>he asks to the expert, or</li>
<li>he finally asks to his manager (who will communicate with other manager to find the good expert).</li>
</ol>
<h2 id="skills-management-is-not-an-option">Skills management is not an option<a class="zola-anchor" href="#skills-management-is-not-an-option" aria-label="Anchor link for: skills-management-is-not-an-option">๐</a></h2>
<p>Two years ago, the developers by Emakina were still organized in heterogeneous pools, one per business unit. That organization couldn't really scale and came with several issues such as bad durability of knowledge or missed synergies. Emakina has then decided to invest in solutions allowing a better management of those skills: building a specific organization and culture to implicitly know the current state of available skills in house, to improve the skills and to capitalize them.</p>
<p>This massive investment in skills management in the form of functions (expert), missions for project managers and even dedicated team (e-learning) seems to be successful, but it is also due to some inherent factors:</p>
<ul>
<li>short cycle development allowing a short feedback loop, and</li>
<li>enough developers to put in place technological leadership.</li>
</ul>
<p>According Brice, the evaluation of the actual level of a skill will be the next challenge to shorten the learning loop and improve the empowerment.</p>
<p><em>We would like to warmly thank Brice for the meeting, the feedbacks, and the review of this post.</em></p>
Startup Weekend Brussels 2: the storm of startups2011-12-09T00:00:00+00:002011-12-09T00:00:00+00:00https://ibakesoftware.com/blog/startup-weekend-brussels-2-the-storm-of-startups/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<p>The Startup Weekend is an 54-hours weekend event during which several persons with different backgrounds form a team around an idea and defend it before a jury the Sunday evening. We have participated to the last one in Brussels on the weekend of the 21st Oct 2011: the <a href="https://web.archive.org/web/20120726053451/http://brussels.startupweekend.org/" title="Startup Weekend Brussels">Startup Weekend Brussels Second Edition</a> (SWBRU). Before the weekend, we did attend to the <a href="https://ibakesoftware.com/blog/running-lean-workshop-by-ash-maurya/">Running Lean Workshop</a> given by <a href="http://www.ashmaurya.com/">Ash Maurya</a>. It was a great and very dense weekend during which we learned a lot and meet many kind and interesting people. I'll discuss what I've learned from SWBRU.</p>
<h2 id="team">Team<a class="zola-anchor" href="#team" aria-label="Anchor link for: team">๐</a></h2>
<p>Without a team, you can't build anything. Even if we were already two, it was not enough. But team work is not easy, especially with people you never met before. Even if SWBRU is full of good spirit, each person has his goal, his way to work or collaborate without forgetting the unexpected such as a disease. We've lost two members the second day: one because of a disease, another because of an incompatibility of goals and way to work. We've finally ended with a good team for Just Delivered: <a href="https://www.linkedin.com/in/martinvanaken">Martin</a>, <a href="/">me</a>, <a href="https://www.linkedin.com/in/nicolas-overloop-ba691b9/">Nicolas Overloop</a> and <a href="https://www.linkedin.com/in/alexmreis/">Alex Reis</a>. It was a great learning to work with people you don't know in a time window so short for an ambitious goal.</p>
<h2 id="cooperation">Cooperation<a class="zola-anchor" href="#cooperation" aria-label="Anchor link for: cooperation">๐</a></h2>
<p>SWBRU is a competition. It's a fact. You can imagine that every participants adopt a competitive behavior, including not helping other competitor teams. It wasn't the case. People collaborate a lot, even if they didn't belong to the same team. I've talked with so many other participants about their project or mine. We have shared a lot, given feedbacks and opinions in order to improve our respective projects. It was probably one of the key point of the SWBRU spirit.</p>
<h2 id="creativity">Creativity<a class="zola-anchor" href="#creativity" aria-label="Anchor link for: creativity">๐</a></h2>
<p>Having an idea is one thing, building a sustainable business from it is another thing entirely. The Business Model Canvas was our support to be creative and improve our business model (it was also a great use case for our Business Model Canvas online editor, bemco). From a home express delivery of Belgian beers, we've pivoted several times to a marketplace allowing people needing a goods home delivery to find people ready to do it. SWBRU is a great sandbox to learn how to build a business model and how to challenge it thanks to a customer development approach.</p>
<h2 id="on-stage">On stage<a class="zola-anchor" href="#on-stage" aria-label="Anchor link for: on-stage">๐</a></h2>
<p>To be creative is not enough, you have also to present and defend your 54-hour project on stage before the jury in 5 minutes. This is not an easy practice. We had a good teamwork session to build a nice and sweet slide deck and to train Nicolas at pitching. Nicolas did a great job and we answered the investors' questions together. Just Delivered was selected as the <a href="https://web.archive.org/web/20120719034856/http://brussels.startupweekend.org:80/2011/10/25/winners-of-startup-weekend-brussels-second-edition/">Leanest Startup Winner</a>. Great reward for all of us, and validations of our learnings.</p>
<h2 id="learnings">Learnings<a class="zola-anchor" href="#learnings" aria-label="Anchor link for: learnings">๐</a></h2>
<p>SWBRU is mainly about learnings thanks to your commitment, other participants, and mentors. Moreover, mentors brought us constructive and tough feedbacks that pushed us to be better and learn more. We've met, notably, <a href="http://www.ashmaurya.com/">Ash Maurya</a>, <a href="http://www.linkedin.com/in/benpiquard">Ben Piquard</a>, <a href="http://www.linkedin.com/in/tjorvendenorme">Tjorven Denorme</a>, <a href="http://be.linkedin.com/in/brunowattenberghbelgium">Bruno Wattenbergh</a>, <a href="http://be.linkedin.com/in/bdelepierre" title="Bruno Delepierre on LinkedIn">Bruno Delepierre</a>, <a href="http://brussels.startupweekend.org/mentors-list/www.linkedin.com/in/sebastiendoyen">Sรฉbastien Doyen</a>, or <a href="http://be.linkedin.com/in/antoineperdaens">Antoine Perdaens</a>. The interaction with them helped us a lot. They brought us their experimented opinions: we had a way to progress.</p>
<h2 id="the-swbru-cocktail-people-smile-creativity">The #SWBRU Cocktail = people + smile + creativity<a class="zola-anchor" href="#the-swbru-cocktail-people-smile-creativity" aria-label="Anchor link for: the-swbru-cocktail-people-smile-creativity">๐</a></h2>
<p>We learned a lot. We met great people among other participants, mentors, organizers, volunteers and jury members. Smiles were one constant of the weekend. I've met people with smiling faces, very kind, open to discuss and listen to you, with sharp feedbacks and creative suggestions.</p>
<p>You don't become a very innovative person from day 1. You not build a very disruptive idea in less than 3 days. You need to work, to learn, to practice, to challenge you, to meet people, to open your mind. You need to experiment and experience! This is what SWBRU allows you to do. Nothing more, nothing less. Some fairy tales could happen, but it is definitively not an end, just a beginning...</p>
Running Lean Workshop by Ash Maurya2011-10-31T00:00:00+00:002011-10-31T00:00:00+00:00https://ibakesoftware.com/blog/running-lean-workshop-by-ash-maurya/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<blockquote>
<p>A systematic process for iterating from Plan A to a plan that works.</p>
<p>Ash Maurya</p>
</blockquote>
<p>I (and Martin) have attended to <a href="http://brussels.startupweekend.org/2011/10/11/lean-startup-workshop-in-brussels-with-ash-maurya/">Running Lean Workshop</a>, before the <a href="http://brussels.startupweekend.org/">Startup Weekend Brussels 2nd edition</a>. I follow <a href="http://www.ashmaurya.com/" title="Practice Trumps Theory">Ash Maurya's blog</a> since a few months, after reading about the existence of the lean startup concept. The contents he usually authors are very useful and precise. For instance, thanks to his post <a href="http://www.ashmaurya.com/2011/08/customer-development-getting-started/" title="The Achilles Heel of Customer Development">"The Achilles Heel of Customer Development"</a>, I've got enough material to start customer interviews. After several ones, I've learned how to refine the way I lead problem interview and how to correctly listen to an user or a customer. Attending a workshop by himself shouldn't be a bad thing. It was a great opportunity. During the workshop, he mainly presented the concept of running lean. He did this with a clear structure, illustration, advices and interactions with the audience. The workshop finished with a practical case coming from one of the attendants, the founder of <a href="http://mobilosoft.com/">mobilosoft</a>. In the following, I'll summarize what I've remembered from and some personal thoughts.</p>
<p>The concept of lean consists in finding a path to a working plan before running out of resources. This methodology allows you to iterate over a business model according to new input collected. Considering some facts, it is not a bad thing to have one to follow: 9 products among 10 fail. But the risk is not in the product but in the market and customers. You have to gather information from there, you have to work there. Otherwise, you're just out of the real world. This is very similar to the <a href="http://en.wikipedia.org/wiki/Effectuation" title="Effectuation">effectuation concept</a>. This concept states that successful entrepreneurs adopt the same kind of approach to build a business: you find a path from a starting point defined by who you are, who you can reach and what you have. The path is then mean driven and lead to a goal you don't necessary know in advance. It is then built thanks to interactions with the market and the customers, in another words the real world.</p>
<p>Running lean is defined by Ash as the composition of three other methodologies:</p>
<ol>
<li>Customer Development by<a href="http://steveblank.com/">Steve Blank</a>: get out of the building.</li>
<li><a href="http://en.wikipedia.org/wiki/Lean_Startup">Lean Startup</a> by <a href="http://www.startuplessonslearned.com/">Eric Ries</a>: iterate enough before out of money, a mix between Agile project management, Extreme Programming and Lean Production management.</li>
<li><a href="http://en.wikipedia.org/wiki/Bootstrapping#Business">Bootstrapping</a> by <a href="http://bijoygoswami.com/">Bijoy Goswami</a>: right action, right time.</li>
</ol>
<blockquote>
<p>Your product is not the product, it is the business model.</p>
<p>Ash Maurya</p>
</blockquote>
<p>The business model is a description of your current plan. But how to represent it without writing a whole business plan? You can use the Business Model Canvas (and edit online thanks to <a href="https://ibakesoftware.com/blog/bemco-launched/">Bemco</a>) or a Ash's variation, the <a href="http://leancanvas.com/">Lean Canvas</a>. In order to follow him during the workshop, Ash gave us an access to his web online editor of <a href="http://leancanvas.com/">Lean Canvas</a>.</p>
<p>The methodology of Running Lean could be summarized as following:</p>
<ol>
<li>define an initial set of several variations of a business model</li>
<li>skim some of them according your priority</li>
<li>test the risk with customers interviews, A/B testing, marketing experiment, prototyping</li>
<li>remove variations according tests</li>
<li>halt if everything is validated or go back to 3.</li>
<li>select the best one</li>
</ol>
<p>You can then apply your working plan in a given market segment, and growth. It is very important to validate learning before growing. Otherwise, you will grow on bad foundations. What is very interesting, in my opinion, is the way to test and validate. As a former scientist, it is very familiar. You formulate testable hypothesis, and you run an experiment to reject or accept it. In case of acceptation, you have validated your learning. For instance, is my blog a good channel to lead people to my product B? You can formulate this by testing if you get more than 20 new visitors from your blog on your product landing page after having talked about it on your blog.</p>
<p>I do not go deeper in the topic and invite you to watch the workshop video "Running Lean Workshop with Ash Maurya at Beta Cowork"</p>
<div >
<iframe src="https://www.youtube-nocookie.com/embed/o95AQfTcvls" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div>
<p>or to read his <a href="http://www.runningleanhq.com/" title="Running Lean">book "Running Lean</a>". It was an interesting learning for me and an opportunity to meet Ash, a calm and kind person with sharp advices and interesting experiences. If you can attend to one of his workshops, do it.</p>
Bemco launched2011-10-21T00:00:00+00:002011-10-21T00:00:00+00:00https://ibakesoftware.com/blog/bemco-launched/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<p>Some weeks ago, we wrote here that we were working on Bemco, <a href="https://ibakesoftware.com/blog/a-first-product/">an online editor of Business Model Canvas</a>. We needed it one and still need it. We thought other people would like one also. We've decided to make it. After two weeks of development and two of beta, it's time for us to launch Bemco in the wild. But before please watch our new improved screen cast made by White 7, with some minor changes we're quite proud of.</p>
<div >
<iframe src="https://www.youtube-nocookie.com/embed/wRS8tHt16KE" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
</div>
<p>Bemco is delivered "as-is", and is free. Should you find it useful, or got ideas that would make it better, let us now. We do got some, but we want to hear the user's voice. And for the impatient, go on Bemco and use it.</p>
Gamification by design ... really?2011-10-10T00:00:00+00:002011-10-10T00:00:00+00:00https://ibakesoftware.com/blog/gamification-by-design-really/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<p>I've bought the book <strong><a href="http://gamificationbydesign.com/" title="Gamification by design">Gamification by design</a></strong> authored by Gabe Zichermann and Christopher Cunningham thanks to a daily deal of O'Reilly. The deal consisted in an early release of the book and the videos <a href="http://shop.oreilly.com/product/0636920017622.do" title="Gamification Master Class">Gamification Master Class</a>. I like games, notably board, role playing and video ones. I am interested in game mechanics, especially for role playing games. I was naturally curious to learn about this new buzzy, trendy topic: <a href="http://en.wikipedia.org/wiki/Gamification" title="Gamificaiton">Gamification</a>. It smells like serious games but with more background. I wanted to make my own opinion. So, I bought it.</p>
<p>In the following, I'll not talk a lot about the topic - perhaps I will in a future post - but about the book and the videos. It is a simple review from a neophyte. If you want reviews made by experts, please check <a href="http://blog.habitlabs.com/post/10490680475/gamification-by-design" title="Response to Gabe and Sebastianโs #gamification discussion">this post listing several reviews, debates and discussions - even by Gabe himself</a>.</p>
<p>I've started with the <strong>videos</strong>. I've enjoyed them a lot. Gabe is a good teacher and the course is very well structured with many examples and exercises. The whole course is divided in fourteen chapters from basics to some technical considerations, by explaining deeper some classic game mechanics. The exercises are simple and allow you to get the principles Gabe exposes. But Gabe doesn't teach you a true methodology to design gamification in your application, i.e. the engagement of users and how to resolve problems by using game mechanics. It's true that you can include all those mechanics in your application. But what you have, in my honest opinion, is just a bunch of technics. You can replicate them and mimic some gamification, but it is not a true design. I mean you have no plan, convention, or methodology to build a gamified system and resolve engagement issues such as user conversion or participation. Gabe only gives you some tips, ideas, concepts, and technics, but no abstract approach to effectively and objectively build the gamification. I then thought it was an introductory course, a very great one. I hoped that the book would give me the answers I waited.</p>
<p>The <strong>book</strong> is composed of eight chapters, about 150 pages in total. Well, enough pages to go in details. But the first fifth chapters deal with all the topics presented in the videos. Sometimes, it is exactly the same content and structure. It was very boring to read again what I've watched before, especially with no real additional and worthy information. After you read those chapters, you have some good idea what Gabe means by gamification. You can even list some technics allowing to resolve some specific issues and illustrate them. But the design in itself is still not explained. When I reached the sixth chapter, after more than a half of the book, the title <em>Gamification Case Studies</em> let me believe the design will be finally tackled. But the chapter only presents and details several real world cases thanks to the concepts and technics presented in the previous chapters. I still read until the seventh chapter. I was champing at the bit. The seventh and eighth chapters have titles beginning with the word " <em>Tutorial</em>". Probably, the good ones to talk about design. But it is not. Those chapters talk about programming and how to implement specific technics. I was very disappointed. The book doesn't really talk about design.</p>
<p>As I said above, I mean by <strong>design</strong> a method, a way to build a given system. Software architects design softwares thanks to</p>
<ul>
<li><strong>concepts</strong>: abstraction, modularity, data structure</li>
<li><strong>considerations</strong>: availability, security, robustness</li>
<li><strong>language</strong>: UML, flowchart</li>
<li><strong>patterns</strong>: common way to resolve specific problem</li>
</ul>
<p>But there are just design blocks. It is not enough. Software achitects <strong>can design</strong> a software thanks to a methodology that describes the software life cycle, i.e. how and when the design occurs and interacts with other development steps. When I've finished this book, I have some concepts, some considerations, and nearly some patterns. But I have no clue how to proceed, which plan to follow, what to measure or to test, where I can begin, or how to exactly state the problem.</p>
<p>As <strong>conclusion</strong>, it is a good book introducing the gamification, and some of the theories behind. It gives you the elements to study farther this field, and allows you to build your own opinion about it. That's all. Maybe the field is too young and not yet well defined enough to talk about design. I don't know. <em>But it's definitively not a book about design</em>.</p>
A first product2011-09-20T00:00:00+00:002011-09-20T00:00:00+00:00https://ibakesoftware.com/blog/a-first-product/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<p>When you start your first venture, you spend a lot of time to eat and digest a lot of new knowledge. It's necessary, but it's not enough if you don't <a href="http://gettingreal.37signals.com/" title="Getting real">get real</a>. Me and Martin are strongly convinced that learning is actually done by doing and failing. That's why we've decided to quickly launch a first product. But what product? We've picked one idea among the several ones we have around the same problem theme 8th color addresses.</p>
<p>The idea is one of the simplest we got, and one that we need ourselves. It is an <strong>online and collaborative web editor to design</strong> Business Model Canvas.</p>
<p>Not yet ready, we just <strong>tease the product today</strong>: take a look at <strong>Bemco</strong>.</p>
<p><img src="/blog/images/bmc_freemium.png" alt="Bemco screenshot" /></p>
<p><strong>If</strong>:</p>
<ul>
<li>you are interested in it, submit your email on <strong>Bemco</strong>.</li>
<li>you have some comments about it, share them.</li>
<li>you want to participate to a beta, tell us.</li>
</ul>
<p>Thanks for reading us, we hope to hear from you.</p>
Nested resources with independent views in Ruby on Rails2011-08-30T00:00:00+00:002011-08-30T00:00:00+00:00https://ibakesoftware.com/blog/nested-resources-with-independent-views-in-ruby-on-rails/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<h2 id="introduction">Introduction<a class="zola-anchor" href="#introduction" aria-label="Anchor link for: introduction">๐</a></h2>
<p>In <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer" title="Representational State Transfer">REST-style architecture</a> , a <a href="http://tomayko.com/writings/rest-to-my-wife" title="Explain REST to my wife"><em>resource</em></a> is simply a source of information, the one you want to expose. The resource is referenced thanks to a global identifier such as an <a href="http://en.wikipedia.org/wiki/Uniform_Resource_Identifier" title="Uniform Resource Identifier">URI</a>.</p>
<p>For example, in our own <a href="https://web.archive.org/web/20150906222250/https://www.pullreview.com/" title="PullReview">PullReview</a>, Code Reviews and Users are resources with their related routes and actions.</p>
<p>When you deal with information structure such as composition, you'll use nested resources. The reference of the embedded resource is then built over the reference of the composite resource.</p>
<p>Ruby on Rails allows you to set up nested resources. For instance in the <a href="http://guides.rubyonrails.org/getting_started.html" title="Getting started guide">"Getting started" guide</a> where you build a very simple blog, Post and Comment are nested resources. Indeed, it is impossible to consider a lone comment without any post. A Comment <em>belongs to a Post</em>. Resources being referenced by URIs, the setup of nested resources in RoR is done through routing as following:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>resources </span><span style="color:#a3be8c;">:posts </span><span style="color:#b48ead;">do
</span><span> resources </span><span style="color:#a3be8c;">:comments
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>But in the <a href="http://guides.rubyonrails.org/getting_started.html" title="Getting Started guide">example of the guide</a>, a Comment hasn't got its own view. A Comment is managed through the views of its Post. It's totaly suited to a blog, but in another case, maybe you would like to program nested resources with independant views, i.e. each resource has their views. This is the goal of this tutorial. I start from the same blog example, but this time I'll generate scaffolds for both models, Post and Comment.</p>
<h2 id="same-first-steps-post-model">Same first steps: Post model<a class="zola-anchor" href="#same-first-steps-post-model" aria-label="Anchor link for: same-first-steps-post-model">๐</a></h2>
<p>First, create the blog application:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">rails</span><span> new blog
</span><span style="color:#96b5b4;">cd</span><span> blog
</span></code></pre>
<p>Generate a scaffolded Post resource:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">rails</span><span> generate scaffold Post name:string title:string content:text
</span></code></pre>
<p>Add some validation to it (app/models/post.rb):</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>
</span><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Post </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">ActiveRecord::Base
</span><span> validates </span><span style="color:#a3be8c;">:name</span><span>, </span><span style="color:#a3be8c;">:presence </span><span>=> </span><span style="color:#d08770;">true
</span><span> validates </span><span style="color:#a3be8c;">:title</span><span>, </span><span style="color:#a3be8c;">:presence </span><span>=> </span><span style="color:#d08770;">true</span><span>, </span><span style="color:#a3be8c;">:length </span><span>=> { </span><span style="color:#a3be8c;">:minimum </span><span>=> </span><span style="color:#d08770;">5 </span><span>}
</span><span style="color:#b48ead;">end
</span><span>
</span></code></pre>
<p>Until now, it's totally the same than in the <a href="http://guides.rubyonrails.org/getting_started.html" title="Getting Started guide">guide</a>. The next step starts the fork!</p>
<h2 id="fork-comment-model">Fork: Comment Model<a class="zola-anchor" href="#fork-comment-model" aria-label="Anchor link for: fork-comment-model">๐</a></h2>
<p>Generate a scaffolded Comment resource:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>rails generate scaffold </span><span style="color:#bf616a;">Comment </span><span style="color:#a3be8c;">commenter:</span><span>string </span><span style="color:#a3be8c;">body:</span><span>text </span><span style="color:#a3be8c;">post:</span><span>references
</span></code></pre>
<p>Edit the app/models/post.rb file to add the other side of the association:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Post </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">ActiveRecord::Base
</span><span> validates </span><span style="color:#a3be8c;">:name</span><span>, </span><span style="color:#a3be8c;">:presence </span><span>=> </span><span style="color:#d08770;">true
</span><span> validates </span><span style="color:#a3be8c;">:title</span><span>, </span><span style="color:#a3be8c;">:presence </span><span>=> </span><span style="color:#d08770;">true</span><span>, </span><span style="color:#a3be8c;">:length </span><span>=> { </span><span style="color:#a3be8c;">:minimum </span><span>=> </span><span style="color:#d08770;">5 </span><span>}
</span><span>
</span><span> has\_many </span><span style="color:#a3be8c;">:comments
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>Setup nested resources (config/routes.rb):</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>resources </span><span style="color:#a3be8c;">:posts </span><span style="color:#b48ead;">do
</span><span> resources </span><span style="color:#a3be8c;">:comments
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>Add some validations to the Comment resource (app/models/comment.rb):</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">Comment </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">ActiveRecord::Base
</span><span> validates </span><span style="color:#a3be8c;">:commenter</span><span>, </span><span style="color:#a3be8c;">:presence </span><span>=> </span><span style="color:#d08770;">true
</span><span> validates </span><span style="color:#a3be8c;">:body</span><span>, </span><span style="color:#a3be8c;">:presence </span><span>=> </span><span style="color:#d08770;">true
</span><span>
</span><span> belongs\_to </span><span style="color:#a3be8c;">:post
</span><span style="color:#b48ead;">end
</span></code></pre>
<h3 id="comment-controller">Comment controller<a class="zola-anchor" href="#comment-controller" aria-label="Anchor link for: comment-controller">๐</a></h3>
<p>Edit the Comment controller app/controllers/comments_controller.rb:</p>
<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span style="color:#b48ead;">class </span><span style="color:#ebcb8b;">CommentsController </span><span style="color:#eff1f5;">< </span><span style="color:#a3be8c;">ApplicationController
</span><span> </span><span style="color:#65737e;"># GET /posts/:post\_id/comments
</span><span> </span><span style="color:#65737e;"># GET /posts/:post\_id/comments.xml
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">index
</span><span> </span><span style="color:#65737e;">#1st you retrieve the post thanks to params[:post\_id]
</span><span> post = </span><span style="color:#ebcb8b;">Post</span><span>.find(params[</span><span style="color:#a3be8c;">:post</span><span>\_id])
</span><span> </span><span style="color:#65737e;">#2nd you get all the comments of this post
</span><span> @</span><span style="color:#bf616a;">comments </span><span>= post.comments
</span><span>
</span><span> respond\_to </span><span style="color:#b48ead;">do</span><span> \|</span><span style="color:#96b5b4;">format</span><span>\|
</span><span> </span><span style="color:#96b5b4;">format</span><span>.html </span><span style="color:#65737e;"># index.html.erb
</span><span> </span><span style="color:#96b5b4;">format</span><span>.xml { render </span><span style="color:#a3be8c;">:xml </span><span>=> @</span><span style="color:#bf616a;">comments </span><span>}
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#65737e;"># GET /posts/:post\_id/comments/:id
</span><span> </span><span style="color:#65737e;"># GET /comments/:id.xml
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">show
</span><span> </span><span style="color:#65737e;">#1st you retrieve the post thanks to params[:post\_id]
</span><span> post = </span><span style="color:#ebcb8b;">Post</span><span>.find(params[</span><span style="color:#a3be8c;">:post</span><span>\_id])
</span><span> </span><span style="color:#65737e;">#2nd you retrieve the comment thanks to params[:id]
</span><span> @</span><span style="color:#bf616a;">comment </span><span>= post.comments.find(params[</span><span style="color:#a3be8c;">:id</span><span>])
</span><span>
</span><span> respond\_to </span><span style="color:#b48ead;">do</span><span> \|</span><span style="color:#96b5b4;">format</span><span>\|
</span><span> </span><span style="color:#96b5b4;">format</span><span>.html </span><span style="color:#65737e;"># show.html.erb
</span><span> </span><span style="color:#96b5b4;">format</span><span>.xml { render </span><span style="color:#a3be8c;">:xml </span><span>=> @</span><span style="color:#bf616a;">comment </span><span>}
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#65737e;"># GET /posts/:post\_id/comments/new
</span><span> </span><span style="color:#65737e;"># GET /posts/:post\_id/comments/new.xml
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">new
</span><span> </span><span style="color:#65737e;">#1st you retrieve the post thanks to params[:post\_id]
</span><span> post = </span><span style="color:#ebcb8b;">Post</span><span>.find(params[</span><span style="color:#a3be8c;">:post</span><span>\_id])
</span><span> </span><span style="color:#65737e;">#2nd you build a new one
</span><span> @</span><span style="color:#bf616a;">comment </span><span>= post.comments.build
</span><span>
</span><span> respond\_to </span><span style="color:#b48ead;">do</span><span> \|</span><span style="color:#96b5b4;">format</span><span>\|
</span><span> </span><span style="color:#96b5b4;">format</span><span>.html </span><span style="color:#65737e;"># new.html.erb
</span><span> </span><span style="color:#96b5b4;">format</span><span>.xml { render </span><span style="color:#a3be8c;">:xml </span><span>=> @</span><span style="color:#bf616a;">comment </span><span>}
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#65737e;"># GET /posts/:post\_id/comments/:id/edit
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">edit
</span><span> </span><span style="color:#65737e;">#1st you retrieve the post thanks to params[:post\_id]
</span><span> post = </span><span style="color:#ebcb8b;">Post</span><span>.find(params[</span><span style="color:#a3be8c;">:post</span><span>\_id])
</span><span> </span><span style="color:#65737e;">#2nd you retrieve the comment thanks to params[:id]
</span><span> @</span><span style="color:#bf616a;">comment </span><span>= post.comments.find(params[</span><span style="color:#a3be8c;">:id</span><span>])
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#65737e;"># POST /posts/:post\_id/comments
</span><span> </span><span style="color:#65737e;"># POST /posts/:post\_id/comments.xml
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">create
</span><span> </span><span style="color:#65737e;">#1st you retrieve the post thanks to params[:post\_id]
</span><span> post = </span><span style="color:#ebcb8b;">Post</span><span>.find(params[</span><span style="color:#a3be8c;">:post</span><span>\_id])
</span><span> </span><span style="color:#65737e;">#2nd you create the comment with arguments in params[:comment]
</span><span> @</span><span style="color:#bf616a;">comment </span><span>= post.comments.create(params[</span><span style="color:#a3be8c;">:comment</span><span>])
</span><span>
</span><span> respond\_to </span><span style="color:#b48ead;">do</span><span> \|</span><span style="color:#96b5b4;">format</span><span>\|
</span><span> </span><span style="color:#b48ead;">if </span><span>@</span><span style="color:#bf616a;">comment</span><span>.save
</span><span> </span><span style="color:#65737e;">#1st argument of redirect\_to is an array, in order to build the correct route to the nested resource comment
</span><span> </span><span style="color:#96b5b4;">format</span><span>.html { redirect\_to([@</span><span style="color:#bf616a;">comment</span><span>.post, @</span><span style="color:#bf616a;">comment</span><span>], </span><span style="color:#a3be8c;">:notice </span><span>=> '</span><span style="color:#a3be8c;">Comment was successfully created.</span><span>') }
</span><span> </span><span style="color:#65737e;">#the key :location is associated to an array in order to build the correct route to the nested resource comment
</span><span> </span><span style="color:#96b5b4;">format</span><span>.xml { render </span><span style="color:#a3be8c;">:xml </span><span>=> @</span><span style="color:#bf616a;">comment</span><span>, </span><span style="color:#a3be8c;">:status </span><span>=> </span><span style="color:#a3be8c;">:created</span><span>, </span><span style="color:#a3be8c;">:location </span><span>=> [@</span><span style="color:#bf616a;">comment</span><span>.post, @</span><span style="color:#bf616a;">comment</span><span>] }
</span><span> </span><span style="color:#b48ead;">else
</span><span> </span><span style="color:#96b5b4;">format</span><span>.html { render </span><span style="color:#a3be8c;">:action </span><span>=> "</span><span style="color:#a3be8c;">new</span><span>" }
</span><span> </span><span style="color:#96b5b4;">format</span><span>.xml { render </span><span style="color:#a3be8c;">:xml </span><span>=> @</span><span style="color:#bf616a;">comment</span><span>.errors, </span><span style="color:#a3be8c;">:status </span><span>=> </span><span style="color:#a3be8c;">:unprocessable</span><span>\_entity }
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#65737e;"># PUT /posts/:post\_id/comments/:id
</span><span> </span><span style="color:#65737e;"># PUT /posts/:post\_id/comments/:id.xml
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">update
</span><span> </span><span style="color:#65737e;">#1st you retrieve the post thanks to params[:post\_id]
</span><span> post = </span><span style="color:#ebcb8b;">Post</span><span>.find(params[</span><span style="color:#a3be8c;">:post</span><span>\_id])
</span><span> </span><span style="color:#65737e;">#2nd you retrieve the comment thanks to params[:id]
</span><span> @</span><span style="color:#bf616a;">comment </span><span>= post.comments.find(params[</span><span style="color:#a3be8c;">:id</span><span>])
</span><span>
</span><span> respond\_to </span><span style="color:#b48ead;">do</span><span> \|</span><span style="color:#96b5b4;">format</span><span>\|
</span><span> </span><span style="color:#b48ead;">if </span><span>@</span><span style="color:#bf616a;">comment</span><span>.update\_attributes(params[</span><span style="color:#a3be8c;">:comment</span><span>])
</span><span> </span><span style="color:#65737e;">#1st argument of redirect\_to is an array, in order to build the correct route to the nested resource comment
</span><span> </span><span style="color:#96b5b4;">format</span><span>.html { redirect\_to([@</span><span style="color:#bf616a;">comment</span><span>.post, @</span><span style="color:#bf616a;">comment</span><span>], </span><span style="color:#a3be8c;">:notice </span><span>=> '</span><span style="color:#a3be8c;">Comment was successfully updated.</span><span>') }
</span><span> </span><span style="color:#96b5b4;">format</span><span>.xml { head </span><span style="color:#a3be8c;">:ok </span><span>}
</span><span> </span><span style="color:#b48ead;">else
</span><span> </span><span style="color:#96b5b4;">format</span><span>.html { render </span><span style="color:#a3be8c;">:action </span><span>=> "</span><span style="color:#a3be8c;">edit</span><span>" }
</span><span> </span><span style="color:#96b5b4;">format</span><span>.xml { render </span><span style="color:#a3be8c;">:xml </span><span>=> @</span><span style="color:#bf616a;">comment</span><span>.errors, </span><span style="color:#a3be8c;">:status </span><span>=> </span><span style="color:#a3be8c;">:unprocessable</span><span>\_entity }
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span>
</span><span> </span><span style="color:#65737e;"># DELETE /posts/:post\_id/comments/1
</span><span> </span><span style="color:#65737e;"># DELETE /posts/:post\_id/comments/1.xml
</span><span> </span><span style="color:#b48ead;">def </span><span style="color:#8fa1b3;">destroy
</span><span> </span><span style="color:#65737e;">#1st you retrieve the post thanks to params[:post\_id]
</span><span> post = </span><span style="color:#ebcb8b;">Post</span><span>.find(params[</span><span style="color:#a3be8c;">:post</span><span>\_id])
</span><span> </span><span style="color:#65737e;">#2nd you retrieve the comment thanks to params[:id]
</span><span> @</span><span style="color:#bf616a;">comment </span><span>= post.comments.find(params[</span><span style="color:#a3be8c;">:id</span><span>])
</span><span> @</span><span style="color:#bf616a;">comment</span><span>.destroy
</span><span>
</span><span> respond\_to </span><span style="color:#b48ead;">do</span><span> \|</span><span style="color:#96b5b4;">format</span><span>\|
</span><span> </span><span style="color:#65737e;">#1st argument reference the path /posts/:post\_id/comments/
</span><span> </span><span style="color:#96b5b4;">format</span><span>.html { redirect\_to(post\_comments\_url) }
</span><span> </span><span style="color:#96b5b4;">format</span><span>.xml { head </span><span style="color:#a3be8c;">:ok </span><span>}
</span><span> </span><span style="color:#b48ead;">end
</span><span> </span><span style="color:#b48ead;">end
</span><span style="color:#b48ead;">end
</span></code></pre>
<p>The important changes are the following:</p>
<ul>
<li>Retrieve a Comment<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>post = </span><span style="color:#ebcb8b;">Post</span><span>.find(params[</span><span style="color:#a3be8c;">:post</span><span>\_id])
</span><span>@</span><span style="color:#bf616a;">comment </span><span>= post.comments.find(params[</span><span style="color:#a3be8c;">:id</span><span>])
</span></code></pre>
</li>
<li>Retrieve all Comments<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>post = </span><span style="color:#ebcb8b;">Post</span><span>.find(params[</span><span style="color:#a3be8c;">:post</span><span>\_id])
</span><span>@</span><span style="color:#bf616a;">comments </span><span>= post.comments
</span></code></pre>
</li>
<li>Building of a new Comment<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>post = </span><span style="color:#ebcb8b;">Post</span><span>.find(params[</span><span style="color:#a3be8c;">:post</span><span>\_id])
</span><span>@</span><span style="color:#bf616a;">comment </span><span>= post.comments.build
</span></code></pre>
</li>
<li>Creation of a new Comment<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>post = </span><span style="color:#ebcb8b;">Post</span><span>.find(params[</span><span style="color:#a3be8c;">:post</span><span>\_id])
</span><span>@</span><span style="color:#bf616a;">comment </span><span>= post.comments.create(params[</span><span style="color:#a3be8c;">:comment</span><span>])
</span></code></pre>
</li>
<li>Redirection to the Comment resource<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>redirect\_to([@</span><span style="color:#bf616a;">comment</span><span>.post, @</span><span style="color:#bf616a;">comment</span><span>], </span><span style="color:#a3be8c;">:notice </span><span>=> '</span><span style="color:#a3be8c;">Comment was successfully created.</span><span>')
</span></code></pre>
</li>
<li>Redirection to the list of Comments<pre data-lang="ruby" style="background-color:#2b303b;color:#c0c5ce;" class="language-ruby "><code class="language-ruby" data-lang="ruby"><span>redirect\_to(post\_comments\_url)
</span></code></pre>
</li>
</ul>
<h2 id="comment-views">Comment Views<a class="zola-anchor" href="#comment-views" aria-label="Anchor link for: comment-views">๐</a></h2>
<p>Edit the views app/views/comments/:</p>
<ul>
<li><code>form.html.erb</code>: remove the <code>:post</code> member<pre data-lang="erb" style="background-color:#2b303b;color:#c0c5ce;" class="language-erb "><code class="language-erb" data-lang="erb"><span style="color:#ab7967;"><%=</span><span> form\_for([@</span><span style="color:#bf616a;">comment</span><span>.post, @</span><span style="color:#bf616a;">comment</span><span>]) </span><span style="color:#b48ead;">do</span><span> \|f\| </span><span style="color:#ab7967;">%>
</span><span> </span><span style="color:#ab7967;"><% </span><span style="color:#b48ead;">if </span><span>@</span><span style="color:#bf616a;">comment</span><span>.errors.any? </span><span style="color:#ab7967;">%>
</span><span> ## </span><span style="color:#ab7967;"><%=</span><span> pluralize(@</span><span style="color:#bf616a;">comment</span><span>.errors.count, "</span><span style="color:#a3be8c;">error</span><span>") </span><span style="color:#ab7967;">%></span><span> prohibited this comment from being saved:
</span><span> </span><span style="color:#ab7967;"><% </span><span>@</span><span style="color:#bf616a;">comment</span><span>.errors.full\_messages.each </span><span style="color:#b48ead;">do</span><span> \|msg\| </span><span style="color:#ab7967;">%>
</span><span> </span><span style="color:#ab7967;"><%=</span><span> msg </span><span style="color:#ab7967;">%>
</span><span> </span><span style="color:#ab7967;"><% </span><span style="color:#b48ead;">end </span><span style="color:#ab7967;">%>
</span><span> </span><span style="color:#ab7967;"><% </span><span style="color:#b48ead;">end </span><span style="color:#ab7967;">%>
</span><span>
</span><span> </span><span style="color:#ab7967;"><%=</span><span> f.label </span><span style="color:#a3be8c;">:commenter </span><span style="color:#ab7967;">%>
</span><span> </span><span style="color:#ab7967;"><%=</span><span> f.text\_field </span><span style="color:#a3be8c;">:commenter </span><span style="color:#ab7967;">%>
</span><span> </span><span style="color:#ab7967;"><%=</span><span> f.label </span><span style="color:#a3be8c;">:body </span><span style="color:#ab7967;">%>
</span><span> </span><span style="color:#ab7967;"><%=</span><span> f.text\_area </span><span style="color:#a3be8c;">:body </span><span style="color:#ab7967;">%>
</span><span> </span><span style="color:#ab7967;"><%=</span><span> f.submit </span><span style="color:#ab7967;">%>
</span><span style="color:#ab7967;"><% </span><span style="color:#b48ead;">end </span><span style="color:#ab7967;">%>
</span></code></pre>
</li>
<li><code>edit.html.erb</code>: update link<pre data-lang="erb" style="background-color:#2b303b;color:#c0c5ce;" class="language-erb "><code class="language-erb" data-lang="erb"><span># Editing comment
</span><span style="color:#ab7967;"><%= </span><span style="color:#96b5b4;">render </span><span>'</span><span style="color:#a3be8c;">form</span><span>' </span><span style="color:#ab7967;">%>
</span><span style="color:#ab7967;"><%=</span><span> link\_to '</span><span style="color:#a3be8c;">Show</span><span>', [@</span><span style="color:#bf616a;">comment</span><span>.post, @</span><span style="color:#bf616a;">comment</span><span>] </span><span style="color:#ab7967;">%></span><span> \|
</span><span style="color:#ab7967;"><%=</span><span> link\_to '</span><span style="color:#a3be8c;">Back</span><span>', post\_comments\_path(@</span><span style="color:#bf616a;">comment</span><span>.post) </span><span style="color:#ab7967;">%>
</span></code></pre>
</li>
<li><code>index.html.erb</code>: remove <code>:post</code> member and update link<pre data-lang="erb" style="background-color:#2b303b;color:#c0c5ce;" class="language-erb "><code class="language-erb" data-lang="erb"><span># Listing comments
</span><span style="color:#ab7967;"><% </span><span>@</span><span style="color:#bf616a;">comments</span><span>.each </span><span style="color:#b48ead;">do</span><span> \|comment\| </span><span style="color:#ab7967;">%>
</span><span style="color:#ab7967;"><% </span><span style="color:#b48ead;">end </span><span style="color:#ab7967;">%>
</span><span>
</span><span>CommenterBodyPost</span><span style="color:#ab7967;"><%=</span><span> comment.commenter </span><span style="color:#ab7967;">%><%=</span><span> comment.body </span><span style="color:#ab7967;">%><%=</span><span> link\_to '</span><span style="color:#a3be8c;">Show</span><span>', [comment.post, comment] </span><span style="color:#ab7967;">%><%=</span><span> link\_to '</span><span style="color:#a3be8c;">Edit</span><span>', edit\_post\_comment\_path(comment.post, comment)</span><span style="color:#ab7967;">%><%=</span><span> link\_to '</span><span style="color:#a3be8c;">Destroy</span><span>', [comment.post, comment], </span><span style="color:#a3be8c;">:confirm </span><span>=> '</span><span style="color:#a3be8c;">Are you sure?</span><span>', </span><span style="color:#a3be8c;">:method </span><span>=> </span><span style="color:#a3be8c;">:delete </span><span style="color:#ab7967;">%>
</span><span>
</span><span style="color:#ab7967;"><%=</span><span> link\_to '</span><span style="color:#a3be8c;">New Comment</span><span>', </span><span style="color:#8fa1b3;">new</span><span>\_post\_comment\_path </span><span style="color:#ab7967;">%>
</span></code></pre>
</li>
<li><code>new.html.erb</code>: update link<pre data-lang="erb" style="background-color:#2b303b;color:#c0c5ce;" class="language-erb "><code class="language-erb" data-lang="erb"><span># New comment
</span><span style="color:#ab7967;"><%= </span><span style="color:#96b5b4;">render </span><span>'</span><span style="color:#a3be8c;">form</span><span>' </span><span style="color:#ab7967;">%>
</span><span style="color:#ab7967;"><%=</span><span> link\_to '</span><span style="color:#a3be8c;">Back</span><span>', post\_comments\_path(@</span><span style="color:#bf616a;">comment</span><span>.post)</span><span style="color:#ab7967;">%>
</span></code></pre>
</li>
<li><code>show.html.erb</code>: remove :post member and update link<pre data-lang="erb" style="background-color:#2b303b;color:#c0c5ce;" class="language-erb "><code class="language-erb" data-lang="erb"><span style="color:#ab7967;"><%=</span><span> notice </span><span style="color:#ab7967;">%>
</span><span>**Commenter:**
</span><span> </span><span style="color:#ab7967;"><%= </span><span>@</span><span style="color:#bf616a;">comment</span><span>.commenter </span><span style="color:#ab7967;">%>
</span><span>
</span><span>**Body:**
</span><span> </span><span style="color:#ab7967;"><%= </span><span>@</span><span style="color:#bf616a;">comment</span><span>.body </span><span style="color:#ab7967;">%>
</span><span>
</span><span style="color:#ab7967;"><%=</span><span> link\_to '</span><span style="color:#a3be8c;">Edit</span><span>', edit\_post\_comment\_path(@</span><span style="color:#bf616a;">comment</span><span>.post, @</span><span style="color:#bf616a;">comment</span><span>) </span><span style="color:#ab7967;">%></span><span> \|
</span><span style="color:#ab7967;"><%=</span><span> link\_to '</span><span style="color:#a3be8c;">Back</span><span>', post\_comments\_path(@</span><span style="color:#bf616a;">comment</span><span>.post) </span><span style="color:#ab7967;">%>
</span></code></pre>
</li>
<li>And finally, add a link to the show view of post <code>app/views/posts/show.html.erb</code>:<pre data-lang="erb" style="background-color:#2b303b;color:#c0c5ce;" class="language-erb "><code class="language-erb" data-lang="erb"><span style="color:#ab7967;"><%=</span><span> notice </span><span style="color:#ab7967;">%>
</span><span>
</span><span>**Name:**
</span><span style="color:#ab7967;"><%= </span><span>@</span><span style="color:#bf616a;">post</span><span>.</span><span style="color:#96b5b4;">name </span><span style="color:#ab7967;">%>
</span><span>
</span><span>**Title:**
</span><span style="color:#ab7967;"><%= </span><span>@</span><span style="color:#bf616a;">post</span><span>.title </span><span style="color:#ab7967;">%>
</span><span>
</span><span>**Content:**
</span><span style="color:#ab7967;"><%= </span><span>@</span><span style="color:#bf616a;">post</span><span>.content </span><span style="color:#ab7967;">%>
</span><span>
</span><span style="color:#ab7967;"><%=</span><span> link\_to '</span><span style="color:#a3be8c;">Comments</span><span>', post\_comments\_path(@</span><span style="color:#bf616a;">post</span><span>) </span><span style="color:#ab7967;">%></span><span> \|
</span><span style="color:#ab7967;"><%=</span><span> link\_to '</span><span style="color:#a3be8c;">Edit</span><span>', edit\_post\_path(@</span><span style="color:#bf616a;">post</span><span>) </span><span style="color:#ab7967;">%></span><span> \|
</span><span style="color:#ab7967;"><%=</span><span> link\_to '</span><span style="color:#a3be8c;">Back</span><span>', posts\_path </span><span style="color:#ab7967;">%>
</span></code></pre>
</li>
</ul>
<h2 id="final-commands">Final commands<a class="zola-anchor" href="#final-commands" aria-label="Anchor link for: final-commands">๐</a></h2>
<p>Check the routes:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">rake</span><span> routes
</span><span> </span><span style="color:#bf616a;">post</span><span style="color:#96b5b4;">\_</span><span style="color:#bf616a;">comments</span><span> GET /posts/:post</span><span style="color:#96b5b4;">\_</span><span>id/comments(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">comments</span><span>", :action=>"</span><span style="color:#a3be8c;">index</span><span>"}
</span><span> </span><span style="color:#bf616a;">POST</span><span> /posts/:post</span><span style="color:#96b5b4;">\_</span><span>id/comments(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">comments</span><span>", :action=>"</span><span style="color:#a3be8c;">create</span><span>"}
</span><span> </span><span style="color:#bf616a;">new</span><span style="color:#96b5b4;">\_</span><span style="color:#bf616a;">post</span><span style="color:#96b5b4;">\_</span><span style="color:#bf616a;">comment</span><span> GET /posts/:post</span><span style="color:#96b5b4;">\_</span><span>id/comments/new(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">comments</span><span>", :action=>"</span><span style="color:#a3be8c;">new</span><span>"}
</span><span style="color:#bf616a;">edit</span><span style="color:#96b5b4;">\_</span><span style="color:#bf616a;">post</span><span style="color:#96b5b4;">\_</span><span style="color:#bf616a;">comment</span><span> GET /posts/:post</span><span style="color:#96b5b4;">\_</span><span>id/comments/:id/edit(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">comments</span><span>", :action=>"</span><span style="color:#a3be8c;">edit</span><span>"}
</span><span> </span><span style="color:#bf616a;">post</span><span style="color:#96b5b4;">\_</span><span style="color:#bf616a;">comment</span><span> GET /posts/:post</span><span style="color:#96b5b4;">\_</span><span>id/comments/:id(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">comments</span><span>", :action=>"</span><span style="color:#a3be8c;">show</span><span>"}
</span><span> </span><span style="color:#bf616a;">PUT</span><span> /posts/:post</span><span style="color:#96b5b4;">\_</span><span>id/comments/:id(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">comments</span><span>", :action=>"</span><span style="color:#a3be8c;">update</span><span>"}
</span><span> </span><span style="color:#bf616a;">DELETE</span><span> /posts/:post</span><span style="color:#96b5b4;">\_</span><span>id/comments/:id(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">comments</span><span>", :action=>"</span><span style="color:#a3be8c;">destroy</span><span>"}
</span><span> </span><span style="color:#bf616a;">posts</span><span> GET /posts(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">posts</span><span>", :action=>"</span><span style="color:#a3be8c;">index</span><span>"}
</span><span> </span><span style="color:#bf616a;">POST</span><span> /posts(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">posts</span><span>", :action=>"</span><span style="color:#a3be8c;">create</span><span>"}
</span><span> </span><span style="color:#bf616a;">new</span><span style="color:#96b5b4;">\_</span><span style="color:#bf616a;">post</span><span> GET /posts/new(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">posts</span><span>", :action=>"</span><span style="color:#a3be8c;">new</span><span>"}
</span><span> </span><span style="color:#bf616a;">edit</span><span style="color:#96b5b4;">\_</span><span style="color:#bf616a;">post</span><span> GET /posts/:id/edit(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">posts</span><span>", :action=>"</span><span style="color:#a3be8c;">edit</span><span>"}
</span><span> </span><span style="color:#bf616a;">post</span><span> GET /posts/:id(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">posts</span><span>", :action=>"</span><span style="color:#a3be8c;">show</span><span>"}
</span><span> </span><span style="color:#bf616a;">PUT</span><span> /posts/:id(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">posts</span><span>", :action=>"</span><span style="color:#a3be8c;">update</span><span>"}
</span><span> </span><span style="color:#bf616a;">DELETE</span><span> /posts/:id(.:format) </span><span style="color:#bf616a;">{:controller</span><span>=>"</span><span style="color:#a3be8c;">posts</span><span>", :action=>"</span><span style="color:#a3be8c;">destroy</span><span>"}
</span></code></pre>
<p>Create and migrate the db:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">rake</span><span> db:create
</span><span style="color:#bf616a;">rake</span><span> db:migrate
</span></code></pre>
<p>Run the server:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">rails</span><span> server
</span></code></pre>
<p>Voilร !</p>
8th color, the color of magic2011-08-22T00:00:00+00:002011-08-22T00:00:00+00:00https://ibakesoftware.com/blog/the-color-of-magic/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<p>After having chosen one and asked people what they think about, we've given a name to our company: <strong>8th color</strong>. We've got a lot of very interesting comments from our friends, family, colleagues and also readers thanks to direct interaction and the poll. First of all, thanks everybody for your feedbacks. But where does it come from? Some of our readers with great literature culture have found the inspiration behind. It comes from a Terry Pratchett's Discworld novel: <a href="http://en.wikipedia.org/wiki/The_colour_of_magic" title="The colour of magic">The colour of magic</a>.</p>
<blockquote>
<p>It was octarine [the eighth colour], the colour of magic. It was alive and glowing and vibrant and it was the undisputed pigment of the imagination, because wherever it appeared it was a sign that mere matter was a servant of the powers of the magical mind. It was enchantment itself. But Rincewind always thought it looked a sort of greenish-purple.</p>
</blockquote>
<p>For us, code and programming is a kind of magic. The developers can realize nearly everything he can imagine. If it is well realized, the user don't feel the mechanism behind, and everything magically behaves. We believe in great tool with great interface. We don't want to create a hammer with a poor and buggy handle. We also believe that we can't consider ourselves too seriously if we want to reach this goal: humor is a very nice way to stay critical.</p>
<p>For those reasons and we love Pratchett's work, <strong>8th color</strong> is full of meaning. And well, if the company could be successful as much as Rincewind is, it's definitively a good name .</p>
<p>We reassure you, we will not use a colormap according the Rincewind's perception.</p>
Who are our customers?2011-08-19T00:00:00+00:002011-08-19T00:00:00+00:00https://ibakesoftware.com/blog/who-are-our-posible-customers/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<p>When we sketched our first business model canvas, we quickly hit into this question. We quickly answered: "They are the developers". But when considering the value propositions, we realized two facts:</p>
<ol>
<li>their needs are not the same, and</li>
<li>the developer is not always the buyer.</li>
</ol>
<p>We're then able to identify 3 segments:</p>
<ul>
<li>the lone developer (freelance, hobbyist),</li>
<li>the small team, the IT startup, and</li>
<li>the big corporate and its large bunch of developer.</li>
</ul>
<p>First step, first lesson: it is not a trivial question. Without knowing our customers, we cannot imagine value propositions, channels, revenue streams, relationships. There are no business at all.</p>
<p>Thanks to the Business Model Generation book, now, we can try to catch customers' mind, to understand them, to perceive through their eyes. This can be done with the <a href="http://www.xplane.com/" title="XPLANE website">XPLANE</a>'s Empathy Map.</p>
<p><img src="/blog/images/empathy_map.png" alt="Empathy Map" /></p>
<p>It consists in a framework helping you to perceive, feel, think, and act as your customer by asking clear and simple questions:</p>
<ol>
<li>What does he see?</li>
<li>What does he hear?</li>
<li>What does he really think and feel?</li>
<li>What does he say and do?</li>
<li>What is his pain?</li>
<li>What does he gain?</li>
</ol>
<p>At first sight, we thought: "this is trivial". But, after trying to answer those questions, we quickly understand it is not trivial at all. More important, we understand our a priori about our customers are biased by us.</p>
<p>After reproducing the map on a A3 sheet, we've decided to do the exercise for our three customer segments: the lone dev, the project leader and the CIO. We've used Post-it of three colors, one for each customer segment. We've selected a question summarizing the kind of pain we address. And we've debated and answered all questions, one after the other, for each customer segment. Sometimes, we've got an answer for another customer segment and we've just put it on a Post-it of adequate color. The whole process lasted about 3 hours and allow us to produce the following empathy map:</p>
<p><img src="/blog/images/first-empathy-map.jpg" alt="First empathy map" /></p>
<p>The empathy map help us to:</p>
<ul>
<li>deeply understand who possibly are our customers and their environment,</li>
<li>confirm there are more than one possible customer segments,</li>
<li>identify different kind of profiles inside each segment,</li>
<li>link value propositions with customer segments (especially thanks to the pain and gain sections), and</li>
<li>realize it is not, at all, a trivial question.</li>
</ul>
<p>The last point pushes us to plan interviews of customers. This will help us to iterate over this map and, by doing so, our business models.</p>
Business Model Generation2011-07-25T00:00:00+00:002011-07-25T00:00:00+00:00https://ibakesoftware.com/blog/business-model-generation/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<p>In our quest <em>building-our-company</em>, I've just finished a book: <a href="http://businessmodelgeneration.com/book" title="Business Model Generation">Business Model Generation</a> notably written by <a href="http://www.businessmodelalchemist.com/" title="Business Model Alchemist">Alexander Osterwalder</a>. This book presents a new tool allowing to develop and sketch out new or existing business models: <strong><a href="http://en.wikipedia.org/wiki/Business_Model_Canvas" title="Business Modela Canvas">Business Model Canvas</a></strong>. This tool consists in a visual template composed of nine building blocks composing the business model.</p>
<p><img src="/blog/images/Business_Model_Canvas.png" alt="Business Model Canvas" /></p>
<p>I don't go deeper in its description, let me instead tell you how the book is structured, and how is worthy I think it is or not.</p>
<p>The book came from the Alexander Osterwalder's PhD thesis under Yves Pigneur's supervision. The methodology he's designed has started to be applied around the world and notably by some big companies such as 3M or Deloitte. The idea of a book naturally came. But they didn't want to make yet another business book. They built an online community around a core team in order to fund the project and obtain feedbacks and contributions. As results, the final book is coauthored by 470 practitioners. That means lots of real-world perspectives and examples. Another good point is the visual presentation of the book, in the spirit of "a sketch is often more valuable than a thousand of words". It makes the reading very comfortable: even if you're get lost by the presented concepts, you can grab on them thanks to the drawings.</p>
<p>About its structure, the book is composed of five main sections guiding you from the tool basics to how you can generate business model:</p>
<ol>
<li>Canvas,</li>
<li>Pattern,</li>
<li>Design,</li>
<li>Strategy, and</li>
<li>Process.</li>
</ol>
<p>The first section, <strong>Canvas</strong>, defined the Business Model Canvas and its 9 components. In the next section, <strong>Pattern</strong>, several business models are expressed in terms of the canvas and patterns are underlined. The third one, <strong>Design</strong>, describes 6 techniques (customer insight, ideation, visual thinking, prototyping, storytelling, and scenarios) that can help you design business model. It starts with a quote of Roger Martin, the author of the book <a href="https://ibakesoftware.com/blog/the-design-of-business/" title="The design of business">The design of business</a> that appears to me as a wing of one of my last reads:</p>
<blockquote>
<p>Business people don't just need to understand designers better; they need to become designers.</p>
</blockquote>
<p>The fourth section, <strong>Strategy</strong>, explores four different strategies to challenge business models you've designed. In other words, they help you to make choices and adapt your new or existing model. In the last section, <strong>Process</strong>, an whole design process is presented. This process is built over all the concepts, tools and techniques explained in the previous sections.</p>
<p>It's time to tell you what I think. When I've started to think about running a business two years ago, it quickly came to me some concepts such as business plan, budget or marketing. Business plan seemed to be the must to do. Well, I didn't even know what it is exactly. After googling and reading several websites, business plan appeared to me as a big document including a lot of subjects that I wasn't comfortable with. I've then received a <a href="http://www.amazon.fr/Strat%C3%A9gie-pour-Cr%C3%A9ation-dEntreprise-D%C3%A9veloppement/dp/2100525360/ref=ntt_at_ep_dpt_1" title="Stratรฉgie pour la Crรฉation d'Entreprise : Crรฉation, Reprise, Dรฉveloppement">book about the creation of company</a>. I've started to read it. I've learned a lot about all those concepts I didn't know. But it was boring. Throughout the book, it became harder and harder to still reading. The book was like a big academic course bundling different subjects with no clear methodology to design your business model and write your business plan (even it is the purpose of the book). Moreover, the difficulty was very unequal. Sometimes, it is explained as you're a child, and two pages after you have to deal with complex economical topics. I don't usually drop a book I've started to read. But to be honest, I've dropped that one and producing a business plan has still seemed as a mystery. Until this book, Business Model Generation.</p>
<p>After the first section, <strong>Canvas</strong>, Martin and I have designed our first business model. It is probably not good, but we still iterate over it or simply design other ones. The <strong>Pattern</strong> section gives you a better understanding of existing businesses and you start to differently see them. We've already applied one technique described in the <strong>Design</strong> section: customer insight. It helps us to better understand what are probably our customers (probably the subject of a future post). The two last sections are still too abstract. We have to practice in order to really understand them. It is the only negative point of the book. The last sections are not well put in perspective. Even if some examples illustrate them, it is hard to get the presented concepts. But we have at least a guideline to practice them. It is enough.</p>
<p>Each time we apply what we've learned thanks the book, we make progress. Besides, at the end of the book, you'll find one page explaining how to write your business plan from your final and filled Business Model Canvas. Now, I can conceive how to produce my business plan. If you're a business noob as I was, I recommend you to start with this book and get into the following definition opening the Canvas section:</p>
<blockquote>
<p>A business model describes the rationale of how an organization creates, delivers, and captures value.</p>
</blockquote>
Experiencing Brussels Pitch Bootcamp2011-07-07T00:00:00+00:002011-07-07T00:00:00+00:00https://ibakesoftware.com/blog/brussells-pitch-bootcamp/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<p>Yesterday, Martin and I have attended the <a href="http://brfibootcamp2011.eventbrite.com/" title="Brussels Pitch Bootcamp">Brussels Pitch Bootcamp</a> organized by the <a href="http://betagroup.be" title="BetaGroup">BetaGroup</a> and the <a href="http://www.founderinstitute.com/" title="Founder Institute">Founder Institute</a>. The event was hosted at the <a href="http://www.betacowork.com/" title="Betacowork Coworking Brussels">Betacowork Coworking Brussels</a>. It was the opportunity to discover this very nice, clean and calm place that we hear a lot about. After seeing it, I still want more to come work there sometimes. But this is not the purpose of this post. Let's back to our subject the Pitch Bootcamp which is dedicated to learn and practice the art of pitching.</p>
<p>This was an amazing experience. I've attended a lot of courses, tutorials, workshops, lectures, professional developments ... all those kind of passive or active presentations that you can attend when you are a student, an academic researcher, or simply an employee. Still, it was the first time in my life - it's not rhetoric - that I go to a talk/workshop that:</p>
<ul>
<li>I'm enjoying me all along,</li>
<li>Make me learn so much in a very clear and structured way,</li>
<li>Oblige me to directly practice what I've learned, and</li>
<li>Allow me to improve what I know/think.</li>
</ul>
<p>When I've left, I was sure of something: I didn't waste my time. Yes, the talker <a href="http://www.adeoressi.com/about/" title="about Adeo Ressi">Adeo Ressi</a>, the founder of the Founder Institute, is a kind of very charming showman with a very good balancing between tough and encouraging words. It's true. Better yet, his talent as a showman does not deserve his purpose at all: learn us something about pitching. It only makes it more enjoyable! Notice that the audience was also very nice, all attendees having well played the game.</p>
<p>The workshop was composed of four parts:</p>
<ol>
<li>Information about the Founder Institute, its program, how it works, etc.</li>
<li>Some theories and exercises about pitching:
<ol>
<li>3 kinds ( <a href="http://en.wikipedia.org/wiki/Elevator_pitch" title="Elevator Pitch">elevator</a>, competative, investor), their differences</li>
<li>What is an elevator pitch? Its purpose, its structure?</li>
<li>What is a good elevator pitch? Active session during which several attendees did practice and have feedbacks/comments from Adeo Ressi and the audience.</li>
<li>What is an competative pitch? Its purpose, its structure? The 3 possible approaches (factual, narrative, pain point).</li>
<li>What is a good competative pitch? Again an active session.</li>
</ol>
</li>
<li>Speed pitching to peers: Pick a partner randomly. One pitches during 30s, the other gives feedback during 60s and then you switch roles. After 3 min, repeat with another person. I think we did 5 or 6 turns.</li>
<li>Conclusion and feedback</li>
</ol>
<p>After that, you're exhausted and happy like after a good sport session. We've learned a lot, and I think it helps to precise our ideas. A beer session followed the bootcamp, but we passed it due to some private reasons.</p>
<p>After leaving the event, Martin and I did share our feelings and thoughts on the evening. A question quickly came to our minds. If we can learn so much in one session, what we can learn by following the full session of the Founder Institute? Or is this just a very good presale advertising event to push us to apply the program and pay the fees? Maybe it is an event to attract "customers". Maybe. But we're sure of something: it cannot possible that the quality is not met after we've experienced. Moreover, the fee is pretty reasonable: 900โฌ for about 16 workshops and some other stuff. Some "professional workshop" costs this price for 8 hours. Without listing all other reasons such as networking or feedbacks on our project, we are nearly convinced to apply.</p>
Git and Gitosis on Debian Squeeze2011-06-27T00:00:00+00:002011-06-27T00:00:00+00:00https://ibakesoftware.com/blog/git-and-gitosis-on-debian-squeeze/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<h2 id="preliminaries">Preliminaries<a class="zola-anchor" href="#preliminaries" aria-label="Anchor link for: preliminaries">๐</a></h2>
<p>We've started to prototype some of our ideas those last weeks. Currently, we're working on 3 projects. For one, we have 2 branches. Today, it exists <a href="http://en.wikipedia.org/wiki/Revision_Control_System" title="Revision control system">wonderful tools to manage collaboration and revision of source code</a>. Even when I'm alone in a software development project, I use one. It is about time to set up one for enkio.</p>
<p>The purpose of the current post is not to deal with the trollable question "which RCS is the best". Maybe I'll share later about that, but not now. We have chosen <a href="http://en.wikipedia.org/wiki/Git_%28software%29" title="Git">Git</a> because it is used by the <a href="http://en.wikipedia.org/wiki/Ruby_on_Rails" title="Ruby on Rails">RoR</a> and <a href="http://en.wikipedia.org/wiki/Django_%28Web_framework%29" title="Django">Django</a> communities and dedicated hosting solutions, and we want make our opinion by ourselves.</p>
<p>This howto concerns the installation of Git and Gitosis. The last one is a simple manager of repository access using SSH key and not needing shell accounts. Before starting, here are some conventions I'll use for prompt symbols:</p>
<pre style="background-color:#2b303b;color:#c0c5ce;"><code><span>> = remote
</span><span>$ = local
</span></code></pre>
<h2 id="installation">Installation<a class="zola-anchor" href="#installation" aria-label="Anchor link for: installation">๐</a></h2>
<p>As usual, update your package db:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span>> aptitude </span><span style="color:#bf616a;">update
</span></code></pre>
<p>Install git and gitosis</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span>> aptitude </span><span style="color:#bf616a;">install</span><span> git-core gitosis
</span></code></pre>
<p>The Debian package has created a <code>gitosis</code> sys user and its home directory is at <code>/srv/gitosis</code>.</p>
<h3 id="init-gitosis">Init Gitosis<a class="zola-anchor" href="#init-gitosis" aria-label="Anchor link for: init-gitosis">๐</a></h3>
<p>Now, you need to setup gitosis and the administration access. To do that you need a SSH public key that I simply name <code>id.pub</code> here. First of all, copy this key on the server in the <code>/tmp</code> directory:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> scp id.pub your.server.com:/tmp
</span></code></pre>
<p>You can now setup gitosis:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span>> su </span><span style="color:#bf616a;">gitosis
</span><span>> cd
</span><span>> gitosis-init < /tmp/id.pub
</span><span style="color:#bf616a;">Initialized</span><span> empty Git repository in /srv/gitosis/repositories/gitosis-admin.git/
</span><span style="color:#bf616a;">Reinitialized</span><span> existing Git repository in /srv/gitosis/repositories/gitosis-admin.git
</span></code></pre>
<p>This creates the repository gitosis-admin, setting up gitosis. But to effectively set up gitosis you have to clone it locally, in order to work on its setup file <code>gitosis.conf</code> and add new SSH public keys for other users.</p>
<h3 id="retrieve-gitosis-admin-locally">Retrieve gitosis-admin locally<a class="zola-anchor" href="#retrieve-gitosis-admin-locally" aria-label="Anchor link for: retrieve-gitosis-admin-locally">๐</a></h3>
<p>But before don't forget to correctly setup your SSH by adding at least the following in your <code>~/.ssh/config</code> file:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> cat << </span><span style="color:#b48ead;">EOF </span><span>> </span><span style="color:#bf616a;">~</span><span>/.ssh/config
</span><span style="color:#a3be8c;">Host your.server.com
</span><span style="color:#a3be8c;"> IdentityFile ~/.ssh/id
</span><span style="color:#b48ead;">EOF
</span></code></pre>
<p>Now you can clone the gitosis-admin repository:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> git clone gitosis@your.server.com:gitosis-admin.git
</span><span style="color:#bf616a;">Cloning</span><span> into gitosis-admin...
</span><span style="color:#bf616a;">Enter</span><span> passphrase for key '</span><span style="color:#a3be8c;">/home/you/.ssh/id</span><span>':
</span><span style="color:#bf616a;">remote:</span><span> Counting objects: 5, done.
</span><span style="color:#bf616a;">remote:</span><span> Compressing objects: 100% (4/4)</span><span style="color:#bf616a;">,</span><span> done.
</span><span style="color:#bf616a;">remote:</span><span> Total 5 (delta 0)</span><span style="color:#bf616a;">,</span><span> reused 5 (delta 0)
</span><span style="color:#bf616a;">Receiving</span><span> objects: 100% (5/5)</span><span style="color:#bf616a;">,</span><span> done.
</span></code></pre>
<p>In the directory <code>gitosis-admin</code>, you'll find the <code>gitosis.conf</code> file and the directory <code>keydir</code> where you have to put git user SSH public keys.</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> ls gitosis-admin
</span><span style="color:#bf616a;">gitosis.conf</span><span> keydir
</span><span style="color:#bf616a;">$</span><span> ls gitosis-admin/keydir
</span><span style="color:#bf616a;">id.pub
</span></code></pre>
<p>Let's take a look into <code>gitosis.conf</code> file:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> cd gitosis-admin
</span><span style="color:#bf616a;">$</span><span> cat gitosis.conf
</span><span style="color:#bf616a;">[gitosis]
</span><span>
</span><span style="color:#bf616a;">[group</span><span> gitosis-admin]
</span><span style="color:#bf616a;">writable</span><span> = gitosis-admin
</span><span style="color:#bf616a;">members</span><span> = id
</span></code></pre>
<p>A group <code>gitosis-admin</code> is already set up. It gives write access to the <code>gitosis-admin</code> repository and there is a member: <code>id</code>. <code>id</code> is the user name associated to the SSH public key defined inside the file <code>id.pub</code>.</p>
<h3 id="setup-access-to-the-new-repository">Setup access to the new repository<a class="zola-anchor" href="#setup-access-to-the-new-repository" aria-label="Anchor link for: setup-access-to-the-new-repository">๐</a></h3>
<p>To illustrate how to use and setup gitosis, I'll create a repository and give write access to another user. First of all, I have to set up the access:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> cat << </span><span style="color:#b48ead;">EOF </span><span>>> gitosis.conf
</span><span style="color:#a3be8c;">[group myteam]
</span><span style="color:#a3be8c;">writable = myproject
</span><span style="color:#a3be8c;">members = id another
</span><span style="color:#b48ead;">EOF
</span></code></pre>
<p>By adding those lines, all members of group <code>myteam</code> have been given write access to <code>myproject</code>. And members of this group are <code>id</code> and <code>another</code>. I do not forget to add a SSH public key for another user:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> cp </span><span style="color:#bf616a;">~</span><span>/another.pub keydir/
</span><span style="color:#bf616a;">$</span><span> git add gitosis.conf keydir/another.pub
</span><span style="color:#bf616a;">$</span><span> git commit</span><span style="color:#bf616a;"> -m </span><span>"</span><span style="color:#a3be8c;">give write access to group myteam on project myproject</span><span>"
</span><span style="color:#bf616a;">$</span><span> git push
</span></code></pre>
<p>And it's done.</p>
<h3 id="create-the-new-repository">Create the new repository<a class="zola-anchor" href="#create-the-new-repository" aria-label="Anchor link for: create-the-new-repository">๐</a></h3>
<p>Then, I can create a blank repository <code>myproject</code>:</p>
<pre data-lang="bash" style="background-color:#2b303b;color:#c0c5ce;" class="language-bash "><code class="language-bash" data-lang="bash"><span style="color:#bf616a;">$</span><span> cd ..
</span><span style="color:#bf616a;">$</span><span> git clone gitosis@your.server.com:myproject.git
</span><span style="color:#bf616a;">Cloning</span><span> into myproject...
</span><span style="color:#bf616a;">Enter</span><span> passphrase for key '</span><span style="color:#a3be8c;">/home/id/.ssh/id</span><span>':
</span><span style="color:#bf616a;">Initialized</span><span> empty Git repository in /srv/gitosis/repositories/myproject.git/
</span><span style="color:#bf616a;">warning:</span><span> You appear to have cloned an empty repository.
</span></code></pre>
<p>Voilร !</p>
<h2 id="references">References<a class="zola-anchor" href="#references" aria-label="Anchor link for: references">๐</a></h2>
<ul>
<li><a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way">http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way</a></li>
<li><a href="http://git-scm.com/documentation">http://git-scm.com/documentation</a></li>
<li><a href="http://progit.org/book/">http://progit.org/book/</a></li>
<li><a href="https://help.ubuntu.com/community/Git">https://help.ubuntu.com/community/Git</a></li>
<li><a href="http://eagain.net/gitweb/?p=gitosis.git">http://eagain.net/gitweb/?p=gitosis.git</a></li>
</ul>
The design of business2011-06-15T00:00:00+00:002011-06-15T00:00:00+00:00https://ibakesoftware.com/blog/the-design-of-business/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<p>When you've never created a business, you're in front of a total mystery that you discover and experiment for the first time. But you're not the first, there are a plenty of people that did it before you. And hopefully, among them, they are many sharing their experiences, thoughts, theories or advices. I don't know if it is your case, but me, I'm hungry of all of that shared information. I read them and learn from them as much as possible.</p>
<p>One of my last reads is a book written by <a href="http://rogerlmartin.com/" title="Roger Martin's website">Roger Martin</a>: <a href="http://rogerlmartin.com/library/books/the-design-of-business" title="The design of business">The design of business</a>. Well, I think the title couldn't be more adequate. It's a good start. The book was advised to me by Eric, a friend and a founder of <a href="http://euranova.eu/" title="Euranova">Euranova</a>. Another good point. After reading it, I'm not disappointed at all. Roger Martin explains a very interesting approach of design, especially the one of business. I've found myself in a lot of thoughts, but in a very clear framework. So clear that I'm now able to put the exacts words on my personal stance or formalize my approach of design. If you're interested in the creation of a company, or just in the use of design in your daily professional activities, this is a must read.</p>
<p>The book is easy to read and well structured in 7 chapters. First, Roger Martin introduces the concepts of knowledge funnel and design thinking in business. Naturally, a fresh created company goes through this funnel and grows from innovation to effective and reliable business. He then explains that most of business are run with the reliability bias and finally puts aside validity, i.e. the innovation process. In the third chapter, he argues how design thinking can create true advantages by balancing validity and reliability. In the following chapter, he gives the example of a big company, <a href="http://en.wikipedia.org/wiki/Procter_%26_Gamble" title="Wikipedia page of Procter & Gamble">Procter & Gamble</a>, transforming itself to fully adopt design thinking approach. The fifth chapter allows him to present management solutions in order to adopt, apply and protect a culture of design thinking in an organization. The sixth one is mainly a chapter presenting several real design thinkers. And in the final chapter, Roger Martin explains how you can apply this approach to your work even if your organization doesn't take care about it.</p>
<p>As a software engineer, this approach is for me a true echo to modern techniques of software project management such as <a href="http://en.wikipedia.org/wiki/Category:Agile_software_development" title="Agile software development Wikipedia Category">Agile methods</a>. Indeed, in a software project, you have to deal with validity and reliability. Even if the problem is an easy one, the validity fully depends on the needs and views of the customer or the user. According to them, you then produce a lot of blueprints that you iterately refines. When validity is met, you make the software as reliable as possible. That means you fix bugs or ergonomy, but also you improve its maintainability in order to make further development or modification easier without destroying everything. As a software designer, the design thinking is then very natural. Moreover, I think an IT company is certainly a place where it has to be applied because of the very changing and competitive nature of the IT market. I'm then convinced enkio should adopt this culture.</p>
Hello world!2011-05-03T00:00:00+00:002011-05-03T00:00:00+00:00https://ibakesoftware.com/blog/hello-world/
<p><strong>This is an archive of blog post I wrote during my first venture (beginning of 8thcolor).</strong></p>
<p>As for every project, every book, every blog, there is a beginning. This is it.</p>
<p>I am Christophe, a software engineer with a <a href="http://theses.ulb.ac.be/ETD-db/collection/available/ULBetd-11052008-122223/">PhD</a>. After teaching several IT courses (e.g. C++, OOP) and making researches in <a href="http://en.wikipedia.org/wiki/Natural_computing">natural computing</a>, I've started as <a href="http://www.linkedin.com/in/christophephilemotte">freelance IT engineer</a> with interests in software engineering, infrastructure, and system administration. When I left the academia 2 years ago, I knew that I want to lead and create my company. After getting some "true" real world experiences, it is time for me to step forward.</p>
<p>Martin is an economist with a pedagogic title. After some years spent in teaching future programmers, Martin has started a proper IT career, where he did work as a programmer, customer contact, team leader, architect and sometimes a mix of those. With interests in software design and knowledge management (starting with his own), Martin looks for new opportunities to use his skills, help others acquire them and learn some more himself.</p>
<p>Thanks to this blog, me and Martin will mainly share about our current experience of creating a IT company (yet another one), but also linked subjects such as technical howto or simply opinions that matters in our work. We see this as a way to communicate our thoughts, exchange on our ideas and challenge our opinions.</p>