Elias Dorneleshttps://eliasdorneles.com/2023-05-01T20:00:00+02:00So I'm releasing a single!2023-05-01T20:00:00+02:002023-05-01T20:00:00+02:00Elias Dornelestag:eliasdorneles.com,2023-05-01:/2023/05/01/so-i-m-releasing-a-single.html<p><center><img width="400" src="https://eliasdorneles.com/images/cover_tqqesls.jpg" /></center></p>
<p>I have written a few songs over the years, their lyrics are scribbled down
on a personal archive and there are some terrible home-made (phone-made!)
recordings of them laying around, stuff that I've shared with friends and
family over WhatsApp and the like.</p>
<p>This one is different!</p>
<p>I've written this …</p><p><center><img width="400" src="https://eliasdorneles.com/images/cover_tqqesls.jpg" /></center></p>
<p>I have written a few songs over the years, their lyrics are scribbled down
on a personal archive and there are some terrible home-made (phone-made!)
recordings of them laying around, stuff that I've shared with friends and
family over WhatsApp and the like.</p>
<p>This one is different!</p>
<p>I've written this song while writing a short autobiography, as an existential
therapy exercise, and I was trying to remember why was it that when I was 10
years old I asked my parents to be baptised at the evangelical church my family
used to go.</p>
<p>The main reason I was pondering that is because I remember very clearly to
think to myself in multiple occasions while I was younger than that: "when I
grow up, I won't bother going to church!". This thought was a self-fulfilling
prophecy from my young self which eventually became true when I abandoned
religion in my early twenties.</p>
<p>So what was it that made me change my mind when I was 10? Why did I want to
get baptised then?</p>
<p>One reason that I remember and which I wisely didn't mention back then (though
my younger brother was totally onto me!) was that I really wanted to try the
bread and wine served during the "Lord's Supper", which were reserved to the
folks who were already baptised. Oh man, those looked and smelled so good! 😄 </p>
<p>But I knew there was something else, something more profound than that.
So after much reflection, and discussing the matter with my mother and my sister
of similar age (she was 12 at the time and got baptised some time after me), I
realized that the main reason was because I wanted to be considered like a
grown-up, I wanted to be taken seriously, I wanted to <strong>matter</strong>!</p>
<p>My first thought after talking to my sister over the phone was the phrase that
became the refrain and title of the song: <em>« Tudo o que eu queria era ser
levado a sério ! »</em>, which means "all I wanted was to be taken seriously".</p>
<p>I said that out loud, sensed that I had something musical, so I sat down and
wrote the first two verses spontaneously. That was exciting! Recorded it with
my phone, then went to bed, woke up the next day and wrote the final verse in
the same way. Never before writing a song had happened so spontaneously, never
before I was writing from a place of so much authenticity! It was exhilarating!</p>
<p>I then decided to release it to the world, and for that I had the luck to be
accompanied by these great humans helping to make it happen:</p>
<ul>
<li><a href="https://www.marianotelles.com/">Mariano Telles</a> did the music production. This dude is awesome! An astounding guitarist, a talented musician and a great composer! Mariano: I thoroughly enjoyed working on this project with you, some good fun recording! You rock! 🎶🪄</li>
<li><a href="https://www.behance.net/giopiazza">Giovanni Piazza</a>, a friend from years back when I lived in Floripa who is an accomplished designer/entrepreneur/artist, did the gorgeous cover art that you can appreciate in this post 🎨😻</li>
<li><a href="https://www.instagram.com/priscillafrade/">Pricilla Frade</a>, an amazing artist I discovered on Instagram who sings so beautifully, gave me singing lessons and sent many good vibes ✨💜</li>
</ul>
<p>To the three of you: thank you so much! You folks are awesome! 💗</p>
<h3>The single will be released on the 24th May 2023!</h3>
<p>It will be out on the very day I'll be 36 years old -- yes, that'll be my birthday present! 🎁</p>
<p>If you use Spotify, you can <a href="https://distrokid.com/hyperfollow/eliasdorneles/tudo-o-que-eu-queria-era-ser-levado-a-srio">pre-save the title through this page
</a>.</p>
<p>Stay tuned and enjoy the music!</p>
<p><center><img src="https://eliasdorneles.com/images/cover_floating_tqqesls.jpg" /></center></p>Vou lançar um single!2023-05-01T20:00:00+02:002023-05-01T20:00:00+02:00Elias Dornelestag:eliasdorneles.com,2023-05-01:/so-i-m-releasing-a-single-pt-br.html<p><center><img width="400" src="https://eliasdorneles.com/images/cover_tqqesls.jpg" /></center></p>
<p>Escrevi algumas músicas ao longo dos anos, as letras estão rabiscadas em um
arquivo pessoal e existem algumas gravações caseiras delas com qualidade
duvidosa por aí, que compartilhei com amigos e familiares pelo WhatsApp e
coisas do tipo.</p>
<p>Mas essa é diferente!</p>
<p>Essa música me veio enquanto eu escrevia uma …</p><p><center><img width="400" src="https://eliasdorneles.com/images/cover_tqqesls.jpg" /></center></p>
<p>Escrevi algumas músicas ao longo dos anos, as letras estão rabiscadas em um
arquivo pessoal e existem algumas gravações caseiras delas com qualidade
duvidosa por aí, que compartilhei com amigos e familiares pelo WhatsApp e
coisas do tipo.</p>
<p>Mas essa é diferente!</p>
<p>Essa música me veio enquanto eu escrevia uma breve autobiografia, um exercício
de terapia existencial, e eu estava tentando lembrar por que é que aos 10 anos
eu pedi aos meus pais para ser batizado na igreja evangélica que minha família
frequentava.</p>
<p>Fiquei matutando nisso principalmente porque eu lembrava muito claramente de
ter pensado várias vezes quando tinha em torno de 8 anos algo tipo: <em>"quando eu
crescer, não irei mais à igreja!"</em>. Esse pensamento foi uma profecia da criança
que eu era, que eventualmente se realizou quando abandonei a religião no início dos
meus vinte anos.</p>
<p>Mas então, o que me fez mudar de ideia quando tinha 10 anos? Por que eu quis
ser batizado naquela época?</p>
<p>Um motivo do qual me lembro e que sabiamente não mencionei naquela época
(embora meu irmão mais novo tenha percebido!) era que eu realmente queria
experimentar o pão e o vinho servidos durante o ritual da "Santa Ceia", que
eram reservados para as pessoas que já haviam sido batizadas. Cara, aqueles pães
e aquele vinho tinham um cheirinho tão bom! 😄 </p>
<p>Mas eu sabia que havia outra coisa, algo mais profundo do que isso. Então, depois
de muita reflexão e de discutir o assunto com minha mãe e minha irmã que regulava
de idade comigo (ela tinha 12 anos na época e se batizou algum tempo depois de mim),
percebi que a principal razão era porque eu queria ser considerado mais
seriamente. As pessoas diziam de quem era batizado "Fulano já participa da
ceia", era como um degrau na escadinha da maturidade. Eu queria ser considerado
importante assim, tão importante quanto um adulto.</p>
<p>Meu primeiro pensamento depois de falar com minha irmã pelo telefone foi a
frase que se tornou o refrão e o título da música: <em>« Tudo o que eu queria era
ser levado a sério ! »</em></p>
<p>Eu disse isso em voz alta, senti que tinha algo musical, então sentei e escrevi
os primeiros dois versos que vieram de maneira bem natural e espontânea. Legal!
Gravei rapidinho com o telefone, fui dormir, acordei no dia seguinte e escrevi
o verso final na mesma energia. Uau! Nunca antes escrever uma música foi tão
espontâneo, nunca antes eu escrevi a partir de tanta autenticidade! Foi bem
energizante!</p>
<p>Então decidi lançar a música no mundo, e para isso tive a chance de ser
acompanhado por esses seres humanos maravilhosos que me ajudaram a tornar isso
realidade:</p>
<ul>
<li><a href="https://www.marianotelles.com/">Mariano Telles</a> foi responsável pela produção musical. Esse cara é incrível! Um guitarrista surpreendente, um músico talentoso e um grande compositor! Mariano: adorei trabalhar neste projeto com você, e foi bem divertido gravar no seu estúdio! Você é demais! 🎶🪄</li>
<li><a href="https://www.behance.net/giopiazza">Giovanni Piazza</a>, um amigo do tempo que eu morava em Floripa, um designer/empreendedor/artista, fez essa arte linda para a capa que você pode apreciar no post 🎨😻</li>
<li><a href="https://www.instagram.com/priscillafrade/">Pricilla Frade</a>, uma artista maravilhosa que descobri no Instagram e que canta lindamente, me ajudou a trabalhar a voz e a expressão justa para a música e enviou muita energia positiva ✨💜</li>
</ul>
<p>Para vocês três: muito obrigado! Vocês são incríveis! 💗</p>
<h3>O single vai sair no dia 24 de maio de 2023!</h3>
<p>Será lançado no dia em que farei 36 anos - sim, esse será meu presente de aniversário! 🎁</p>
<p>Se você usa o Spotify, pode <a href="https://distrokid.com/hyperfollow/eliasdorneles/tudo-o-que-eu-queria-era-ser-levado-a-srio">fazer o pre-save do título aqui</a>.</p>
<p>Fique ligado e aproveite a música!</p>
<p><center><img src="https://eliasdorneles.com/images/cover_floating_tqqesls.jpg" /></center></p>The Joy of YAML2021-08-13T22:14:00+02:002021-08-13T22:14:00+02:00Elias Dornelestag:eliasdorneles.com,2021-08-13:/2021/08/13/the-joy-of-yaml.html<p>I haven't written much on the blog on the last few years, I don't know, I
didn't felt like I had much to say. There is so much being said on the Web,
lots of great stuff, but also tons of crap too, and I didn't feel like adding
to …</p><p>I haven't written much on the blog on the last few years, I don't know, I
didn't felt like I had much to say. There is so much being said on the Web,
lots of great stuff, but also tons of crap too, and I didn't feel like adding
to the noise. I've learned loads of stuff, but not in the mood for sharing, and
anyway the most important stuff wasn't related to tech.</p>
<p>But today I've got the itch to write, and this little comeback is to tell you that I think
<a href="https://en.wikipedia.org/wiki/YAML">YAML</a> is a pretty cool thing because it
lets you cut corners, ship things fast, give power to your power users, all
that while keeping the design straightforward.</p>
<p>The traditional way most Web programmers have learned to do things like content
management systems, forms, and such, goes something along these lines:</p>
<ol>
<li>get a database (usually relational)</li>
<li>setup a web app with your framework of choice</li>
<li>create the user facing features, either by old-fashioned Web app, or API + frontend app</li>
<li>create an administration interface for staff users to update content</li>
</ol>
<p><sup>(yeah yeah, there are cloud paas providers, nosql, graphql, brainfucql,
yadda yadda... whatever, I said <em>traditional way</em>! By that I mean, people that
learned like me =P)</sup></p>
<p>I want to talk about this last step: the admin interface for your internal users.</p>
<p>When you're doing this for users that you can trust, that's where YAML can be
of great value.</p>
<h2>Growing the admin interface is tricky</h2>
<p>If you use a framework like
<a href="https://docs.djangoproject.com/en/3.2/ref/contrib/admin/">Django</a>, you get
lots of help for quickly having a neat administration interface from the start. With a
few lines of code, you get something that users can actually use, which can be
extended in many ways by adding a few more lines of code.</p>
<p><sup>(If you're not using Django or something similar, you don't get much help
and you gotta implement it like any other user feature, which means it's
even more expensive. I'll stick to Django or similar here to make my
point.)</sup></p>
<p>So it's great, and it is one of the reasons why I and many people like
Django. It's a web framework for perfectionists with deadlines. Even as a solo
developer, you get a lot of shit done real fast, with code that doesn't look
too bad. Awesome!</p>
<p>Except... well, if the system continues living on for a few years, it keeps
increasing and being patched up, you keep adding models and relationships, and
your admin interface starts getting quite complicated.</p>
<p>Users start to get lost on the many different models and the relationships
between them, because the structure isn't clear anymore when you have a few
dozens of models / tables. You start reaching the limits of what can be
achieved with extending the Django admin, it's not as easy to add things
quickly anymore, things like proper validation are quite complicated because of
the many relationships, the admin is getting complex and slow.</p>
<p>And if you have multiple deployment environments (production, staging, beta,
etc), it can get tricky for users as well. They will maybe have to do all this
complicated setup on a testing environment, and then redo everything again on
production once things are deployed. Ugh, it's getting painful.</p>
<p>What to do?</p>
<h2>Your admin interface is configuration</h2>
<p>When I was learning how to program in college, I quickly developed some sort of
taste / habit for most of the code I'd write: I would start with a hard-coded
hash table with configuration at the top of the module file, then a bunch of
functions under that, and at the very bottom there would be some main-like code
that would drive the execution and use the configuration.</p>
<p>A lot of what I wrote back then was PHP, so reducing it to a minimal example, it looked to something like this:</p>
<div class="highlight"><pre><span></span><code><span class="cp"><?php</span>
<span class="nv">$config</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span>
<span class="s2">"items"</span> <span class="o">=></span> <span class="k">array</span><span class="p">(</span>
<span class="s2">"apple"</span> <span class="o">=></span> <span class="k">array</span><span class="p">(</span><span class="s2">"count"</span> <span class="o">=></span> <span class="mi">2</span><span class="p">,</span> <span class="s2">"description"</span> <span class="o">=></span> <span class="s2">"Apples for baking a pie"</span><span class="p">),</span>
<span class="s2">"banana"</span> <span class="o">=></span> <span class="k">array</span><span class="p">(</span><span class="s2">"count"</span> <span class="o">=></span> <span class="mi">1</span><span class="p">,</span> <span class="s2">"description"</span> <span class="o">=></span> <span class="s2">"Banana for quick dessert"</span><span class="p">),</span>
<span class="s2">"tomato"</span> <span class="o">=></span> <span class="k">array</span><span class="p">(</span><span class="s2">"count"</span> <span class="o">=></span> <span class="mi">3</span><span class="p">,</span> <span class="s2">"description"</span> <span class="o">=></span> <span class="s2">"Tomatoes for a salad"</span><span class="p">),</span>
<span class="p">)</span>
<span class="p">);</span>
<span class="k">function</span> <span class="nf">generate_table</span><span class="p">(</span><span class="nv">$items</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$out</span> <span class="o">=</span> <span class="s2">"<table></span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span>
<span class="nv">$out</span> <span class="o">.=</span> <span class="s2">"<th><td>Name</td><td>Count</td><td>Description</td></th></span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span>
<span class="k">foreach</span><span class="p">(</span><span class="nv">$items</span> <span class="k">as</span> <span class="nv">$name</span> <span class="o">=></span> <span class="nv">$it</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$out</span> <span class="o">.=</span> <span class="s2">"<tr>"</span><span class="p">;</span>
<span class="nv">$out</span> <span class="o">.=</span> <span class="s2">"<td>"</span> <span class="o">.</span> <span class="nv">$name</span> <span class="o">.</span> <span class="s2">"</td>"</span><span class="p">;</span>
<span class="nv">$out</span> <span class="o">.=</span> <span class="s2">"<td>"</span> <span class="o">.</span> <span class="nv">$it</span><span class="p">[</span><span class="s2">"count"</span><span class="p">]</span> <span class="o">.</span> <span class="s2">"</td>"</span><span class="p">;</span>
<span class="nv">$out</span> <span class="o">.=</span> <span class="s2">"<td>"</span> <span class="o">.</span> <span class="nv">$it</span><span class="p">[</span><span class="s2">"description"</span><span class="p">]</span> <span class="o">.</span> <span class="s2">"</td>"</span><span class="p">;</span>
<span class="nv">$out</span> <span class="o">.=</span> <span class="s2">"</tr></span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="nv">$out</span> <span class="o">.=</span> <span class="s2">"</table></span><span class="se">\n</span><span class="s2">"</span><span class="p">;</span>
<span class="k">return</span> <span class="nv">$out</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">echo</span> <span class="nx">generate_table</span><span class="p">(</span><span class="nv">$config</span><span class="p">[</span><span class="s2">"items"</span><span class="p">]);</span>
</code></pre></div>
<p>I remember that my friend Valdir, with whom I hanged out all the time, after I showed him some code I was working on, he told me: "dude, I know a piece of code is from you when I see a big array of configuration in the beginning!". He was teasing me, of course, we had a laugh, and I remember feeling kind of proud of it! <em>"Yeah, this is my thing!"</em></p>
<p>There were a bunch of things that I liked about this:</p>
<ol>
<li>
<p>I had one central place to put all the "knobs" that determined how the program behave. That's pretty neat, if I came back later to code that I had written before, I didn't need to read through the code to figure out where to tweak some parameter: I would go directly to my configuration array.</p>
</li>
<li>
<p>I could quickly extend the configuration (copy and paste, modify, tap tap tap...), and use my text editor features and my growing <a href="https://www.vim.org">vim</a> skills. Working on vim is addictive: I still code on it to this day, even after trying lots of other editors and IDEs (<a href="https://github.com/eliasdorneles/dotfiles">and my configuration files are on Github, if you're curious</a>).</p>
</li>
<li>
<p>I could easily add new knobs and extend the model as needed, sometimes by only changing the type of structure: need to add more details to some value in one place? Replace the scalar variable and turn it yet into an array, then in the code type-check and do the right thing if it's an array or scalar.</p>
</li>
</ol>
<p>At the time I was doing it mostly out of intuition, I don't remember having
clearly stated why I like to do it like this back then. But I like to think
that the young programmer I was, in his own way, felt already the need to
come up with something of a clean architecture.</p>
<p>Though I'd probably tell you off if you'd tell me something like that, back
then I was pretty rebellious and I hated jargon that wanted to sound important
like "architecture", "layers". I only trusted code that I could read and run.
I had absorbed a bit too much that phrase from Linus Torvalds, <em>"talk is cheap,
show me the code"</em>.</p>
<p>If you had sent me the link to a <a href="https://blog.cleancoder.com/uncle-bob/2011/11/22/Clean-Architecture.html">blog post by Robert Martin defending clean
architecture</a>,
I would scoff.</p>
<p>But, deep down, I was working my way into those ideas. Years later, when I was ready,
I read folks like Martin Fowler, Robert Martin, Kent Beck, and was like "yes, yes!"</p>
<p>Okay, I like that I showed you some PHP code even though you, dear reader, are most likely a lover of Python, but I will stop digressing and get to the point.</p>
<p>The first point is: every big enough well-structured program has need of some form of configuration.</p>
<p>That is, structured information that some power user may need change from time to time. Some values are more stable than others, some almost never change, some are specific to a deployment environment, etc. It's usually not truly programming code, but it can be, or it can contain code bits. And if it's kept in text files, it starts looking a lot like code, and you can use text editors, with syntax highlighting and automatic checks.</p>
<p>The second point, and this is the important one, is that you can turn some of
your admin interface into configuration files, and let your internal power
users use their text editor to copy and paste, and have their fix of
dopamine when they write "code" and it works!</p>
<p>And that's where YAML comes in!</p>
<p>There is a lot to gain from using well-structured YAML files for the more
stable bits of admin configuration.</p>
<p>Put the files somewhere where your staff users can access and change them, for
example, a dedicated Git repository, or something like an S3 bucket -- this way
you can even track history for free, no need to implement anything fancy.</p>
<p>Then, you can either sync the files with the database, or make your system read
directly from S3, or whatever suits better your system.</p>
<h2>YAML is powerful and human readable</h2>
<p>Of the most commonly available configuration file formats, YAML is the one that
has the best combination of tooling support, power and readability.</p>
<p>In my current job, I will sometimes draft some YAML together with the product
folks who can immediately understand what it means, and later even write YAML
on their own. That YAML draft becomes a spec once everyone is happy with it,
and feeds right into the implementation. In a way, it's almost like it would
answer the programmer who would say: <em>"talk is cheap, show me the code"</em>.</p>
<p>It's widely supported, has plenty of tooling support, and if you've never done
any YAML, you may be surprised that it has even some <a href="https://www.netways.de/en/blog/2019/11/21/gitlab-ci-yaml-write-less-with-anchors-extends-and-hidden-keys/">reuse
features</a>,
so that I don't need to repeat myself, unless if I so desire.</p>
<p>And it's not hard to learn, you can learn the basics in Y minutes:
<a href="https://learnxinyminutes.com/docs/yaml/">https://learnxinyminutes.com/docs/yaml/</a>.
Of course you won't do this right now, you'll learn as you go when you need it,
on your rhythm, and that's totally fine.</p>
<p>The only kinda bad thing about using YAML is that, depending on your parser
implementation, sometimes you might run into some confusing error messages for
some silly syntax errors, which is <strong>VERY</strong> annoying. As YAML is
indentation-based (like Python), there are some corner cases for which it's
tricky to handle the error with a clear error message -- oh well.</p>
<p>But most of the time it works correctly, and the value that it brings overcomes
this by far. Plus, the tooling will get better and better, and perhaps more
importantly, people get better at avoiding mistakes even more quickly, so it's
fine.</p>
<h2>YAML inspiration</h2>
<p>The DevOps folks have known about the power of YAML for quite a while, plenty of DevOps tools
use YAML for its configuration.</p>
<p>One great example is <a href="https://docs.gitlab.com/ee/ci/quick_start/#create-a-gitlab-ciyml-file">the Gitlab CI
configuration</a>
which is all YAML-based, which is a great inspiration. They've actually kind of extended
YAML supporting "include" features and other things.</p>
<p>Someone did a round up of <a href="https://octopus.com/blog/state-of-config-file-formats">some common formats used for configuration
here</a>, mostly to explain
why Hashicorp went out to develop <a href="https://github.com/hashicorp/hcl">their own language</a> to use
in Terraform, which is actually quite cool, but not really usable for anything other at this point.</p>
<p>A non-DevOps example: a French startup called Papernest <a href="https://medium.com/papernest/papercraft-le-secret-des-po-de-papernest-pour-sortir-des-features-sans-une-seule-ligne-de-code-f5b85de97202">has essentially built
an internal CMS based on
YAML</a>,
with AB-testing support and all. I specially like how they came up with a neat
way of representing nested AND/OR conditions that you can see on one of the
screenshots, something which is <a href="https://ux.stackexchange.com/questions/11177/good-solutions-for-boolean-filter-with-sub-conditions">notably hard to come up with a good user
interface
for</a>,
<a href="https://ux.stackexchange.com/questions/1737/intuitive-interface-for-composing-boolean-logic">even for
Apple</a>.</p>
<p>Okay, I think I said everything I wanted to say, let's stop here!</p>
<p>Aaaand, I've managed to write a blog post about YAML with zero YAML snippets on it, only PHP, haha!</p>
<p>I'm off, have a good one, folks!
Have fun coding, or whatever it is you like to do! =)</p>Em busca de conteúdo francófono2019-01-25T23:38:00+01:002019-01-25T23:38:00+01:00Elias Dornelestag:eliasdorneles.com,2019-01-25:/2019/01/25/em-busca-de-conteudo-francofono.html<p>Faz pouco mais de um ano que estou morando na França, e ainda estou
descobrindo onde encontrar bom conteúdo francófono na internet.</p>
<p>O Netflix tem vários filmes e algumas séries, mas acho que poderia melhorar
muito o catálogo francófono. Quando eu estava no Brasil não haviam muitas
opções, e o …</p><p>Faz pouco mais de um ano que estou morando na França, e ainda estou
descobrindo onde encontrar bom conteúdo francófono na internet.</p>
<p>O Netflix tem vários filmes e algumas séries, mas acho que poderia melhorar
muito o catálogo francófono. Quando eu estava no Brasil não haviam muitas
opções, e o catálogo é melhor estando aqui na França, mas ainda deixa muito a
desejar.</p>
<p>Ainda bem que tem bastante coisa de qualidade na internet de graça! :)</p>
<h2>Vídeos</h2>
<p><a href="https://arte.tv">arte.tv</a> é o site duma empresa de televisão franco-alemã que
tem uma programação muito boa. Frequentemente séries inteiras estão disponíveis
de graça (por um tempo limitado).</p>
<h3>No Youtube</h3>
<p>Se você está fora da França, você pode assistir <a href="https://www.youtube.com/channel/UCXzt21wguxoJGo7TFBXNRgw">a série Kaamelott inteira </a> -- é muito engraçada, um humor bem francês.</p>
<p>Eu curto muito o teatro de improviso, e no <a href="https://www.youtube.com/user/Canalimpro">Canal
Impro</a> existem vários espetáculos
formato longo disponíveis inteiros -- simplesmente fantástico!</p>
<p>Existem também outras mini-séries legais, com episódios curtos:</p>
<ul>
<li><a href="https://www.youtube.com/user/bref">Bref</a> - bref, é a história dum cara</li>
<li><a href="https://www.youtube.com/channel/UCYx7aAgyuFvpESh9YGKNsXg">Serge le Mytho</a> -- história de um mitomano, o ator é um improvisador conhecido.</li>
</ul>
<p>Tem <a href="https://www.senscritique.com/liste/Le_merveilleux_monde_de_Youtube/715414">uma lista grande de séries que se pode achar no Youtube,
mas que ainda não conferi</a>.</p>
<p>Por fim, não é uma série, mas um dos meu canais do Youtube francófonos favorito é o <a href="https://www.youtube.com/user/faireset2">Parole de Chat</a>.</p>
<h2>Quadrinhos</h2>
<p><a href="https://tumourrasmoinsbete.blogspot.com/">Tu mourra moins bête</a> é o blog da
autora <a href="https://fr.wikipedia.org/wiki/Marion_Montaigne">Marion de Montagne</a> que
faz umas paradas bem humoradas de divulgação científica. Recomendo muito!</p>
<p><a href="http://www.bouletcorp.com/">Boulet Corp</a> é o site onde o autor de quadrinhos
(BD, <strong>bande dessinée</strong>)
<a href="https://fr.wikipedia.org/wiki/Boulet_(auteur)">Boulet</a> publica suas notas
desde <strong>2004</strong>! Tem uma seção com links para vários outros blogs
de autores de BD também, que ainda não conheço muito (alguns não são muito
atualizados), mas vale dar uma olhada.</p>
<p>Se você gosta de quadrinhos e de desenhar, talvez curta também <a href="https://www.youtube.com/channel/UCpjg52rm6hnREqbn6msYcLg">o canal de um desenhista francês, com várias dicas de desenho, demonstrações e coisas do tipo</a>.</p>
<p>Voilà, c'est tout pour l'instant !</p>Cool Linux apps you might not know2019-01-25T23:03:00+01:002019-01-25T23:03:00+01:00Elias Dornelestag:eliasdorneles.com,2019-01-25:/2019/01/25/cool-small-linux-gui-tools.html<p><sup>Trying to ship the old blog post drafts</sup></p>
<p>Here are some cool Linux apps you might not know yet.</p>
<h3>sm -- or, screen message</h3>
<p><a href="https://packages.debian.org/sid/sm">sm</a> is a small app to display text big and fullscreen.</p>
<p>Simple as that.</p>
<h3>Flameshot</h3>
<p><a href="https://flameshot.js.org">flameshot</a> is an awesome app for making screenshots.</p>
<p>I've mapped my <kbd>PrintScr …</kbd></p><p><sup>Trying to ship the old blog post drafts</sup></p>
<p>Here are some cool Linux apps you might not know yet.</p>
<h3>sm -- or, screen message</h3>
<p><a href="https://packages.debian.org/sid/sm">sm</a> is a small app to display text big and fullscreen.</p>
<p>Simple as that.</p>
<h3>Flameshot</h3>
<p><a href="https://flameshot.js.org">flameshot</a> is an awesome app for making screenshots.</p>
<p>I've mapped my <kbd>PrintScr</kbd> key to launch <code>flameshot gui</code>.</p>
<h3>Play it slowly</h3>
<p><a href="https://29a.ch/playitslowly">Play It Slowly</a> is an app to play an audio or video slower (or faster), while keeping (or otherwise manipulating) the pitch.</p>
<p>If you're a musician, you can use this to play some audio slower to be able to focus more closely on a small piece of a song.</p>
<p>If you're a singer, you can use this to play a track in a tonality that suits your voice better, while keeping the same tempo.</p>
<h3>Solfege</h3>
<p><a href="https://www.gnu.org/software/solfege/">Solfege</a> is a tool for ear-training. You can use this to practice identifying intervals, rhythms, chords, scales, etc.</p>
<p>To be honest I never used it that much... It's a pretty cool piece of software
and I suppose it will appeal to people who are used to music notation.</p>Post Pycon blues2018-05-22T23:48:00+02:002018-05-22T23:48:00+02:00Elias Dornelestag:eliasdorneles.com,2018-05-22:/2018/05/22/post-pycon-blues.html<p>When I arrived at Cleveland's airport a few weeks ago to attend
<a href="https://us.pycon.org">Pycon</a>, the customs agent didn't know that
there was a tech conference happening in town.
I'm sure many other people knew something was going on, because
I was welcomed by a screen just after she checked my documents …</p><p>When I arrived at Cleveland's airport a few weeks ago to attend
<a href="https://us.pycon.org">Pycon</a>, the customs agent didn't know that
there was a tech conference happening in town.
I'm sure many other people knew something was going on, because
I was welcomed by a screen just after she checked my documents and let me in.
It was a nice gesture, and it surely put a smile on my tired sleepy face!</p>
<p><img alt="" src="https://eliasdorneles.com/images/hello_pycon_2018.jpg"></p>
<p>Pycon is a great conference, because it's really several events at the same
time, it goes a lot more than just people presenting talks. In fact I barely
watch any talk: since the talks are recorded and are available online very
quickly, I prefer to profit of the time there to just talk to people, see old
friends, make new ones, talk to my open source buddies and also harass
famous cool people asking them to take pictures with me!</p>
<p><img src="https://eliasdorneles.com/images/pycon_roomies.jpg" class="align-right"/></p>
<p>It was my third Pycon this year, and I feel already so at home with those
folks! Some of my dearest friends are people from the Python community, and I'm
grateful to have this opportunity to go see them in the same place every year!
Since I live far away from many of them, it is really great to be able to be
with them. The only difficult part is to manage splitting my time among them,
because I love them all -- and even if I'd love to take them all home with me,
I don't think my roommate would accept that.</p>
<p>Pycon is also a special time also because it's when I get to see <a href="https://pybee.org/community/team/">my cheerful
buddies who maintain BeeWare</a>, which have
welcomed me to the team about an year ago. This time I got to meet the awesome
<a href="https://twitter.com/danyeaw">Dan Yeaw</a> who I only knew from the online chat,
and is a super nice person (so nice in fact, that some people say that he is
Canadian... jk)! We had a booth in the space dedicated to open source projects,
where we had to explain several times that <a href="https://pybee.org">BeeWare</a> is not
really about an IDE (anymore). It's always fun being around these folks,
preaching the BeeWare word, sharing stories, and I always learn a lot from
them.</p>
<p><img alt="" src="https://eliasdorneles.com/images/beeware_not_an_ide.jpg"></p>
<p>One of my favorite things at Pycon are the open source sprints, which btw <a href="http://blog.zulip.org/2016/10/13/static-types-in-python-oh-mypy/">have
already been described as a
party</a>. This
is essentially, a bunch of people excited about open source getting together
and doing open source things: writing code, writing docs, trying out stuff, get
feedback from users trying out stuff, debug issues, discuss implementation
ideas, and more! I always come back full of ideas and positive thoughts from
this!</p>
<p>BeeWare sprints are specially cool because it's kind of a big deal when you get
your first pull-request merged in a project: basically, <a href="https://pybee.org/contributing/challenge-coins/">you get a coin as
acknowledgment for the
contribution</a> and everyone
applauds! This always feels great, I'm specially excited when people say this
is their first open source contribution ever! <a href="https://twitter.com/PyBeeWare/status/996482510992367616">This year the supply of coins
was finished in the second
day</a>, I guess we'll
have to be better prepared for next year.</p>
<p>Unfortunately this year I could stay only for two days of sprints, because I
had another event in NYC (where I also met some more dear friends, btw).
Still, I'm happy I could make it for some days, and we got quite a few bugs
fixed in <a href="https://pybee.org/voc">VOC</a> during that.</p>
<p>So yeah, Pycon is great, if you're in doubt if you would enjoy, you should just
go the next time! You don't even need to like Python that much to get a kick
out of it.</p>
<p>Thank you, Pycon, for bringing so much joy and for bringing together so many
people that I love. To all the organizers, volunteers and everyone: y'all rock!</p>
<p>Now I'll do my best to keep surviving without seeing y'all until next year!</p>
<p><img alt="" src="https://eliasdorneles.com/images/thankyou_pycon.jpg"></p>Meta-blogging2018-05-02T00:49:00+02:002018-05-02T00:49:00+02:00Elias Dornelestag:eliasdorneles.com,2018-05-02:/2018/05/02/meta-blogging.html<p>I've been wanting to write since a little while but whenever I sit to write a
post I end up on an endless yak-shaving of making small adjustments to the
blog. I know that if I wanted to optimize my blogging flow for writing
I should start using something like …</p><p>I've been wanting to write since a little while but whenever I sit to write a
post I end up on an endless yak-shaving of making small adjustments to the
blog. I know that if I wanted to optimize my blogging flow for writing
I should start using something like Medium, or maybe even go back to good-ol' Wordpress.</p>
<p>But I don't want to increase the exposure of my readership (who are these
people anyway??) to advertising, nor useless tracking, nor annoying pop-ups like "psst,
you should create an account to better read". As <a href="https://ramalho.org/wiki/doku.php?id=porque_cada_pessoa_deve_ter_seu_site_na_web">my wise friend Luciano
Ramalho says (in
Portuguese)</a>,
the Web is supposed to be decentralized and shouldn't be controlled by
half-a-dozen tech corporations with their opaque algorithms.</p>
<p>That's how it's like these days, you wanted to share rambling thoughts with the
world through a blog post, then you gotta choose a blogging platform, suddenly
that choice becomes a political statement. So much meta-cognition, it drives me
nuts sometimes... I just wanted to write!!</p>
<p>That's how I end up writing posts in Vim, which is okay for writing prose but
it just sucks if you want to add a picture to your post. I guess this explains
why my posts don't have much images these days.</p>
<p>I guess it is still worthwhile, because the blog is pretty snappy. Also, by not
using Medium/Wordpress/whatever, I don't see user stats, which means that I
don't know what posts people are accessing, I don't get comments, all those
"features" that these days would mostly just give me anxiety.</p>
<p>For some reason, I've been finding hard to write stuff in public again. I used
to be a lot braver before. Life happens, and I feel like I've grown a bit
cynical, and maybe the "hopeful ramble" in the blog title isn't so hopeful
anymore. And even if a lot happened in my life over the recent years and
sometimes I think it could be good to share, I don't really feel like writing
about it. It's like, I want to keep them mine.</p>
<p>I also feel like I've become increasingly self-conscious about writing over the
recent years, which kinda pisses me off. "Stop editing, just write!", a brain
thread of thought shouts to another. "But the fear is there for a reason"
another brain thread jumps in, which gets "just worry about it later!" shouted
back from first thread.</p>
<p>Things used to be simpler.</p>
<p>I figured out some time ago that <a href="http://www.bbc.com/news/health-34039054">I have more difficulty to visualize things
than the average person</a>. Since then,
I've grown even more fond of the technique of writing to clear my thoughts.
It's possibly useful to many people, considering we're all getting addicted to
our screens and shit, but I realize that it's probably more relevant for some
than it is for others.</p>
<p>In any case, narration seems to be an important tool for me. My memory is more
like an audio-book than a movie. Or maybe an audio-book with an accompanying
comic book with blurry drawings. It sort of blew my mind when I learned that
aphantasia was a thing, and I keep remembering things that I seem to have
experienced very differently than other people because of it and I didn't
really understand it at the time.</p>
<p>Anyway, that's why I like writing. Someone already said "if you're not writing,
you're only thinking that you're thinking", and it rings a bell for me. It's
obviously not true (you can think in many ways), but it does feel like that in
my case, clear thinking usually needs writing.</p>
<p>Okay, enough writing about writing. Nobody really cares. (BTW, see what I mean
about the self-consciousness?)</p>
<p>Hopefully next time I'll have something interesting to say. Cya!</p>Urwid is great!2017-04-21T22:09:00+02:002017-04-21T22:09:00+02:00Elias Dornelestag:eliasdorneles.com,2017-04-21:/2017/04/21/urwid-is-great.html<p>Ever since I started using the awesome <a href="https://pypi.python.org/pypi/pudb">pudb debugger for Python
programs</a> I've been curious about the <a href="http://urwid.org/">urwid
library</a>, an user interface library for console-based
applications that the debugger uses. The <a href="http://urwid.org/examples/index.html">examples in the
gallery</a> are just gorgeous!</p>
<p>So last week I decided I would write a console-based game and …</p><p>Ever since I started using the awesome <a href="https://pypi.python.org/pypi/pudb">pudb debugger for Python
programs</a> I've been curious about the <a href="http://urwid.org/">urwid
library</a>, an user interface library for console-based
applications that the debugger uses. The <a href="http://urwid.org/examples/index.html">examples in the
gallery</a> are just gorgeous!</p>
<p>So last week I decided I would write a console-based game and learn Urwid in the process.
I decided to implement a <a href="https://en.wikipedia.org/wiki/Patience_(game)">Solitaire clone (specifically, the Klondike form)</a>.
I thought it would be fun to draw the cards using the <a href="https://en.wikipedia.org/wiki/Box-drawing_character">box-drawing characters</a> and <a href="https://en.wikipedia.org/wiki/Playing_cards_in_Unicode">card symbols</a> available in Unicode.</p>
<p>Here is a screenshot of the final game:</p>
<p><img alt="Screenshot showing usolitaire" src="https://raw.githubusercontent.com/eliasdorneles/usolitaire/master/screenshot-usolitaire.png"></p>
<p>Before starting to code, I explored the library a bit in the shell, following <a href="http://urwid.org/tutorial/index.html">the examples from the tutorial</a>.
I also did <a href="https://raw.githubusercontent.com/eliasdorneles/usolitaire/c18b4643bcd20cf53705a16de6072f2d1e766a43/PLAN.txt">some planning</a>, working out how to draw the game elements so that it would fit a 40x80 characters terminal window.</p>
<p>Then it was time to start coding, I started by trying to write something that I could put in the screen, a <a href="http://urwid.org/manual/widgets.html">custom widget</a> to represent a card.</p>
<p>After reading about widget layouts and sizings, I thought I wanted a fixed size widget, but my attempts to write one were hard to use, I kept running into <a href="https://github.com/urwid/urwid/wiki/FAQ#what-does-the-attributeerror-xxx-object-has-no-attribute-rows-error-mean">errors that happen when you try to use a fixed widget with things that expect something else</a>.</p>
<p>I was finally able to do it after reading more carefully the <a href="http://urwid.org/manual/widgets.html#custom-widgets">documentation about custom widgets</a> and figured it was easier to use the <code>urwid.WidgetWrap</code> class around a <code>urwid.Text</code> widget drawing the card using line-breaks to break the content.</p>
<p>Overall I found the library nicely documented and very well designed.</p>
<p>I kept running into those errors related to the sizing mode later on, so I had to become a bit more acquainted with the widgets I was using to know if they were box-sizing or flow-sizing mode. I wonder if there is an easier way of dealing with those.</p>
<p>I'm really liking to play with this library, I think I'll try more stuff with it soon.</p>
<p>If you want to play the game, you can install it with:</p>
<div class="highlight"><pre><span></span><code>pip install usolitaire
</code></pre></div>
<p>The <a href="https://github.com/eliasdorneles/usolitaire">source code is on Github</a>.</p>Lazy evaluation as alternative to state machines, maybe2017-03-27T22:13:00+02:002017-03-27T22:13:00+02:00Elias Dornelestag:eliasdorneles.com,2017-03-27:/2017/03/27/lazy-evaluation-as-alternative-to-state-machines.html<p>Some days ago I read <a href="http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines">this nice article talking about co-routines as an
alternative to state
machines</a>.</p>
<p>The most popular use case for co-routines in Python has been asynchronous I/O,
and there are a bunch of Python things that use them (like
<a href="https://twistedmatrix.com">Twisted</a>, <a href="http://www.tornadoweb.org">Tornado</a> and
the standard library module …</p><p>Some days ago I read <a href="http://eli.thegreenplace.net/2009/08/29/co-routines-as-an-alternative-to-state-machines">this nice article talking about co-routines as an
alternative to state
machines</a>.</p>
<p>The most popular use case for co-routines in Python has been asynchronous I/O,
and there are a bunch of Python things that use them (like
<a href="https://twistedmatrix.com">Twisted</a>, <a href="http://www.tornadoweb.org">Tornado</a> and
the standard library module
<a href="https://docs.python.org/3/library/asyncio.html">asyncio</a> which appeared in
Python 3.4).</p>
<p>Apart from the async stuff, I find quite hard to think up use cases for
co-routines, they mostly look like complicated stuff that smart people have a
lot of trouble to make it useful.</p>
<p>So I was curious about this idea of using co-routines as alternative for <a href="https://en.wikipedia.org/wiki/Finite-state_machine">state
machines</a>, because state
machines are kind of everywhere, even if not always explicitly.</p>
<p>I've seen a few other examples that kinda made sense, like David's <a href="http://www.dabeaz.com/coroutines/pyos8.py">scheduler
for cooperative tasks</a>, and a
discrete event simulation in the book <a href="http://shop.oreilly.com/product/0636920032519.do">Fluent
Python</a> by <a href="https://twitter.com/ramalhoorg">Luciano
Ramalho</a>, but these still seem a bit far away
for me.</p>
<p>So I decided to test out for myself reimplementing some simple state
machine as a co-routine and see how it goes.</p>
<h2>Are co-routines an alternative to state machines?</h2>
<p>To try out the idea, I decided to write a small program using a state machine,
and then write a co-routine version of it. I decided to implement a naive
program to strip out C-style comments.</p>
<p>I must say that this is not production code, it ignores the case of comments
inside of a string (as in <code>'/**/'</code> for the sake of simplicity). I only wrote
this to explore the idea of alternatives to state machines.</p>
<p>Here is a diagram of the state machine:</p>
<p><center>
<img alt="Picture with diagram of Finite State machine" src="https://eliasdorneles.com/images/fsm_strip_comments.png">
</center></p>
<p><a href="https://github.com/eliasdorneles/lazy-eval-gt-state-machines/blob/master/001_state_machine.py">Here is the state machine implementation</a>.</p>
<p>It was fairly straightforward to implement, but the code ends up a bit verbose.</p>
<p>Next, I went on and wrote <a href="https://github.com/eliasdorneles/lazy-eval-gt-state-machines/blob/master/002_coroutine.py">the co-routine version</a>, and didn't really like the result.
First of all, I find a bit cumbersome having to write the sink and build the driving code,
I thought: "why can't I just use the function? what if I want to do something
else than just print, do I have to write a sink-like code every time?"</p>
<p>After mulling for a bit, I realized that the most important gain from the
co-routine code was being able to "pause execution", so I figured I could write
a generator function that would consume the input lazily. While attempting
to do that, I realized I don't even need it to be a generator, it can
be just a regular function that will consume the input lazily and
return the full results.</p>
<p>And <a href="https://github.com/eliasdorneles/lazy-eval-gt-state-machines/blob/master/004_imperative_final.py">that's what I did, and decided that I like this code more than the co-routine version</a>.
I think it allows you to skip thinking about the explicit states when writing
the code, it's lazy and it's easy to use (just a regular function).</p>
<p>I'm not sure if it's better than the state machine version, though,
because I think to read it and understand you sort of have to build a
mental model of the states in your head. So it seems easier to write,
but may be tougher to read.
I think for state machines with high number of states this would not be
good for maintainability, and you'd probably want have a diagram.</p>
<p>I also had <a href="https://github.com/eliasdorneles/lazy-eval-gt-state-machines/commit/458fb7e124dff3bb06a9f61b62453507ad0c3d75">a bug on the first
implementation</a>,
which I only noticed when writing this blog post and <a href="https://github.com/eliasdorneles/lazy-eval-gt-state-machines/blob/master/diagram.dot">creating the state
machine
diagram</a>
and then had to go back and <a href="https://github.com/eliasdorneles/lazy-eval-gt-state-machines/commit/0bb8092a7d7b80aae34ef95af1334657ffd04ff5">fix it in the other implementations</a>.
Fixing the bug was a lot easier for the state machine implementation.</p>
<h2>Conclusions, or, how I feel about this</h2>
<p>State machines are complicated, but they're very useful. Even if it takes some
effort to understand them, I feel it's still less effort than co-routines.</p>
<p>Co-routines are also complicated, I find they demand too much cognition
to work with and can be harder to debug than regular state machine code.</p>
<p>Combining lazy evaluation and Python functions probably work better as an
alternative of state machines than co-routines, because they give you the
benefits without most of the drawbacks.</p>
<p>I'm not sure if they're as much powerful nor I'm convinced that the code is
more maintainable, but for some state machines it may be very expressive.</p>
<p>Also, <a href="https://github.com/eliasdorneles/lazy-eval-gt-state-machines/blob/master/005_pro.py">regular expressions are awesome</a>. =)</p>Pybee is awesome2016-10-28T14:28:00+02:002016-10-28T14:28:00+02:00Elias Dornelestag:eliasdorneles.com,2016-10-28:/2016/10/28/pybee-is-awesome.html<p>I've recently discovered the <a href="https://beeware.org">BeeWare project, also known as pybee</a>, and
it's bloody awesome.</p>
<p><center>
<a href="https://beeware.org">
<img src="https://beeware.org/static/images/brutus-270.png" alt="BeeWare logo" width="150">
</a>
</center></p>
<p>I had stumbled upon it before at Pycon US earlier, they had a booth set up
and their website said "BeeWare, the IDEs of Python".</p>
<p>I didn't gave much attention at it at first, because I've …</p><p>I've recently discovered the <a href="https://beeware.org">BeeWare project, also known as pybee</a>, and
it's bloody awesome.</p>
<p><center>
<a href="https://beeware.org">
<img src="https://beeware.org/static/images/brutus-270.png" alt="BeeWare logo" width="150">
</a>
</center></p>
<p>I had stumbled upon it before at Pycon US earlier, they had a booth set up
and their website said "BeeWare, the IDEs of Python".</p>
<p>I didn't gave much attention at it at first, because I've kinda given up on
IDEs some time ago. Every now and then I try Pycharm (which seems to be one of
the best UI for Python development out there) and always end up getting back to
Vim. An open source replacement for Pycharm definitely sounded cool, but still
didn't seem much more than a bunch of developers tools born out of yak-shaving.</p>
<p>However, while there is some fun yak-shaving involved, it's just a teeny tiny
part of the picture.</p>
<p><a href="https://beeware.org/project/overview/">BeeWare is about bringing to people the power of computing</a>.</p>
<p>It's about enabling people who learned a little bit of Python programming to
build something for their own needs, using the devices and environments they're
already using now. That means smartphones, tablets and web browsers.</p>
<p>Sure, professional programmers can dive into new programming languages and
environments to be able to build a nice native app. But professional
programmers are a tiny part of world population.</p>
<p>Many people learn just enough of programming to solve a problem. And Python is
a great language for that, because with just-enough-Python you can already do
tons of stuff.</p>
<p>Many people in the Python community aren't working as professional developers,
they just use Python to solve different kinds of human problems.</p>
<p>BeeWare will give these people the power of building stuff to show to their friends.</p>
<p>And of course, this will be empowering for professional developers as well!</p>
<p>I love Python, but the truth nowadays is that if I want to do something that my
family and friends would use, chances are that I'd be doing more JavaScript than Python.
Because that's the thing that I know how to program for that would be easily accessible
from the devices that they're using all the time.</p>
<p>That's why this project is such a big deal.</p>
<p>I myself can't wait to be able to use this stuff!</p>
<p>You can do some things already, see <a href="https://www.youtube.com/watch?v=RisCgSIWwLA">a demo video
here</a> and <a href="https://gist.github.com/freakboy3742/7beb22c587e57240610777a44af645d8">the code used for
it</a>.</p>
<p>This is just a proof-of-concept, you can see in the code that it's still using
different codebases for each target platform. There is still work to be done
until getting to the point of building apps for all platforms from the same
codebase, but the foundation is there.</p>
<p>If you love Python and are looking for an open source project to contribute,
consider the <a href="https://beeware.org/contributing/">BeeWare project</a>.</p>
<p>It's got a wonderful mission, it's welcoming to beginners and there's plenty
of work to do. You'll be helping to build the future of Python.</p>
<p>Go watch the video of the talk <a href="https://beeware.org/community/resources/python-all-the-things/">Python All the Things</a>, presented at Pycon
Australia by the <a href="https://beeware.org/community/team/">delightful Russell Keith-Magee who founded the BeeWare
project</a>, get excited and get to work! =)</p>On getting productive with Git2016-06-19T00:29:00+02:002016-06-19T00:29:00+02:00Elias Dornelestag:eliasdorneles.com,2016-06-19:/2016/06/19/on-getting-productive-with-git.html<p>I remember the first time I submitted a pull request in GitHub and some
reviewer asked me to <a href="https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Squashing-Commits">squash the
commits</a>.
I had no idea what they were talking about. I didn't have any friends who knew
Git, I was pretty much a noob on Git and GitHub. It's easy …</p><p>I remember the first time I submitted a pull request in GitHub and some
reviewer asked me to <a href="https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Squashing-Commits">squash the
commits</a>.
I had no idea what they were talking about. I didn't have any friends who knew
Git, I was pretty much a noob on Git and GitHub. It's easy to forget how scary
this stuff can be for someone just starting out with their first open source
contribution.</p>
<div class="figure align-right" style="width: 250px">
<img src="https://eliasdorneles.com/images/confused.png">
<p class="caption">
First-timer OSS contributor asked to rebase and squash commits
</p>
</div>
<p>It took me several weeks to figure out the whole thing because I was so afraid
of messing up. And in the end the code didn't even get merged.</p>
<p>I never forgot my frustration during this, which is why today I avoid as much
as possible to ask for someone to rebase their code in a pull request, unless I
can pair with them and show how to do it.</p>
<p>Well, nowadays <a href="https://help.github.com/articles/about-pull-request-merge-squashing/">GitHub allows a maintainer to squash commits when
merging</a>,
which is pretty cool. However, this isn't a task that's particularly hard to
do. When you have someone else to show you how, you pick it up real fast. It's
just a bit scary when you're on your own.</p>
<p>I've found there are many little things like this with Git. Git is a fine tool
for collaborating on software development and many open source developers would
find hard to use any other thing.</p>
<p>However, there is all this learning curve you must go through until you're
finally actually productive with it. When you're just starting to use it, this
XKCD comic is very real:</p>
<p><a href="https://xkcd.com/1597">
<img src="https://imgs.xkcd.com/comics/git.png" class="align-center">
</a></p>
<p>You want to get stuff done, you don't want to be spending cognition on your
version control tool. With Git, it takes a little while to get to a point where
you don't need to think much about it, at least when you're collaborating on a
project with many different people, as is the case in many open source
projects.</p>
<p>I want to share with you a couple things I learned in order to get productive
with Git, in the hopes that it will ease your own learning curve and get you
productive quicker. This won't be a Git tutorial, it's more like a booster of
your own Git learning. These are things that helped me to learn and use Git
better. If you want a tutorial, <a href="https://try.github.io">this is a cool one</a>.</p>
<p>I'm far from a Git expert, most of what I learned was while trying to get stuff
done, usually after googling for <em>"how to do X in Git"</em>. I have trouble
understanding Git's help because it seems to be written for people that know Git
internals, using all this unfamiliar vocabulary. But I can get stuff done, and
you can too.</p>
<p>So, let's start! The first thing I want you to know is ...</p>
<h2>There is always a way to undo</h2>
<p>The fact that this isn't obvious and that undoing things in Git aren't
always straightforward, is one of the biggest reasons for the fear of messing up.
So, let's get rid of those fears first.</p>
<p>Almost always, there is a way to undo whatever you've done. This is true even
when you've used one of the power tools (<code>git rebase</code>) that rewrites the commit
history. As long as you haven't deleted your local repo, you can always get
back to a previous state.</p>
<h3>Undo a commit</h3>
<p>If you've committed and then realized that you didn't mean to,
don't worry, you can undo it with the following command:</p>
<div class="highlight"><pre><span></span><code>git undo-commit
</code></pre></div>
<p>This will undo the last commit, but will keep your files intact
so you won't lose any work.</p>
<p>Now, if you've just tried running that and it didn't work it's because I've
lied to you -- sorry! That command doesn't exist by default in Git, but it
should! In order to add it, run the following command:</p>
<div class="highlight"><pre><span></span><code>git config --global alias.undo-commit 'reset HEAD~1 --mixed'
</code></pre></div>
<p>This adds an alias, which is essentially a shortcut to another command.
Git aliases are very helpful, because that's how you tweak Git's complicated
command line interface to something that's actually usable. Aliases (and
Git's global configuration for your user) are stored in a <code>.gitconfig</code>
file in your user directory, which you can edit using your editor if you like.</p>
<p>In fact, you can even add an alias to add new aliases more easily, but this may
be getting out of hand... Anyway, later on, we'll see also how to use Bash
aliases and functions to further improve the workflow.</p>
<p>You can check <a href="https://github.com/eliasdorneles/dotfiles/tree/master/gitconfig">my personal
gitconfig</a>
(which contains the stuff I share here and more) if you're already familiar
with this stuff and came here only for the Git aliases.</p>
<p>You can use any other alias name that you prefer instead of <code>undo-commit</code>
there. Personally, I use just <code>undo</code> for this one.</p>
<h3>Undo adding a file to commit</h3>
<p>If you've added a file with <code>git add</code> that you didn't mean to,
you can undo it with:</p>
<div class="highlight"><pre><span></span><code>git undo-add
</code></pre></div>
<p>Again, this is only after you've added the proper alias with the following command:</p>
<div class="highlight"><pre><span></span><code>git config --global alias.undo-add 'reset --keep'
</code></pre></div>
<h3>Undo a rebase that went wrong</h3>
<p>If you've tried doing a rebase or some other command that rewrote the commit history
and you want to undo it, you can use something called the reference log (or, <code>reflog</code>).
Try running <code>git reflog</code> in a Git repository, you'll see something like this:</p>
<div class="highlight"><pre><span></span><code><span class="mf">26</span><span class="n">e15cf</span><span class="w"> </span><span class="n">HEAD</span><span class="err">@{</span><span class="mf">0</span><span class="err">}</span><span class="p">:</span><span class="w"> </span><span class="n">rebase</span><span class="w"> </span><span class="n">finished</span><span class="p">:</span><span class="w"> </span><span class="kr">return</span><span class="n">ing</span><span class="w"> </span><span class="kr">to</span><span class="w"> </span><span class="n">refs</span><span class="o">/</span><span class="n">heads</span><span class="o">/</span><span class="n">master</span>
<span class="mf">26</span><span class="n">e15cf</span><span class="w"> </span><span class="n">HEAD</span><span class="err">@{</span><span class="mf">1</span><span class="err">}</span><span class="p">:</span><span class="w"> </span><span class="n">pull</span><span class="w"> </span><span class="o">--</span><span class="n">rebase</span><span class="p">:</span><span class="w"> </span><span class="n">moving</span><span class="w"> </span><span class="n">basic</span><span class="w"> </span><span class="n">path</span><span class="w"> </span><span class="n">config</span><span class="w"> </span><span class="kr">to</span><span class="w"> </span><span class="err">~</span><span class="o">/</span><span class="mf">.</span><span class="n">profile</span><span class="w"> </span><span class="kr">to</span><span class="w"> </span><span class="n">work</span><span class="w"> </span><span class="n">with</span><span class="w"> </span><span class="n">gnome</span><span class="w"> </span><span class="n">apps</span>
<span class="n">f993d5c</span><span class="w"> </span><span class="n">HEAD</span><span class="err">@{</span><span class="mf">2</span><span class="err">}</span><span class="p">:</span><span class="w"> </span><span class="n">pull</span><span class="w"> </span><span class="o">--</span><span class="n">rebase</span><span class="p">:</span><span class="w"> </span><span class="n">checkout</span><span class="w"> </span><span class="n">f993d5cc3d6df6ce9f5c083ebf17d45b9c7e9130</span>
<span class="n">b517509</span><span class="w"> </span><span class="n">HEAD</span><span class="err">@{</span><span class="mf">3</span><span class="err">}</span><span class="p">:</span><span class="w"> </span><span class="n">pull</span><span class="p">:</span><span class="w"> </span><span class="n">Merge</span><span class="w"> </span><span class="n">made</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="err">'</span><span class="n">recursive</span><span class="err">'</span><span class="w"> </span><span class="n">strategy</span><span class="mf">.</span>
<span class="mf">29438</span><span class="n">f2</span><span class="w"> </span><span class="n">HEAD</span><span class="err">@{</span><span class="mf">4</span><span class="err">}</span><span class="p">:</span><span class="w"> </span><span class="n">commit</span><span class="p">:</span><span class="w"> </span><span class="n">moving</span><span class="w"> </span><span class="n">basic</span><span class="w"> </span><span class="n">path</span><span class="w"> </span><span class="n">config</span><span class="w"> </span><span class="kr">to</span><span class="w"> </span><span class="err">~</span><span class="o">/</span><span class="mf">.</span><span class="n">profile</span><span class="w"> </span><span class="kr">to</span><span class="w"> </span><span class="n">work</span><span class="w"> </span><span class="n">with</span><span class="w"> </span><span class="n">gnome</span><span class="w"> </span><span class="n">apps</span>
<span class="n">a000618</span><span class="w"> </span><span class="n">HEAD</span><span class="err">@{</span><span class="mf">5</span><span class="err">}</span><span class="p">:</span><span class="w"> </span><span class="n">clone</span><span class="p">:</span><span class="w"> </span><span class="n">from</span><span class="w"> </span><span class="n">git</span><span class="err">@</span><span class="n">github</span><span class="mf">.</span><span class="n">com</span><span class="p">:</span><span class="n">eliasdorneles</span><span class="o">/</span><span class="n">dotfiles</span><span class="mf">.</span><span class="n">git</span>
</code></pre></div>
<p>This is a log of every state of your files that is stored, which includes
when you commit changes, checkout branches, do rebases (with separate states
for every step of the rebase), merges and etc.</p>
<p>You can get back to any of those states, using the command below, replacing
<code>REFLOG_ENTRY</code> by the <code>HEAD@{index}</code> from the reflog for the state
you want to go back:</p>
<div class="highlight"><pre><span></span><code>git reset --hard REFLOG_ENTRY
</code></pre></div>
<p>Note that those numbers are counting backwards, they change every time you make
a change in the repo. You want to always run <code>git reflog</code> before going back,
to be sure you'll use the up-to-date reference.</p>
<p>Also, note that these logs are only stored locally, you'll lose them if you delete
your local repo.</p>
<hr>
<p>Alright, we're done covering undoing stuff. I hope now that you know how to
undo, you will feel more comfortable trying more stuff without the fear of
breaking things. The next tips will be a bit more random.</p>
<h2>Enable colors</h2>
<p>Your brain can parse this:</p>
<p><img src="https://i.imgur.com/OBOFz7A.png" width="400" class="align-center"></p>
<p>Much easier than this:</p>
<p><img src="https://i.imgur.com/ajXQxbA.png" width="400" class="align-center"></p>
<p>In case your Git output isn't showing colored output, configure it to do so:</p>
<div class="highlight"><pre><span></span><code>git config --global color.ui auto
</code></pre></div>
<p>Also, if you end up needing to do this, consider upgrading Git, this has been
the default for some time, together with many other nice usability
improvements.</p>
<h2>Preparing files to commit, the easy way</h2>
<p>I rarely run the command <code>git add FILENAME</code>.</p>
<p>I usually use short aliases to either <code>git add --update</code> or <code>git add --all</code>.</p>
<h3>Add only files that were edited, ignore new ones</h3>
<p>When you want to commit all files that you have edited,
ignoring any new files that may now be inside the repo
directory, do:</p>
<div class="highlight"><pre><span></span><code>git add -u
</code></pre></div>
<p>This is a shortcut to <code>git add --update</code>, which is the equivalent
of doing a <code>git add</code> on every modified file that were previously
committed.</p>
<p>It can also take a directory, you can ask Git to add only
files that were edited inside a directory:</p>
<div class="highlight"><pre><span></span><code>git add -u tests/
</code></pre></div>
<h3>Add all files, detecting file renames and deletes</h3>
<p>Git expects you to tell it when you rename or delete files. You can ask Git to
add all changes to be committed, including adding, deleting and renaming
files, using the command:</p>
<div class="highlight"><pre><span></span><code>git add --all
</code></pre></div>
<p>You can also give it a directory, so that Git only does this for the stuff under it:</p>
<div class="highlight"><pre><span></span><code>git add --all some_dir/
</code></pre></div>
<p>I use this so often that it deserved an alias:</p>
<div class="highlight"><pre><span></span><code>git config --global alias.aa 'add --all'
</code></pre></div>
<h2>Solve conflicts only once</h2>
<p>When you're merging or rebasing often, some conflicts keep reappearing,
specially when you're working temporarily on a branch. Instead of solving them
again manually every time, ask Git to do it automatically, by enabling
<a href="https://git-scm.com/docs/git-rerere"><code>rerere</code></a>:</p>
<div class="highlight"><pre><span></span><code>git config --global rerere.enabled true
</code></pre></div>
<p>The name <code>rerere</code> stands for "reuse recorded resolution", and that's exactly what
it does: it will record how you solved previous conflicts and next time it finds
the same conflict it will just apply your previous fix. This way, you won't need to
keep solving the same conflicts again and again and save a few brain cycles.</p>
<h2>Opening files in your editor</h2>
<p>I edit code in <a href="https://www.vim.org">Vim</a>.</p>
<p>But even if you don't, you might find useful these Bash functions and aliases
(taken from <a href="https://github.com/eliasdorneles/dotfiles/blob/master/bashrc">my <code>~/.bashrc</code> file</a>)
and tweak them to your needs:</p>
<div class="highlight"><pre><span></span><code><span class="nv">edit_modified_files</span><span class="ss">()</span>{
<span class="w"> </span><span class="mh">$ED</span><span class="nv">ITOR</span><span class="w"> </span>$<span class="ss">(</span><span class="w"> </span><span class="ss">(</span><span class="nv">git</span><span class="w"> </span><span class="nv">ls</span><span class="o">-</span><span class="nv">files</span><span class="w"> </span><span class="o">-</span><span class="nv">m</span><span class="w"> </span><span class="o">-</span><span class="nv">o</span><span class="w"> </span><span class="o">--</span><span class="nv">exclude</span><span class="o">-</span><span class="nv">standard</span><span class="c1">; git diff --cached --name-only --relative .) | sort | uniq)</span>
}
<span class="nv">edit_files_with_conflicts</span><span class="ss">()</span>{
<span class="w"> </span><span class="mh">$ED</span><span class="nv">ITOR</span><span class="w"> </span>$<span class="ss">(</span><span class="nv">git</span><span class="w"> </span><span class="nv">diff</span><span class="w"> </span><span class="o">--</span><span class="nv">name</span><span class="o">-</span><span class="nv">only</span><span class="w"> </span><span class="o">--</span><span class="nv">diff</span><span class="o">-</span><span class="nv">filter</span><span class="o">=</span><span class="nv">U</span><span class="ss">)</span>
}
<span class="nv">edit_recently_committed</span><span class="ss">()</span>{
<span class="w"> </span><span class="mh">$ED</span><span class="nv">ITOR</span><span class="w"> </span>$<span class="ss">(</span><span class="nv">git</span><span class="w"> </span><span class="k">show</span><span class="w"> </span><span class="o">--</span><span class="nv">name</span><span class="o">-</span><span class="nv">only</span><span class="w"> </span><span class="o">--</span><span class="nv">oneline</span><span class="w"> </span><span class="o">--</span><span class="nv">relative</span><span class="w"> </span>.<span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nv">egrep</span><span class="w"> </span><span class="o">-</span><span class="nv">v</span><span class="w"> </span><span class="s2">"^[a-z0-9]+ "</span><span class="ss">)</span>
}
<span class="nv">alias</span><span class="w"> </span><span class="nv">em</span><span class="o">=</span><span class="nv">edit_modified_files</span>
<span class="nv">alias</span><span class="w"> </span><span class="nv">ec</span><span class="o">=</span><span class="nv">edit_files_with_conflicts</span>
<span class="nv">alias</span><span class="w"> </span><span class="nv">er</span><span class="o">=</span><span class="nv">edit_recently_committed</span>
</code></pre></div>
<p>I came up with these functions when I realized how often I wanted to do open
the editor and load one of these set of files:</p>
<ol>
<li>the ones that are currently modified, so I can wrap it up for commit</li>
<li>the ones that have conflicts, so I can fix them</li>
<li>the ones that were in the last commit, so I can continue working on them</li>
</ol>
<p>This may or may not be useful to you, depending on how you use your editor.
In my case, I open and close vim often, sometimes in different terminals,
so this has been quite handy.</p>
<h2>Fetching code from a pull request (GitHub only)</h2>
<blockquote>
<p><strong>Update:</strong> <a href="https://github.com/immerrr">A friend</a> has pointed out that
another option is to <a href="https://gist.github.com/piscisaureus/3342247">add a configuration to have the PRs fetched
automatically</a>.</p>
</blockquote>
<p>If you maintain open source projects, you may like this one.</p>
<p>When you want to check out locally the changes introduced by
a pull request, in vanilla Git it's a bit of work (you have to add
a new remote, fetch from it and then checkout the branch). GitHub
allows you to skip adding a new remote, you can fetch the code
from a pull request into a new branch with only one command:</p>
<div class="highlight"><pre><span></span><code>git fetch origin pull/$PULL_REQUEST_ID/head:BRANCH_NAME
</code></pre></div>
<p>If you're like me, you'll be lazy to type (and memorize) all that too,
so here is an alias for doing that, paste it under the <code>[alias]</code> section
in your <code>~/.gitconfig</code>:</p>
<div class="highlight"><pre><span></span><code><span class="s s-Atom">fetch</span><span class="o">-</span><span class="s s-Atom">pr</span> <span class="o">=</span> <span class="err">"</span><span class="p">!</span><span class="nf">f</span><span class="p">(){</span><span class="s s-Atom">\</span>
<span class="p">[</span> <span class="o">-</span><span class="s s-Atom">z</span> <span class="s s-Atom">\</span><span class="err">"$</span><span class="mi">1</span><span class="s s-Atom">\</span><span class="err">"</span> <span class="p">]</span> <span class="s s-Atom">&&</span> <span class="p">{</span> <span class="s s-Atom">echo</span> <span class="nv">Usage</span><span class="o">:</span> <span class="s s-Atom">git</span> <span class="s s-Atom">fetch</span><span class="o">-</span><span class="s s-Atom">pr</span> <span class="nv">PULL_REQUEST_ID</span> <span class="p">[</span><span class="s s-Atom">new_branch_name</span><span class="p">];</span> <span class="s s-Atom">exit</span> <span class="mi">1</span><span class="p">;</span> <span class="p">};</span> <span class="s s-Atom">\</span>
<span class="s s-Atom">branch=</span><span class="err">$</span><span class="p">{</span><span class="mi">2</span><span class="o">:-</span><span class="s s-Atom">pr-</span><span class="err">$</span><span class="mi">1</span><span class="p">};</span> <span class="s s-Atom">\</span>
<span class="s s-Atom">git</span> <span class="s s-Atom">fetch</span> <span class="s s-Atom">origin</span> <span class="s s-Atom">\</span><span class="err">"</span><span class="s s-Atom">pull/</span><span class="err">$</span><span class="mi">1</span><span class="o">/</span><span class="s s-Atom">head</span><span class="p">:</span><span class="err">$</span><span class="s s-Atom">branch\</span><span class="err">"</span><span class="p">;</span> <span class="s s-Atom">\</span>
<span class="p">};</span> <span class="s s-Atom">f</span> <span class="err">"</span>
</code></pre></div>
<p>This alias is using a shell function to parameterize it.
If you run <code>git fetch-pr</code> it will show the help:</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">git</span><span class="w"> </span><span class="k">fetch</span><span class="o">-</span><span class="n">pr</span>
<span class="k">Usage</span><span class="err">:</span><span class="w"> </span><span class="n">git</span><span class="w"> </span><span class="k">fetch</span><span class="o">-</span><span class="n">pr</span><span class="w"> </span><span class="n">PULL_REQUEST_ID</span><span class="w"> </span><span class="o">[</span><span class="n">new_branch_name</span><span class="o">]</span>
</code></pre></div>
<p>Using this, to fetch the code from pull request #1234, you can do simply:</p>
<div class="highlight"><pre><span></span><code>git fetch-pr 1234
</code></pre></div>
<p>This will create a branch called <code>pr-1234</code> with the checked-out code.
If you want to name the branch, just provide yet another parameter:</p>
<div class="highlight"><pre><span></span><code><span class="nv">git</span><span class="w"> </span><span class="nv">fetch</span><span class="o">-</span><span class="nv">pr</span><span class="w"> </span><span class="mi">1234</span><span class="w"> </span><span class="nv">new</span><span class="o">-</span><span class="nv">branch</span><span class="o">-</span><span class="k">for</span><span class="o">-</span><span class="nv">pull</span><span class="o">-</span><span class="nv">request</span><span class="o">-</span><span class="mi">1234</span>
</code></pre></div>
<h2>Other things that might be helpful</h2>
<p><code>git stash</code> is an useful command to know: it sets aside your current changes,
so you can work in other stuff. Use <code>git stash pop</code> to get back the changes.
This is handy to switch to a different task, without having to copy files or
lose your current uncommitted progress.</p>
<p>I've also found useful to know how to use diffs & patches, including the diff
tools <code>git diff</code> & <code>git apply</code> and also the <code>patch</code> command-line tool. These
are helpful a few times, when you have to replay your work in another
repository.</p>
<p>If you like to do atomic commits (i.e., making each commit introduces a small
self-contained change), you will like the <code>git add -p</code> command. It starts an
interactive session, asking for each piece of the diff if you want to include
in the next commit or not.</p>
<p>You will also like the <code>git diff --cached</code> command, which shows the diff for
the stuff added to the index, i.e., the changes you're about to commit.</p>
<p>One tool that I've been meaning to learn is <a href="http://jonas.nitro.dk/tig/">tig</a>,
a console interface for Git. It has some nice features, like you can do <code>tig
grep</code> to search files and then hit <code>e</code> on top of a search result to open the
file in your editor in that exact place. I haven't adopted this tool fully
in my workflow, though, I'm still evaluating.</p>
<p>There is also this thing called <a href="http://www.git-legit.org">Legit</a>, a set of
extensions (used via aliases) created by <a href="https://twitter.com/kennethreitz">Kenneth
Reitz</a> (from <a href="https://www.python-requests.org">Python
Requests</a> and <a href="https://httpbin.org/">httpbin</a>
fame) which looks interesting. I have only recently started experimenting with
it, so I can't comment much. I know that Git deserves something like it. If you
use it, let me know how you like it.</p>
<p>Finally, you may also like this <a href="https://stackoverflow.com/questions/315911/git-for-beginners-the-definitive-practical-guide">StackOverflow thread with Git questions and
answers</a>.</p>
<p>That's all I had for now, folks!</p>You're not alone2016-04-19T19:19:00+02:002016-04-19T19:19:00+02:00Elias Dornelestag:eliasdorneles.com,2016-04-19:/2016/04/19/youre-not-alone.html<blockquote>
<p>I've shared this text almost as-is internally at @Scrapinghub, the company I work at. As it had a good response, I'm sharing it here after some minor editing. I wrote it mainly to my programmer friends, but many people will probably relate to it.</p>
</blockquote>
<p>Here are some things that I …</p><blockquote>
<p>I've shared this text almost as-is internally at @Scrapinghub, the company I work at. As it had a good response, I'm sharing it here after some minor editing. I wrote it mainly to my programmer friends, but many people will probably relate to it.</p>
</blockquote>
<p>Here are some things that I want to share with you:</p>
<p>If you’ve ever felt that you’re a mediocre developer at best, even though you show up and do your best everyday, you’re not alone.</p>
<p>If you’ve ever felt bad about not being nearly as productive as you’d want to, you’re not alone.</p>
<p>If you’ve ever thought that you will probably be fired eventually because you’re not as smart and accomplished as your peers and “someday they’ll figure that out”, you’re not alone.</p>
<p>If you’ve ever refrained from introducing an idea out of fear of being ridiculed or laughed at, you’re not alone.</p>
<p>If the thought ever crossed your mind that you’re a fraud waiting to be uncovered, that everyone is smarter and better and faster and more knowledgeable than you, I want to tell you that you’re not alone.</p>
<p>Most of us go through that at least at some point, sometimes every day. And the thing is, there <em>are</em> ways for us to overcome these feelings that, even if we don’t completely eliminate them, it help us to grow both personally and professionally.</p>
<p>I want to talk about these issues, because I believe this conversation is important for building our culture and we all can benefit from it.</p>
<h1>Scarcity culture</h1>
<p>There is this book titled <a href="https://www.goodreads.com/book/show/13588356-daring-greatly">Daring Greatly</a> which talks about the culture of scarcity that we’re living in, what’s dangerous about it and how we can deal with it.</p>
<p>Scarcity is this strong sense of lacking something, of never being good/smart/healthy/safe/successful/etc enough.</p>
<p>Quoting the book:</p>
<blockquote>
<p>Scarcity is the "never enough" problem. The word scarce is from the Old Norman French scars, meaning "restricted in quantity" (c. 1300). Scarcity thrives in a culture where everyone is hyperaware of lack. Everything from safety and love to money and resources feels restricted and lacking. We spend inordinate amounts of time calculating how much we have, want, and don't have, and how much everyone else has, needs, and wants.</p>
<p>What makes the constant assessing and comparing so self-defeating is that we are often comparing our lives, our marriages, our families, and our communities to unattainable, media-driven visions of perfection, or we're holding up our reality against our own fictional account of how great someone else has it.</p>
</blockquote>
<p>Never before we were so aware of how much we lack and how inadequate we are. If you’re like me, you will not have trouble relating to this. We have things like the Github timeline making us feel bad about not contributing much to open source, we obsess about StackOverflow points and similar rank systems, and when comparing to our more accomplished peers it’s easy to think that we are so little and don’t have anything to contribute.</p>
<p><a href="http://brenebrown.com">Brené Brown, the researcher who wrote the book</a> tells us that the formula of the scarcity culture is made of three components: shame, comparison and disengagement. This same dynamic can show up not only in the larger culture, but also in family, work or any other community.</p>
<p>She offers the following questionnaire as a starting point to start reflecting on these three components:</p>
<ol>
<li><strong>Shame:</strong> Is fear of ridicule and belittling used to manage people and/or to keep people in line? Is self-worth tied to achievement, productivity, or compliance? Are blaming and finger-pointing norms? Are put-downs and name-calling rampant? What about favoritism? Is perfectionism an issue?</li>
<li><strong>Comparison:</strong> Healthy competition can be beneficial, but is there constant overt or covert comparing and ranking? Has creativity been suffocated? Are people held to one narrow standard rather than acknowledged for their unique gifts and contributions? Is there an ideal way of being or one form of talent that is used as measurement of everyone else’s worth?</li>
<li><strong>Disengagement:</strong> Are people afraid to take risks or try new things? Is it easier to stay quiet than to share stories, experiences, and ideas? Does it feel as if no one is really paying attention or listening? Is everyone struggling to be seen and heard?</li>
</ol>
<p>Looking at the larger culture, my answer to most of these questions is <em>yes</em>. Watching the news and the social network feeds (specially at the moment of political turmoil we’re living here in Brazil), it’s <em>oh gosh, yes</em>!</p>
<p>Now, if that’s the situation of the larger culture, what if we want to build an organizational culture (in our family, in our work) that goes the opposite way to these cultural norms of scarcity? There will always be pressure from the larger culture, so how would that work?</p>
<p>Well, first of all we need awareness. Then it’s a matter of commitment and hard work, every day.</p>
<p>Quoting the book again:</p>
<blockquote>
<p>The counterapproach to living in scarcity is not about abundance. In fact, I think abundance and scarcity are two sides of the same coin. The opposite of “never enough” isn’t abundance or “more than you could ever imagine.” The opposite of scarcity is enough, or what I call Wholeheartedness. As I explained in the Introduction, there are many tenets of Wholeheartedness, but at its very core is vulnerability and worthiness: facing uncertainty, exposure, and emotional risks, and knowing that I am enough.</p>
</blockquote>
<p>Now, if we want to be vulnerable and cultivate worthiness, we really want the opposite of the conditions from those questions from before. This is the problem of a scarcity culture. It prevents us from taking risks, from facing uncertainty, from putting ourselves out there, from feeling that we belong.</p>
<p>When we ask a question, and when we try to answer a question, when we send out our work for review, review the work of someone else or when we get our own work reviewed, when we publish a post, give an opinion -- all these involve the exact kind of exposure and emotional risk we’re talking about here. And when we don’t feel we’re enough, we disengage because it feels too risky.</p>
<h1>Understanding shame</h1>
<p>Some things to know about shame:</p>
<ol>
<li>We all have it</li>
<li>We’re all afraid of talking about it</li>
<li>The less we talk about it, the more it can control us</li>
</ol>
<p>Quoting the book:</p>
<blockquote>
<p>There are a couple of very helpful ways to think about shame. First, shame is the fear of disconnection. We are psychologically, emotionally, cognitively, and spiritually hardwired for connection, love, and belonging. Connection, along with love and belonging (two expressions of connection), is why we are here, and it is what gives purpose and meaning to our lives. Shame is the fear of disconnection—it’s the fear that something we’ve done or failed to do, an ideal that we’ve not lived up to, or a goal that we’ve not accomplished makes us unworthy of connection. I’m not worthy or good enough for love, belonging, or connection. I’m unlovable. I don’t belong.</p>
<p>Shame is the intensely painful feeling or experience of believing that we are flawed and therefore unworthy of love and belonging.</p>
</blockquote>
<p>And by the way, as far as the brain is concerned, <a href="https://www.pnas.org/content/108/15/6270.abstract">shame and pain hurt the same way</a>.</p>
<blockquote>
<p>Shame is real pain. The importance of social acceptance and connection is reinforced by our brain chemistry, and the pain that results from social rejection and disconnection is real pain.</p>
</blockquote>
<p>It’s also important to distinguish shame from guilt, which can be understood as the difference between “I am bad” and “I did something bad”.</p>
<p>Guilt is more like: “I did something bad”. Guilt is not bad, because it’s something you understand that you did and you can change that. And if you feel guilty you will feel impelled to change. Guilt is what’s happening when we apologize for real and try to make amends. This is the kind of feeling that, if you’re a parent, you want your child to feel when doing something bad, so that they can change their behavior.</p>
<p>Shame is more like: “I am bad” or “I am not good”, and that’s much more dangerous. Shame is such a deep fear that when we feel it, our instinct is not to try to make amends -- unlike the positive outcome of guilt, shame’s influence is always destructive. If we do something bad, and instead of feeling guilt (e.g., thinking: “oops, I did something stupid”) we feel shame (thinking: “I’m such a stupid loser”), the instinct is to protect ourselves by blaming something or someone, rationalize our mistake, give a fake apology or simply hide.</p>
<p>There is no positive outcome for shame (at least not for unacknowledged shame). Brené Brown <a href="http://www.huffingtonpost.com/2013/04/18/brene-brown-shame-guilt-addiction-oprah_n_2966351.html">reports</a> that researchers have correlated shame with <a href="https://www.psychologicalscience.org/news/releases/shame-about-past-alcoholism-predicts-relapse-and-declining-health-in-recovering-alcoholics.html">addiction</a>, <a href="http://www.ncbi.nlm.nih.gov/pmc/articles/PMC3763505/">violence</a>, aggression, depression, eating disorders and bullying -- while guilt is inversely correlated to those. (the book has many pointers for this, but sadly most are books and academic papers not freely available -- I’m sharing some links at the end).</p>
<p>The good news, though, is that if we just start talking about shame, it diminishes. Just by being aware of it, and discussing it, we suddenly have more control of it. Such is the power of language.</p>
<h2>Building shame-resilience</h2>
<p>We can’t not have shame -- it’s just part of being human.</p>
<p>But we <em>can</em> learn to be shame-resilient.</p>
<p>Brown calls shame-resilience “the ability to practice authenticity when we experience shame, to move through the experience without sacrificing our values, and to come out on the other side of the shame experience with more courage, compassion, and connection than we had going into it. Shame resilience is about moving from shame to empathy—the real antidote to shame”.</p>
<blockquote>
<p>If we can share our story with someone who responds with empathy and understanding, shame can’t survive. Self-compassion is also critically important, but because shame is a social concept—it happens between people—it also heals best between people. A social wound needs a social balm, and empathy is that balm. Self-compassion is key because when we’re able to be gentle with ourselves in the midst of shame, we’re more likely to reach out, connect, and experience empathy.</p>
</blockquote>
<p>In short, empathy and self-compassion are the key values here.</p>
<p>This really hits home for me, because I’ve noticed that when I’m anxious, feeling inadequate and listening to the voice in my head that tells me I’m a fraud, I will avoid having a needed honest conversation, I tend to be impatient towards others’ mistakes and reject others’ ideas without giving thought on why they’re even thinking that.</p>
<p>And when my self-talk is more of acceptance, like “hey, this is difficult for everyone, give yourself a break, remember that nobody is born smart”, I am more willing to face a problem I’m having, discuss new ideas and help someone with a problem of their own.</p>
<h1>Vulnerability and minding the gap</h1>
<p><a href="https://www.goodreads.com/book/show/13588356-daring-greatly">The book</a> has a lot more to offer, there is a great chapter about the “armory” that talks about the defenses that we set up in order to not be vulnerable, how they get in the way and how we can deal with them.</p>
<p>On the subject of disengagement, the book tells us to be aware of the gap between where we want to be and where we’re actually standing. We don’t need to be perfect, but we do need to be engaged and committed to our values and keep trying to close this gap between what we aspire and what we practice.</p>
<blockquote>
<p>The gap starts here: <strong>We can’t give people what we don’t have. Who we are matters immeasurably more than what we know or who we want to be.</strong></p>
<p>The space between our practiced values (what we’re actually doing, thinking, and feeling) and our aspirational values (what we want to do, think, and feel) is the value gap, or what I call “the disengagement divide.” It’s where we lose our employees, our clients, our students, our teachers, our congregations, and even our own children. We can take big steps—we can even make a running jump to cross the widening value fissures that we face at home, work, and school—but at some point, when that divide broadens to a certain critical degree, we’re goners. That’s why dehumanizing cultures foster the highest levels of disengagement—they create value gaps that actual humans can’t hope to successfully navigate.</p>
</blockquote>
<p>Minding the gap is embracing our own imperfection and vulnerability, and practicing the values we hold important in our culture. This requires shame resilience, because we will sometimes find too big of a gap, and we’ll have to remind ourselves of our values and that showing up and putting ourselves out there already counts.</p>
<p>For me, personally, minding the gap means different things in different contexts. At work, it means to accept that there will be always be more things I want to do than what I’m actually able to work on. For an organization, minding the gap may be understanding that you want to be a great success and cultivate great values, but sometimes you fail to practice those values and success seems a bit distant. When we mind the gap, acknowledging the distance of where we are and where we want to be, then we’re more willing to help closing it.</p>
<p>The book has a chapter dedicated to disruptive engagement: how we can start daring to have difficult conversations in our organizations, cultivate an honest and constructive feedback culture, and learn to get more comfortable being uncomfortable. And it starts with understanding how scarcity affects us, combat shame by talking about it and normalizing (i.e. sharing how it’s normal to struggle and feel inadequate at times), ultimately rehumanizing the way we lead and work.</p>
<p>An important point is that: “you can’t give what you don’t have”. Who we are matters more than what we know or want to be. This is why it’s important for leaders to embrace shame-resiliency and vulnerability: if we want people to take risks, we have to be willing to engage with vulnerability, take risks and cultivate trust. When we’re <a href="https://www.inc.com/shelley-prevost/8-signs-youre-a-control-freak.html">too controlling</a>, we end up losing impact. When we think of ourselves as not good enough, we tend to spread that feeling unto others who are looking up to us. We become stagnant.</p>
<p>The chapter ends with <a href="http://brenebrown.com/wp-content/uploads/2013/09/DaringGreatly-LeadershipManifesto-8x10.pdf">the leadership manifesto, which is pretty awesome</a>.</p>
<h1>Final thoughts</h1>
<p>So, my hope is that this will help raising awareness about these issues and perhaps we can all start talking about them and diminish the power of our gremlins. I believe it is important to be mindful of the scarcity culture and do our best to prevent shame and disengagement.</p>
<p>You may not be doing bad, but it’s probably good to be mindful of these things, how they affect us and our interactions and how we can find our way to fight shame and its negative outcomes.</p>
<p>Because if we give in to this scarcity culture, we lose innovation, we don’t show up, we play blaming and cover-ups to discharge our pain and discomfort, we don’t give feedback, we stop contributing and we stop caring. And we don’t want that. We want the opposite.</p>
<p>We all want to be brave and dare greatly.</p>
<h1>Links</h1>
<ul>
<li>TED talks from the author: <a href="http://www.ted.com/talks/brene_brown_on_vulnerability">http://www.ted.com/talks/brene_brown_on_vulnerability</a> and <a href="http://www.ted.com/talks/brene_brown_listening_to_shame">http://www.ted.com/talks/brene_brown_listening_to_shame</a></li>
<li>Article in The Guardian: <a href="http://www.theguardian.com/lifeandstyle/2013/jul/27/brene-brown-people-sick-being-afraid">http://www.theguardian.com/lifeandstyle/2013/jul/27/brene-brown-people-sick-being-afraid</a></li>
<li>The Man in the Arena -- speech from Theodore’s Roosevelt that gave the book’s title: <a href="https://www.goodreads.com/quotes/7-it-is-not-the-critic-who-counts-not-the-man">https://www.goodreads.com/quotes/7-it-is-not-the-critic-who-counts-not-the-man</a></li>
<li>About correlations between shame and the negative outcomes mentioned, I’ve <a href="https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.413.8535&rep=rep1&type=pdf">found</a> <a href="https://www.psychologicalscience.org/news/releases/shame-about-past-alcoholism-predicts-relapse-and-declining-health-in-recovering-alcoholics.html">some</a> <a href="http://www.ncbi.nlm.nih.gov/pmc/articles/PMC3763505/">articles</a> <a href="http://www.soc.ucsb.edu/faculty/scheff/main.php?id=2.html">online</a> -- here are some books referred to in Daring Greatly:<ul>
<li><a href="https://www.goodreads.com/book/show/11735397-shame-in-the-therapy-hour">Shame in the Therapy Hour</a></li>
<li><a href="https://www.amazon.com/Shame-Guilt-Neurosis-Helen-Block/dp/0823626075">Shame and Guilt in Neurosis</a></li>
<li><a href="https://www.goodreads.com/book/show/2045998.Shame_and_Guilt">Shame and Guilt</a></li>
</ul>
</li>
</ul>Trying out something new2016-01-26T22:54:00+01:002016-01-26T22:54:00+01:00Elias Dornelestag:eliasdorneles.com,2016-01-26:/2016/01/26/trying-out-something-new.html
<p><img alt="Hey there!" src="https://i.imgur.com/KZo7ObI.png"></p>
<p><img alt="Smiling: I'm trying something new today" src="https://i.imgur.com/vjWgCAK.png"></p>
<p><img alt="Worried face: not sure if this was a good idea" src="https://i.imgur.com/QPGcgDE.png"></p>
<p><img alt="Smiling: But what the heck, you only live once!" src="https://i.imgur.com/whDBm4O.png"></p>
<p><img alt="Doodle joy face: I'm discovering the joy of DOODLING!" src="https://i.imgur.com/Bq54jBg.png"></p>
<p><img alt="The lack of perfection is a feature" src="https://i.imgur.com/45YdMZI.png"></p>
<p><img alt="Just like life... and being human" src="https://i.imgur.com/zBog5ta.png"></p>
<p><img alt="Squared smile: It's easier when you accept the flaws and KEEP GOING" src="https://i.imgur.com/fgU8Y57.png"></p>
<p>If you liked these drawings, you may like <a href="https://www.youtube.com/watch?v=7TXEZ4tP06c&feature=youtu.be">this video teaching you to draw in a
few minutes</a>.</p>Learning from DAS screencasts - season 32015-12-30T12:36:00+01:002015-12-30T12:36:00+01:00Elias Dornelestag:eliasdorneles.com,2015-12-30:/2015/12/30/learning-from-das-screencasts-season-3.html<p>Here is a summary of my learning from watching <a href="https://www.destroyallsoftware.com/screencasts/catalog">season 3 of Destroy All
Software screencasts</a>.</p>
<h2>Which kind of code should go into Models?</h2>
<p>Gary is fond of an architecture style for web applications, which is
<a href="http://rhodesmill.org/brandon/slides/2014-07-pyohio/clean-architecture/">equivalent to the so-called clean architecture described by Brandon Rhodes
here</a>:</p>
<p><center>
<img src="https://eliasdorneles.com/images/clean-architecture.jpg" alt="The Clean Architecture diagram" width="500" />
</center></p>
<p>Following this architecture …</p><p>Here is a summary of my learning from watching <a href="https://www.destroyallsoftware.com/screencasts/catalog">season 3 of Destroy All
Software screencasts</a>.</p>
<h2>Which kind of code should go into Models?</h2>
<p>Gary is fond of an architecture style for web applications, which is
<a href="http://rhodesmill.org/brandon/slides/2014-07-pyohio/clean-architecture/">equivalent to the so-called clean architecture described by Brandon Rhodes
here</a>:</p>
<p><center>
<img src="https://eliasdorneles.com/images/clean-architecture.jpg" alt="The Clean Architecture diagram" width="500" />
</center></p>
<p>Following this architecture, the code inside model classes (in Rails, this
would be Active Record classes) should be either:</p>
<ul>
<li>validations/relationships</li>
<li>mutation (set & save)</li>
<li>wrapper (meaningful getter)</li>
<li>queries (where/order/etc <- best to always be only there)</li>
<li>creation (create and save)</li>
</ul>
<p>And that’s it.</p>
<p>Things with more application logic (aka business rules) should go into their
own libraries, decoupled from the framework or ORM. This leaves the models with
no extra dependencies apart from the ORM, and make the code implementing the
application logic easier to test and modify.</p>
<p>I like this idea very much, but it seems often quite hard to put it in practice,
because most web frameworks encourage coupling with its APIs. I'm yet to see
a framework that really encourages this kind of separation of concerns.
Even the so-called micro-frameworks often fall in this trap.</p>
<p>My feeling is that you need extra discipline to use this architecture. I think
there is a complexity threshold for deciding when the effort will pay off.</p>
<h2>Outside-in TDD</h2>
<p>I already mentioned <a href="http://coding-is-like-cooking.info/2013/04/outside-in-development-with-double-loop-tdd/">outside-in
TDD</a>
in <a href="https://eliasdorneles.com/2015/08/17/learning-from-das-screencasts-season-2.html">the summary for the second
season</a>, when
Gary talked about
<a href="https://joneaves.wordpress.com/2004/02/18/spike_to_learn_tdd_to_build/">spiking</a>.</p>
<p>Here he shows two approaches to do it:</p>
<ol>
<li>
<p>stubbing dependencies: here you program by wishful thinking, and design the
dependencies by stubbing them out (i.e. using mocks to define the interaction
with the code not yet implemented).</p>
</li>
<li>
<p>stash (using Git): implement a feature, but instead of stubbing a wished
feature, stash the current code (i.e. set apart the current code via
<a href="http://www.gitguys.com/topics/temporarily-stashing-your-work/">git stash</a>),
test and implement the wished feature TDD-style, commit it, unstash the
previous code (git stash pop), finish implementing test with the newly
developped code and then commit it.</p>
</li>
</ol>
<p>Both approaches are valid and result in equivalent granularities, but the order
of commits will be different (with stubbing, the order will be more like
top-down) and tests with the stub approach tend to be more isolated.</p>
<h2>Testing code that calls HTTP APIs</h2>
<p>Here is a cool idea: consider external HTTP APIs like “databases”, and test
your wrapper code mocking the HTTP interactions with a tool to replay
interactions like you would test with a fake database.</p>
<p>There is a neat tool for doing this called <a href="https://github.com/vcr/vcr">vcr</a>
which is written in Ruby, there is a Python port called
<a href="https://pypi.python.org/pypi/vcrpy">vcrpy</a>.</p>
<p>What this VCR tool does is: it records HTTP requests into a "cassette" (an
<a href="https://en.wikipedia.org/wiki/YAML">YAML file</a>) to replay the requests later
from it when running the tests and then checks if the requests match the
expected ones from the cassete file.</p>
<p>This makes the tests verify at the boundary of your app with the external HTTP
API, which is arguably more reliable than verifying interactions with proxy
objects (see <a href="https://www.destroyallsoftware.com/talks/boundaries">this talk for about this idea of
boundaries</a>.)</p>
<p>Here is the introduction for <code>vcrpy</code>:</p>
<blockquote>
<p>VCR.py simplifies and speeds up tests that make HTTP requests. The first time
you run code that is inside a VCR.py context manager or decorated function,
VCR.py records all HTTP interactions that take place through the libraries it
supports and serializes and writes them to a flat file (in yaml format by
default). This flat file is called a cassette. When the relevant piece of
code is executed again, VCR.py will read the serialized requests and
responses from the aforementioned cassette file, and intercept any HTTP
requests that it recognizes from the original test run and return the
responses that corresponded to those requests.</p>
</blockquote>
<p>I've recently started using <code>vcrpy</code>, and I like the approach.
However, I'm not sure about </p>
<p>One possible drawback of this approach is that the library must support the
HTTP library you're using, to be able to intercept the requests -- VCR.py
currently lacks support for Twisted Web Client.</p>
<h2>Dealing with untested Code</h2>
<p>In a series of episodes, Gary demonstrates how to tackle an untested method,
adding tests and then refactoring it, keeping the test suite updated.</p>
<p>In this case, you can’t isolate upfront. Sometimes you can start with "smoke
tests" (e.g. simple output test of a happy path).</p>
<p>Gary’s example is a Rails controller method, he starts by writing RSpec
contexts (just the names/descriptions of the tests), one for every code path
(namely, two for every conditional), then sort them from the happiest path to the "saddest" path.</p>
<p>Having that, then he starts writing tests in that order, always checking the
tests fail for every context when appropriate -- this way ensuring that the
test is verifying the right thing.</p>
<p>I found this quite useful, since I often find myself having to deal with
untested code -- often it's my own (lazy programmer detected!).</p>
<p><strong>Aside about testing tools for Python</strong></p>
<p>These videos got me envious of Ruby programmers because of
<a href="http://rspec.info/">RSpec</a>, it’s a really powerful tool. I couldn't find any
good equivalent for Python yet.</p>
<ul>
<li>If you just want a nice output you may try out
<a href="https://github.com/bitprophet/spec">spec</a> (or <a href="https://pypi.python.org/pypi/pinocchio/">pinochio</a>),
that work with <a href="http://nose.readthedocs.org">nosetests</a></li>
<li><a href="https://pypi.python.org/pypi/pytest-describe">pytest-describe</a> almost cuts
it, but it only supports one level of nesting and its reporting is quite ugly
due to limitations of the implementation.</li>
<li><a href="https://github.com/nestorsalceda/mamba">mamba</a> looks promising -- I like the
API, but it's currently lacking documentation.</li>
<li>I've recently found out about <a href="http://heynemann.github.io/pyvows/">pyvows</a>
which looks really cool. I really like the API, but I'm not sold on requiring
<a href="http://www.gevent.org">gevent</a> for my test suite.</li>
</ul>
<p>I even toyed around with <a href="https://gist.github.com/eliasdorneles/a9d5e7ff9a0c00f5bf29">a class decorator allowing for a similar API but relying
only on unittest</a>
which seems to work well with nose and pytest, but I don't know if it's worth
the hassle (let me know if you think this is useful).</p>
<p>Python doesn't make it easy to build this kind of tool, I'm really envious. =)</p>
<h2>Emacs, chainsaw of chainsaws</h2>
<p>Emacs is written in Elisp, and can be extended with Elisp -- this offers a
great level of customization. Also, Emacs environment knows about itself: for
example, the help system is dynamic and can even show your own custom shortcut
for a function.
Vim doesn’t have anything like that, help system are static text files.</p>
<blockquote>
<p>You can build vim inside Emacs, but you could never build Emacs inside vim.</p>
</blockquote>
<p>However, a fresh Emacs installation (without customization) is less usable than
a fresh Vim installation.</p>
<h2>Better structure for Bash scripts by using many small functions.</h2>
<p>This:</p>
<div class="highlight"><pre><span></span><code>userinfo() {
grep "^$1:" /etc/passwd
}
extract_uid(){
cut -d: -f3
}
extract_home(){
cut -d: -f6
}
echo User ID: $(userinfo $1 | extract_uid)
echo Home: $(userinfo $1 | extract_home)
</code></pre></div>
<p>is better than this:</p>
<div class="highlight"><pre><span></span><code>echo User ID: $(grep "^$1:" /etc/passwd | cut -d: -f3)
echo Home: $(grep "^$1:" /etc/passwd | cut -d: -f6)
</code></pre></div>
<p>Last one is shorter, but the former is easier to read and more composable.</p>
<h2>TDD: when to generalize</h2>
<p>Deciding when to generalize in TDD can be difficult, depending on your code and
process.</p>
<p>In case you start your tests with the happy path (as opposed to starting with edge cases),
here are some situations to help you decide when it's time to generalize instead of sliming
(hardcoding values or writing fake implementation just for the current test to pass).</p>
<ul>
<li>
<p>If there is a pending test (not yet implemented) that will force
generalization, use that: implement the test and then generalize.</p>
</li>
<li>
<p>If sliming is harder than generalize, just generalize already.</p>
</li>
<li>
<p>If the implementation is obvious and easy (e.g., it's just calling code
that's already tested and trusted), generalize, then consider the edge
cases and write tests for them.</p>
</li>
</ul>
<p>Note that this is illustrative, but not comprehensive -- there are probably.</p>
<h2>TDD: bad expectations</h2>
<p>Here are some notes about bad expectations/assertions in the test code, which
are bad because they mine our confidence in the test suite.</p>
<p>Negative expectations (e.g., asserting that some function was NOT called, or
that some expression isn't true) are dangerous because it's easy to miss
a case where result can be incorrect and the assertion still pass.</p>
<p>The same is true for partial matches (checking containment or substring) like:</p>
<div class="highlight"><pre><span></span><code><span class="s1">'connected'</span><span class="w"> </span><span class="nv">in</span><span class="w"> </span><span class="nv">status</span><span class="w"> </span>#<span class="w"> </span><span class="nv">what</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nv">status</span><span class="w"> </span><span class="nv">is</span><span class="w"> </span><span class="s2">"disconnected"</span>?
</code></pre></div>
<p>Tests that obsess about implementation (like, a test checking the internal state
of the component being tested) are also bad. This kind of test pours concrete
over the code, making changes harder.</p>
<p>Finally, it’s best to write tests against the broad interface of a class,
instead of tests for helper methods in it. In the end, the broad interface is
what really matters, and the helper methods have higher probability to be
changed later, best not to pour concrete around them either.</p>
<p>That's it for season 3 -- thanks for reading! :)</p>Regex metacharacters differences across several environments2015-12-13T02:16:00+01:002015-12-13T02:16:00+01:00Elias Dornelestag:eliasdorneles.com,2015-12-13:/2015/12/13/regex-metacharacters-differences-across-several-environments.html
<p>Here is a table helpful for learning regular expression metacharacters
differences across several languages and environments.</p>
<table>
<thead>
<tr>
<th style="text-align: right;">Language/environment</th>
<th>Optional</th>
<th>More</th>
<th>Brackets</th>
<th>Border</th>
<th>Or</th>
<th>Group</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">Apache, Bash, egrep, Java, JS, Perl, PHP, Python, Ruby, VBScript, .NET</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td><code>{,}</code></td>
<td><code>\b</code></td>
<td><code>|</code></td>
<td><code>()</code></td>
</tr>
<tr>
<td style="text-align: right;">Gawk, Openffice.org</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td><code>{,}</code></td>
<td><code>\<,\></code></td>
<td><code>|</code></td>
<td><code>()</code></td>
</tr>
<tr>
<td style="text-align: right;">awk, Mawk, Expect</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td>N/A</td>
<td>N/A</td>
<td><code>|</code></td>
<td><code>()</code></td>
</tr>
<tr>
<td style="text-align: right;">C, Lex, Tcl</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td><code>{,}</code></td>
<td>N …</td></tr></tbody></table>
<p>Here is a table helpful for learning regular expression metacharacters
differences across several languages and environments.</p>
<table>
<thead>
<tr>
<th style="text-align: right;">Language/environment</th>
<th>Optional</th>
<th>More</th>
<th>Brackets</th>
<th>Border</th>
<th>Or</th>
<th>Group</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: right;">Apache, Bash, egrep, Java, JS, Perl, PHP, Python, Ruby, VBScript, .NET</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td><code>{,}</code></td>
<td><code>\b</code></td>
<td><code>|</code></td>
<td><code>()</code></td>
</tr>
<tr>
<td style="text-align: right;">Gawk, Openffice.org</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td><code>{,}</code></td>
<td><code>\<,\></code></td>
<td><code>|</code></td>
<td><code>()</code></td>
</tr>
<tr>
<td style="text-align: right;">awk, Mawk, Expect</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td>N/A</td>
<td>N/A</td>
<td><code>|</code></td>
<td><code>()</code></td>
</tr>
<tr>
<td style="text-align: right;">C, Lex, Tcl</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td><code>{,}</code></td>
<td>N/A</td>
<td><code>|</code></td>
<td><code>()</code></td>
</tr>
<tr>
<td style="text-align: right;">Find, Emacs</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td>N/A</td>
<td><code>\b</code></td>
<td><code>\|</code></td>
<td><code>\(\)</code></td>
</tr>
<tr>
<td style="text-align: right;">grep, ed</td>
<td><code>\?</code></td>
<td><code>\+</code></td>
<td><code>\{,\}</code></td>
<td><code>\b</code></td>
<td><code>\|</code></td>
<td><code>\(\)</code></td>
</tr>
<tr>
<td style="text-align: right;">sed</td>
<td><code>\?</code></td>
<td><code>\+</code></td>
<td><code>\{,\}</code></td>
<td><code>\<,\></code></td>
<td><code>\|</code></td>
<td><code>\(\)</code></td>
</tr>
<tr>
<td style="text-align: right;">Vim</td>
<td><code>\=</code></td>
<td><code>\+</code></td>
<td><code>\{,}</code></td>
<td><code>\<,\></code></td>
<td><code>\|</code></td>
<td><code>\(\)</code></td>
</tr>
<tr>
<td style="text-align: right;">PostgreSQL</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td><code>{,}</code></td>
<td><code>\y</code></td>
<td><code>|</code></td>
<td><code>()</code></td>
</tr>
<tr>
<td style="text-align: right;">MySQL</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td><code>{,}</code></td>
<td><code>[[:<:]]</code></td>
<td><code>|</code></td>
<td><code>()</code></td>
</tr>
<tr>
<td style="text-align: right;">Oracle</td>
<td><code>?</code></td>
<td><code>+</code></td>
<td><code>{,}</code></td>
<td>N/A</td>
<td><code>|</code></td>
<td><code>()</code></td>
</tr>
</tbody>
</table>
<p>Thankfully, <code>.</code> <code>*</code> <code>[]</code> <code>[^]</code> <code>^</code> and <code>$</code> work the same way in all.</p>
<p>The hard work of checking the differences was done by <a href="http://aurelio.net/">Aurelio
Jargas</a>, published in <a href="http://www.piazinho.com.br/">his wonderful book about regular
expressions</a>. (Portuguese only)</p>
<p>I merely grouped them by language/environment, chunking the information for
easier memorizing.</p>The power of a good template2015-10-18T14:25:00+02:002015-10-18T14:25:00+02:00Elias Dornelestag:eliasdorneles.com,2015-10-18:/2015/10/18/the-power-of-a-good-template.html<p>Almost ten years ago, I was an intern helping to maintain a PHP application and
attempting to write a little framework to create the new version of that
application. My little framework generated PHP classes from some templates and
a description you’d write in a DSL language I came …</p><p>Almost ten years ago, I was an intern helping to maintain a PHP application and
attempting to write a little framework to create the new version of that
application. My little framework generated PHP classes from some templates and
a description you’d write in a DSL language I came up with.</p>
<p>It was a nice feeling to come up with a little model and quickly generate a
bunch of classes, but it was also pretty stupid: the generated classes would
get edited, and later the templates would change too, and suddenly all the
generated classes needed manual update.</p>
<p>So I learned back then the following lesson: generating code that needs to be
edited later is a bad idea -- instead of doing that, I must create libraries
and components that allow to be combined and build on top of them. I never
wanted to use boilerplate code generation again. I started thinking that any
solution that required boilerplate were too bloated. I also dismissed the
utility of code snippets too, because I wanted a function, not boilerplate
code.</p>
<p>Great, except this is the wrong conclusion.</p>
<p>It’s true that solutions which don’t require generated code are generally
better for reusability and long term maintenance (e.g. Python properties vs
Java getters), but good templates for boilerplate code generation can be of
great utility sometimes. Good templates are nice not only because they help you
get started in something quickly, they can also teach you the proper way of
doing things and get you started learning more about something.</p>
<p>I started to realize the power of code snippets a couple of years ago, when I
noticed that I was being lazy to write argument parsing code properly for my
Python scripts. I knew the script would be much better parsing arguments with
argparse, but as I wasn’t sure if the script would be useful when I started
writing it, I would be lazy and write something like:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">sys</span>
<span class="n">inputfile</span> <span class="o">=</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">)</span> <span class="o"><</span> <span class="mi">2</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Please provide an input file"</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">process</span><span class="p">(</span><span class="n">inputfile</span><span class="p">)</span>
</code></pre></div>
<p>And this is just awful, for a variety of reasons:</p>
<ol>
<li>it doesn't have a nice help, so people would often need to read the code to
understand what it does</li>
<li>the code isn’t obvious, one has to keep in mind details about sys.argv</li>
<li>it is hard to change when you have more arguments</li>
</ol>
<p>After thinking about this laziness, I decided this was a good use case for a
code snippet, so I grabbed a vim plugin for code snippets and came up with the
following snippet:</p>
<div class="highlight"><pre><span></span><code><span class="p">:::</span><span class="n">python</span>
<span class="c1">#!/usr/bin/env python</span>
<span class="c1"># -*- coding: utf-8 -*-</span>
<span class="sd">"""Script description here</span>
<span class="sd">"""</span>
<span class="kn">from</span> <span class="nn">__future__</span> <span class="kn">import</span> <span class="n">print_function</span>
<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="n">args</span><span class="p">):</span>
<span class="k">pass</span>
<span class="k">if</span> <span class="s1">'__main__'</span> <span class="o">==</span> <span class="vm">__name__</span><span class="p">:</span>
<span class="kn">import</span> <span class="nn">argparse</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="vm">__doc__</span><span class="p">)</span>
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
<span class="n">run</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
</code></pre></div>
<p>Well, as you can see, there is not that much going on here, just simple
boilerplate stuff: a docstring, a shebang, a docstring, and an argparse
initialization inside the if main block.</p>
<p>However, now every time I started a script, even if I <em>really</em> wanted to be
lazy, I could just add to the if main block:</p>
<div class="highlight"><pre><span></span><code>parser.add_argument('my_argument_name')
</code></pre></div>
<p>Then, I could code my script inside the <code>run()</code> function, ending up with a neat
code with help for free. Plus, it was easy to change, I could use the <code>argparse</code>
features for providing defaults, argument help text and maybe validate and type
check the arguments.</p>
<p>This little snippet changed my habit for writing scripts. It made the scripts
easier for people to use and modify them (including myself) and it helped me
to learn better the library, which I didn’t knew much besides the basics earlier
as I didn’t use it much. As I started using <code>argparse</code> more, I started
designing the command line interfaces better, making decisions about
positional vs optional arguments, handling grouping and conflicting options,
trying to come up with truly helpful help text.
The snippet freed me of making small bad decisions when starting a script.</p>
<p>My bad habit was impeding my learning, making life harder for people wanting to
use my scripts and making my life harder when maintaining the scripts. This
little snippet helped me to solve all these problems.</p>
<p>That is the power of a good template.</p>
<p>It helps you grow. If you let it. :)</p>
<p>Templates are not about being lazy -- they’re about <em>learning</em>.</p>
<p>A good template empowers you to learn better, by reducing the initial barrier.</p>
<p>About an year ago, I didn’t know much about Python packaging, my Python
projects were all badly packaged, the <code>setup.py</code> being patched when I hit
an issue. And every time I tried to read some packaging guide I’d get
overwhelmed pretty quickly. <em>“Uh, this is for Python gurus, too many
decisions I don’t understand, it will take years for me to learn enough to
build a nice Python package, nevermind.”</em></p>
<p>Then I heard about <a href="http://cookiecutter.rtfd.org/">cookiecutter</a> (tool for
building and using project templates), found this template for Python packages
called
<a href="https://github.com/audreyr/cookiecutter-pypackage">cookiecutter-pypackage</a> and
gave it a try.</p>
<p>I was very happy when I first built my first little package in a matter of
minutes, wrapping some lame script I had around. It had gorgeous docs published
on <a href="http://readthedocs.org">ReadTheDocs</a>, tests running in
<a href="http://travis-ci.org">Travis-CI</a>, and last but not least, it was published in
<a href="http://pypi.python.org">PyPI</a>! Now anyone can install it with <code>pip install
my_lame_package</code> -- this is awesome!</p>
<p>As the months went by, I got involved in splitting some code bases into smaller
packages. I used the cookiecutter-pypackage template for some of the new small
packages, and for others that needed more custom packaging I would get
inspiration about how the template solved a problem, discuss with others about
better ways to do it, and ended up learning a lot about Python packaging in the
process. I’m far from a guru, but I’m much less ignorant than one year ago.</p>
<p>All this in a learning process that started with trying out a template.</p>
<p>Templates are a great learning tool.</p>
<p>The lesson I should have learned in my failed framework attempt of long time
ago was not that boilerplate code generation is bad in general. It was bad for
what I was using it, generating application code that needed to be kept in sync
with the template sources, quickly turning the generated code into legacy.</p>
<p>But for code that can stand on its own, don’t require updates when the template
source changes, and specially for things that are a bit awkward to get started,
templates are awesome.</p>Working on hard problems2015-09-13T18:41:00+02:002015-09-13T18:41:00+02:00Elias Dornelestag:eliasdorneles.com,2015-09-13:/2015/09/13/working-on-hard-problems.html<p>We programmers often prefer to work in problems that we already know how to
solve, and tend to avoid hard ones that don't have a straightforward solution.
Sure we like to think that we love a challenge, but given the choice of
something easy to solve and another that requires …</p><p>We programmers often prefer to work in problems that we already know how to
solve, and tend to avoid hard ones that don't have a straightforward solution.
Sure we like to think that we love a challenge, but given the choice of
something easy to solve and another that requires thinking more deeply, one
will choose to work in the easy one -- regardless of which one is more
important. We're biased to tools and techniques that we already know and are comfortable
with, we favor solutions we don’t need to think much.</p>
<p><center>
<img src="/images/easy-solution.jpg" alt="a Rubik's cube painted to look solved"
style="border: 1px solid #111; width: 400px" />
</center></p>
<p>By hard problem, I don't mean just something you have never done before but
you're reasonably confident that you can learn how to do it -- you know,
solving a known problem in a different language/technology, these kinds of
things that we like to do sometimes to avoid boredom. I'm talking about problems that you have
no clue how to solve (or even if it’s solvable) and no idea if you can learn
how to solve it. Problems you're afraid of even trying to tackle.</p>
<p>To be fair, this is just human nature, it's not a limitation of programmers
only: most people in similar circumstances will act the same way. And many
times this is okay, it's often not a big deal to do the thing requiring less
energy, we even design products around this behavior of choosing the easy. It's
only human that we will tend to do the easy instead of the hard, and many times
it’s even the wisest thing to do.</p>
<p>Now, what if these hard problems are really the important ones? How do we
decide if they’re really important? What can we do about this natural tendency
of avoiding them? What can you do to make yourself more willing to at least
attempt to solve them? I’ve been thinking about this lately, and I don’t really
have a straight answer.</p>
<p>I suppose it has a bit to do with attitude, a feeling that it will be worth to
give it a try even if you don’t succeed. I suspect the fear of failure is big
for many programmers. Our own expectations for a possible solution are
increasing by the minute, however our ability to learn doesn’t scale at the same proportion.
So we conclude we’re not up to the challenge and give up without really trying,
thus not building resilience while learning from failures, which would be
precisely what would help when tackling a tough problem.</p>
<p>We’re eager to believe in <a href="https://www.safaribooksonline.com/library/view/team-geek/9781449329839/ch01.html">the myth of the genius programmer</a>, which helps to
increase our insecurity. Most programmers have some personal heroes, and that’s
not a bad thing, but it’s good to remind ourselves these heroes are just
people, not that different from you and me. I bet they see themselves as just
people working in hard problems. In some cases they might’ve been privileged
with early access to technology or guidance from knowledgeable people, but I
have the feeling that our heroes are mostly just people who are willing to give
it a try and keep at it.</p>
<p>It’s nice to pay attention on what may be causing us to avoid difficult
problems, and seek to understand which are the sources of anxiety, what are the
risks and fears involved. Hopefully this will help us to see more clearly and
make better decisions about what we should be working on. Because it’s easy to
avoid important work if you’re rushing to do everything fast, fearing to fail
or disappoint someone or just being too busy to spend time thinking.</p>
<p>Sure there will be times when we’ll be too underprepared for a problem. But maybe we
should try it either way, perhaps in a safe environment. At the very minimum we’d learn
a bit more about the problem and maybe grow a better understanding of what to
learn before trying again.
Who knows, <a href="https://hbr.org/2013/04/to-find-happiness-at-work-tap/">this might end up being a good heuristic for increasing happiness</a>.</p>
<p><center>
<img src="https://lh3.googleusercontent.com/-VY-GWqdlGBQ/U_IZKe8HVUI/AAAAAAAABPc/ysFshw14LrA/w612-h612/Ins%2Bbeautiful%2Bdestinations.jpg"
alt="Difficult roads often lead to beautiful destinations"
style="border: 1px solid #111; width: 350px" />
</center></p>Learning from DAS screencasts - season 22015-08-17T01:41:00+02:002015-08-17T01:41:00+02:00Elias Dornelestag:eliasdorneles.com,2015-08-17:/2015/08/17/learning-from-das-screencasts-season-2.html<p>These are my notes for <a href="https://www.destroyallsoftware.com/screencasts/catalog">season 2 of Destroy All Software
screencasts</a>.</p>
<h2>The command line, Unix, git and Vim</h2>
<p>In the first episode Gary teaches how to compose a complex Unix command line:
the point is that you want to build it slowly, checking if it works at every
step …</p><p>These are my notes for <a href="https://www.destroyallsoftware.com/screencasts/catalog">season 2 of Destroy All Software
screencasts</a>.</p>
<h2>The command line, Unix, git and Vim</h2>
<p>In the first episode Gary teaches how to compose a complex Unix command line:
the point is that you want to build it slowly, checking if it works at every
step of the way. This becomes common sense pretty quickly after you acquire the
habit of doing this kind of thing for a while.</p>
<p>For example, say you want to remove the untracked files from a git repo.
Instead of trying to write all of this in one go:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>status<span class="w"> </span>-s<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">'??'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>awk<span class="w"> </span><span class="s1">'{ print $2 }'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>xargs<span class="w"> </span>rm<span class="w"> </span>-f
</code></pre></div>
<p>Since you don't want to delete any files by mistake, you will check every step
along the way, until arriving at the safe command:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>git<span class="w"> </span>status<span class="w"> </span>-s
<span class="w"> </span>M<span class="w"> </span>README.rst
??<span class="w"> </span>anotherfile.txt
??<span class="w"> </span>file.txt
$<span class="w"> </span>git<span class="w"> </span>status<span class="w"> </span>-s<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">'^??'</span>
??<span class="w"> </span>anotherfile.txt
??<span class="w"> </span>file.txt
$<span class="w"> </span>git<span class="w"> </span>status<span class="w"> </span>-s<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">'^??'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>awk<span class="w"> </span><span class="s1">'{ print $2 }'</span>
anotherfile.txt
file.txt
$<span class="w"> </span><span class="c1"># great, got right the list of files now!</span>
$<span class="w"> </span><span class="c1"># now let's pipe it to xargs and print the delete command:</span>
$<span class="w"> </span>git<span class="w"> </span>status<span class="w"> </span>-s<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">'^??'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>awk<span class="w"> </span><span class="s1">'{ print $2 }'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>xargs<span class="w"> </span><span class="nb">echo</span><span class="w"> </span>rm<span class="w"> </span>-f
rm<span class="w"> </span>-f<span class="w"> </span>anotherfile.txt<span class="w"> </span>file.txt
$<span class="w"> </span><span class="c1"># looks safe, let's remove the echo and do it for real:</span>
$<span class="w"> </span>git<span class="w"> </span>status<span class="w"> </span>-s<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span><span class="s1">'^??'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>awk<span class="w"> </span><span class="s1">'{ print $2 }'</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>xargs<span class="w"> </span>rm<span class="w"> </span>-f
</code></pre></div>
<p>His example is more complicated and more interesting than this, but you get the gist of it.</p>
<p>The second episode is about the tar pipe, you can read <a href="http://blog.extracheese.org/2010/05/the-tar-pipe.html">Gary's own post about
it here</a>. I was already
familiar with the shell inner workings because I had to implement a toy shell
as homework when I was in college (my buddy
<a href="https://twitter.com/stummjr">Valdir</a> and I had loads of fun with that). It
was pretty cool to see it takes a few minutes and 10 lines of Python code what
took us days and many lines of C code at the time.</p>
<p>Later there is an episode about Vim with tips about how to learn it.
Here is a summary:</p>
<ul>
<li>Learn the normal mode</li>
<li>Learn the motions (<code>:help motions</code>)</li>
<li>Don't repeat yourself</li>
<li>When automating stuff, you usually start with something that you <em>read</em> (a
message in a buffer), then with something that you <em>scan</em> (a list of things),
then finally with something that you <em>do</em> (an action or command).</li>
<li>An action is better than scanning over a list which is better than having to
read an interpret a message. Choose plugins that are more of the former than
the latter.</li>
</ul>
<p>The thing about Vim is that it feels like practicing a sport or playing an
instrument, you can often do edit work with your eyes closed.</p>
<p>In another episode Gary builds a command-line to look at evolution of the
execution time of the test suite, and then demonstrates using <code>git bisect</code> to
find out which change was responsible for a nice performance boost. He used a
few tricks which I thought were pretty neat. </p>
<p>First trick was, while building a command line for a long list of commits, he
used awk to filter the input to get only every 50th line, before getting the
rest of the command line right for the full output, like this:</p>
<div class="highlight"><pre><span></span><code>some command generating many lines | awk 'NR % 50 == 0'
</code></pre></div>
<p>I can see myself using this in the future, it’s a good way of previewing the results of a command. :)</p>
<p>The other trick I liked was getting a quick histogram in the command-line using
<a href="http://www.unix.com/man-page/freebsd/1/jot/">a command utility called jot</a>
present in Mac OS X and other BSD based systems. The <code>jot</code> command is pretty
similar to seq in Linux-based distros, only it allows to print a string
repeatedly (<code>-b</code> argument) while <code>seq</code> does not allow printing things other
than numbers. This is nice, because you can do things like this:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>jot<span class="w"> </span>-s<span class="w"> </span><span class="s1">''</span><span class="w"> </span>-b<span class="s1">'#'</span><span class="w"> </span><span class="m">10</span>
<span class="c1">##########</span>
</code></pre></div>
<p>Now for an example plotting some numbers:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>seq<span class="w"> </span><span class="m">15</span><span class="w"> </span><span class="m">20</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sort<span class="w"> </span>-R<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="nb">read</span><span class="w"> </span>num<span class="p">;</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="sb">`</span>jot<span class="w"> </span>-s<span class="w"> </span><span class="s1">''</span><span class="w"> </span>-b<span class="s1">'#'</span><span class="w"> </span><span class="nv">$num</span><span class="sb">`</span><span class="w"> </span><span class="nv">$num</span><span class="p">;</span><span class="w"> </span><span class="k">done</span>
<span class="c1">################ 16</span>
<span class="c1">################### 19</span>
<span class="c1">################# 17</span>
<span class="c1">################## 18</span>
<span class="c1">#################### 20</span>
<span class="c1">############### 15</span>
</code></pre></div>
<p>While we don’t have <code>jot</code> distributed by default in Linux distros, we can do the
same thing in Linux using python:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>seq<span class="w"> </span><span class="m">15</span><span class="w"> </span><span class="m">20</span><span class="w"> </span><span class="p">|</span><span class="w"> </span>sort<span class="w"> </span>-R<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="nb">read</span><span class="w"> </span>num<span class="p">;</span><span class="w"> </span><span class="k">do</span><span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="sb">`</span>python<span class="w"> </span>-c<span class="w"> </span><span class="s2">"print('#'*</span><span class="nv">$num</span><span class="s2">)"</span><span class="sb">`</span><span class="w"> </span><span class="nv">$num</span><span class="p">;</span><span class="w"> </span><span class="k">done</span>
<span class="c1">################# 17</span>
<span class="c1">############### 15</span>
<span class="c1">################### 19</span>
<span class="c1">#################### 20</span>
<span class="c1">################## 18</span>
<span class="c1">################ 16</span>
</code></pre></div>
<p>There are <a href="http://superuser.com/questions/86340/linux-command-to-repeat-a-string-n-times">a bunch of other ways of doing it in the shell
itself</a>,
but I like the conciseness and readability of this one.</p>
<h2>TDD</h2>
<p>Some videos deal with Test Driven Design vs Test Driven Development, talking
about an idea I had never heard before called
<a href="http://lizkeogh.com/2012/06/24/beyond-test-driven-development/">spiking</a>
(apparently I’ve missed some TDD literature). The idea is to write some code
without tests in a sort of exploratory way, usually to get an understanding of
what’s possible, and then throw it away and restart from the beginning writing
tests first.</p>
<p>Gary demonstrates the idea of doing <a href="https://www.destroyallsoftware.com/screencasts/catalog/spiking-and-continuous-spiking">continuous
spiking</a>,
where instead of throwing all the code away you’d transition it in a TDD-style
manner, as you write tests for it. (He shows another example of this later in
another video in a workflow using git, where you'd rebase the branch where you
spiked on top of the new implementation you're TDDing.) He mentions there is a
danger of doing this because the end result will probably be heavily influenced
by the design you ended up when doing the spike (writing code without tests),
so you’ll not be driving the design in a test-driven manner.</p>
<p>This probably sounds a bit extreme to some, but the reasoning is that you will
miss some design insights when you’re not putting yourself in the shoes of the
user. It makes sense to me, even though I confess I often do not work that hard
to do test driven design as I'd want to.</p>
<p>There was a nice video about test stubs making the distinction between
incidental interaction vs essential interaction and the relation to using a
normal stub (a dummy for an incidental interaction) vs a null object stub (aka
mocks, when you assert on methods, checking essential interactions). Testing
a module mixin may be a special case, you can mixin directly in the stub for
simpler testing.</p>
<p>As an additional note, it’s useful to make stubs first and share them for
several tests, to localize and make clear what each test cares about.</p>
<p>In another episode Gary shows something I’ve also learned on my own: it’s a
good practice to split tests that test several things into finer grained
isolated tests with meaningful names that test only one thing. This is
specially useful when you’re refactoring and a test breaks, because you can see
more directly what went wrong.</p>
<h2>Refactoring in a codebase new to you</h2>
<p>There are two episodes quite interesting to watch, where Gary refactors out a
Rails controller without much previous knowledge about the code.</p>
<p>I find it hard to write about it, it seems to be the kind of thing for which
video is the best vehicle because it's hard to talk about it using words alone,
without showing the mechanics of it. It seems to me that these videos
illustrate that if you know well your language and tools, you can work
reasonably well in codebases that are new to you. It’s nice to try this kind of
thing every once in a while.</p>
<h2>Acceptance tests</h2>
<p>In a video about acceptance tests, Gary shows the usage of
<a href="https://cucumber.io/">Cucumber</a> for testing a Rails application, using a
browser engine to simulate user actions and a few tricks he uses to make it run
fast (20 scenarios with 104 tests in total, finish under ten seconds). I don’t
have much experience with <a href="https://en.wikipedia.org/wiki/Acceptance_test-driven_development">acceptance test-driven
development</a>,
but one good point I took from from this is that it’s better to come up with
meaningful short names for user actions ("when user creates a monthly coupon")
instead of long names that describe the input ("when user enters X into field Y
and selects option Z").</p>
<p>In another video he investigates the performance of tests testing the same
feature but from different levels for a Rails app: two acceptance tests using a
browser engine to simulate an user, two tests running the controller method
including rendering the view, two tests for the view only and finally two tests
for the same functionality inside a class method.</p>
<p>Plotting the results of the execution times for the tests at different levels,
the curve looks exponential. I suppose the lesson here is that it’s good to
move a lot of functionality into classes and libraries, in order to be able to
rely as much as possible into unit tests and not need to rely much on
integration and acceptance tests. This should probably not be much surprising.</p>
<p>Following that, Gary explains which of those tests he would actually want to
keep for the test suite of the app (he discards the controller tests, leaves
only one acceptance test and reluctantly keeps the view tests because they're
around a conditional). A good point he makes is that if you see a test that
it’s mostly talking about dependencies of the things it claims to be testing,
then it’s probably not testing at the right level.</p>
<p>And that's it for season 2, a pretty cool experience -- thanks for reading! =)</p>Useful small scripts for your ~/bin2015-01-28T00:03:00+01:002015-01-28T00:03:00+01:00Elias Dornelestag:eliasdorneles.com,2015-01-28:/2015/01/28/useful-small-scripts-for-your-bin.html<h3>fields</h3>
<p>So you are a command line geek, you do your
shell-scripts and one-liners using bash to get information you
need.</p>
<p>You use <a href="https://en.wikipedia.org/wiki/Cut_(Unix)">cut</a>
for handling things delimited by some character like comma or space, but
sometimes you have a list of stuff separated by a varied amount of
spaces …</p><h3>fields</h3>
<p>So you are a command line geek, you do your
shell-scripts and one-liners using bash to get information you
need.</p>
<p>You use <a href="https://en.wikipedia.org/wiki/Cut_(Unix)">cut</a>
for handling things delimited by some character like comma or space, but
sometimes you have a list of stuff separated by a varied amount of
spaces, like this:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>cat<span class="w"> </span>myfile.txt
Amelia<span class="w"> </span><span class="m">555</span>-5553<span class="w"> </span>amelia.zodiacusque@gmail.com
Julie<span class="w"> </span><span class="m">555</span>-6699<span class="w"> </span>julie@skeeve.com
</code></pre></div>
<p>This form of vertical alignment is cool because you can skim through any column
very quickly, but it makes your life a little bit harder when processing it in
the command line. Well, maybe you're smiling to yourself because you already
know about <a href="https://en.wikipedia.org/wiki/AWK">awk</a>, and you use it all the time
for this kind of stuff doing something like: </p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>cat<span class="w"> </span>myfile.txt<span class="w"> </span><span class="p">|</span><span class="w"> </span>awk<span class="w"> </span><span class="s1">'{ print $3 }'</span>
amelia.zodiacusque@gmail.com
julie@skeeve.com
</code></pre></div>
<p>That's all fine, <a href="http://ferd.ca/awk-in-20-minutes.html">awk is a great tool to
grok</a>, but typing all that just for
getting out a field is a bit annoying. So I've written a little script to make
that yet easier: just <a href="https://github.com/eliasdorneles/dotfiles/raw/master/bin/fields">download
it</a> and put
somewhere in your $PATH. After that, next time you find yourself in this
situation you'll do:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>cat<span class="w"> </span>myfile.txt<span class="w"> </span><span class="p">|</span><span class="w"> </span>fields<span class="w"> </span><span class="m">1</span>
Amelia
Julie
$<span class="w"> </span>cat<span class="w"> </span>myfile.txt<span class="w"> </span><span class="p">|</span><span class="w"> </span>fields<span class="w"> </span><span class="m">2</span>
<span class="m">555</span>-5553
<span class="m">555</span>-6699
$<span class="w"> </span>cat<span class="w"> </span>myfile.txt<span class="w"> </span><span class="p">|</span><span class="w"> </span>fields<span class="w"> </span><span class="m">2</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="c1"># get fields separated by TABs</span>
<span class="m">555</span>-5553<span class="w"> </span>amelia.zodiacusque@gmail.com
<span class="m">555</span>-6699<span class="w"> </span>julie@skeeve.com
$<span class="w"> </span>cat<span class="w"> </span>myfile.txt<span class="w"> </span><span class="p">|</span><span class="w"> </span>fields<span class="w"> </span>-s<span class="w"> </span>,<span class="w"> </span><span class="m">2</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="c1"># or by comma</span>
<span class="m">555</span>-5553,amelia.zodiacusque@gmail.com
<span class="m">555</span>-6699,julie@skeeve.com
</code></pre></div>
<h3>total_sum</h3>
<p>Another thing you may found yourself running to awk is when you need a sum of
numbers. Often when you need a summation you will also need some more stuff,
and then it might be time to start writing a Python/Ruby/Perl script instead of
hacking in the command line. But I've often finding myself wanting just a
simple sum that justified putting the little awk one-liner <a href="https://github.com/eliasdorneles/dotfiles/raw/master/bin/total_sum">into a script of
its own</a>:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>cat<span class="w"> </span>~/bin/total_sum
<span class="c1">#!/bin/bash</span>
<span class="c1"># Report sum of numbers fed to the stdin</span>
awk<span class="w"> </span><span class="s1">'{ total+=$1 } END { print total }'</span>
$<span class="w"> </span><span class="nb">echo</span><span class="w"> </span>-e<span class="w"> </span><span class="s2">"1\n2\n3\n4"</span>
<span class="m">1</span>
<span class="m">2</span>
<span class="m">3</span>
<span class="m">4</span>
$<span class="w"> </span><span class="nb">echo</span><span class="w"> </span>-e<span class="w"> </span><span class="s2">"1\n2\n3\n4"</span><span class="p">|</span><span class="w"> </span>total_sum
<span class="m">10</span>
</code></pre></div>
<h3>humanize</h3>
<p>If you find yourself having to count digits from a long number representing the
size in bytes of some big file, you're not alone.</p>
<p>I got tired of this and wrote <a href="https://github.com/eliasdorneles/dotfiles/blob/master/bin/humanize">a Python script to humanize these
numbers</a>
(<a href="https://github.com/eliasdorneles/dotfiles/raw/master/bin/humanize">download
here</a>),
shamelessly stealing the naturalsize function from the <a href="https://pypi.python.org/pypi/humanize">humanize Python
library</a>.</p>
<p>Look how pleasant it is to use it:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>humanize<span class="w"> </span><span class="m">32432</span>
<span class="m">32</span>.4<span class="w"> </span>kB
$<span class="w"> </span><span class="nb">echo</span><span class="w"> </span>-e<span class="w"> </span><span class="s2">"10\n1200\n54356\n3123342\n3294384948"</span><span class="w"> </span>><span class="w"> </span>some_file.txt
$<span class="w"> </span>cat<span class="w"> </span>some_file.txt
<span class="m">10</span>
<span class="m">1200</span>
<span class="m">54356</span>
<span class="m">3123342</span>
<span class="m">3294384948</span>
$<span class="w"> </span>cat<span class="w"> </span>some_file.txt<span class="w"> </span><span class="p">|</span><span class="w"> </span>humanize
<span class="m">10</span><span class="w"> </span>Bytes
<span class="m">1</span>.2<span class="w"> </span>kB
<span class="m">54</span>.4<span class="w"> </span>kB
<span class="m">3</span>.1<span class="w"> </span>MB
<span class="m">3</span>.3<span class="w"> </span>GB
$<span class="w"> </span>cat<span class="w"> </span>some_file.txt<span class="w"> </span><span class="p">|</span><span class="w"> </span>humanize--binary
<span class="m">10</span><span class="w"> </span>Bytes
<span class="m">1</span>.2<span class="w"> </span>KiB
<span class="m">53</span>.1<span class="w"> </span>KiB
<span class="m">3</span>.0<span class="w"> </span>MiB
<span class="m">3</span>.1<span class="w"> </span>GiB
</code></pre></div>
<p>That's all I had, folks! :)</p>Things I Learned from Destroy All Software - Season 12015-01-18T10:07:00+01:002015-01-18T10:07:00+01:00Elias Dornelestag:eliasdorneles.com,2015-01-18:/2015/01/18/things-i-learned-from-destroy-all-software---season-1.html<p>So, a few weeks ago I purchased and watched the first season of <a href="https://www.destroyallsoftware.com/">Destroy All
Software screencasts</a> (from <a href="https://twitter.com/garybernhardt">Gary
Bernhard</a>), and it was awesome. I'd say
there are different kinds of stuff to learn from it, depending on your personal
interests and experience.</p>
<p>Here are my notes for some things …</p><p>So, a few weeks ago I purchased and watched the first season of <a href="https://www.destroyallsoftware.com/">Destroy All
Software screencasts</a> (from <a href="https://twitter.com/garybernhardt">Gary
Bernhard</a>), and it was awesome. I'd say
there are different kinds of stuff to learn from it, depending on your personal
interests and experience.</p>
<p>Here are my notes for some things I found useful and want to remember for
later.</p>
<h3>About Git:</h3>
<p>You can use the <code>git rev-list HEAD</code> command to get a list of commits in the
current branch. This is useful for writing scripts to report something about
each commit in the repo. You can, for example, check the evolution of line
counts over the course of the project (or any other statistic like number of
tests, number of files, etc). You can also run the tests for every commit in
the history:</p>
<div class="highlight"><pre><span></span><code>git<span class="w"> </span>rev-list<span class="w"> </span>HEAD<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="nb">read</span><span class="w"> </span>rev<span class="p">;</span><span class="w"> </span><span class="k">do</span>
<span class="w"> </span>git<span class="w"> </span>checkout<span class="w"> </span><span class="nv">$rev</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span>git<span class="w"> </span>clean-fd<span class="w"> </span><span class="o">&&</span><span class="w"> </span>make<span class="w"> </span><span class="nb">test</span>
<span class="k">done</span>
</code></pre></div>
<p>Gary has a script ready for this:
<a href="https://github.com/garybernhardt/dotfiles/blob/master/bin/run-command-on-git-revisions">run-command-on-git-revisions</a></p>
<p>Git tracks everything that happens in the local repo, even stuff that is not
shared when you push (like when you rewrite history doing a rebase). You can
use <code>git reflog</code> to see the history of local changes and <code>git reset --hard
REFLOG_ENTRY</code> to go back to where you were.</p>
<h3>About design:</h3>
<ul>
<li>
<p>Avoiding <code>nil</code> is good because it makes your code more predictable and tracebacks
more understandable.</p>
</li>
<li>
<p>When adding tests to a suite, it's important to pay attention at your stubs.
If they are getting complicated, the design can probably be improved in a way
that will render better tests and better production code.</p>
</li>
<li>
<p>When adding extra functions to a 3rd party API, sometimes it's tempting to do
monkey-patching of the library for a small change. It's usually better to use
a wrapper it instead, because later you will probably need more changes and
this will be easier if your production code is already using a wrapper.</p>
</li>
<li>
<p>Isolated tests are good because they run faster, they encourage better design
and code clarity. This is something I've read about repeatedly in the past and
also applied to some of the code I've done myself, so it's not that new. But it
was great to watch someone applying this on several different code bases,
showing some interesting paths -- it inspired me to apply a bit more of this in
my work.</p>
</li>
</ul>
<h3>About Unix:</h3>
<p>To bring a background process to foreground, besides fg, you can also use <code>%N</code>
where N is the job number reported by the command jobs.</p>
<p>You can use the output of a command as if it were a filename, using
<code><(COMMAND)</code>, like so:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>diff<span class="w"> </span><<span class="o">(</span><span class="nb">echo</span><span class="o">)</span><span class="w"> </span><<span class="o">(</span>date<span class="o">)</span>
1c1
<<span class="w"> </span>
---
><span class="w"> </span>Sat<span class="w"> </span>Jan<span class="w"> </span><span class="m">17</span><span class="w"> </span><span class="m">18</span>:47:48<span class="w"> </span>BRST<span class="w"> </span><span class="m">2015</span>
</code></pre></div>
<p>The shell will run the commands and pass to the program file descriptors
with the proper contents, which you can verify doing:</p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><<span class="o">(</span>ls<span class="w"> </span>-l<span class="o">)</span><span class="w"> </span><<span class="o">(</span>ls<span class="w"> </span>-l<span class="o">)</span>
/dev/fd/63
/dev/fd/62
</code></pre></div>
<p>This is useful for commands like diff that need more than one input file (and
therefore can't just use the stdin), to use it with arbitrary stuff generated
from other commands.</p>
<p>I found this specially helpful for when I want to refactor a script: before I
make changes, I store its original output in a file and then while refactoring
I keep comparing the output of the script with the file to see if I'm not
breaking anything:</p>
<div class="highlight"><pre><span></span><code><span class="gh">diff <(./my_script) original.txt</span>
</code></pre></div>
<p>It can also be useful to see differences between two different versions of
the same web application or sites:</p>
<div class="highlight"><pre><span></span><code><span class="gh">diff <(curl -s http://somesite.com) <(curl -s http://anothersite.com)</span>
</code></pre></div>
<h3>About vim:</h3>
<p>It's nice to see people using vim well, because I can compare with my own
habits and see things where I can improve. Gary seems to strive to keep a tight
feedback loop in everything he's doing, so seeing him using vim and the shell
to build things in this fashion is pretty cool. I see it as a nice validation
for the choice of tools.</p>
<p>I found myself using splits a bit more, after watching the screencasts. I'm
more used to using vim tabs, mostly because I'm not much comfortable with stuff
happening outside my view. This is probably something I can work better if I
grow some tolerance for it.</p>
<p>Apart from this, I stole a bunch of vim functions and ideas from <a href="https://github.com/garybernhardt/dotfiles">Gary's
dotfiles</a>, which I also share in <a href="https://github.com/eliasdorneles/dotfiles">my
dotfiles</a>.</p>The Visual Display of Quantitative Information, or How to Make Better Graphs2014-10-12T17:42:00+02:002014-10-12T17:42:00+02:00Elias Dornelestag:eliasdorneles.com,2014-10-12:/2014/10/12/the-visual-display-of-quantitative-information-or-how-to-make-better-graphs.html<p><a href="https://www.edwardtufte.com/tufte/books_vdqi">The Visual Display
of Quantitative Information</a>,
by <a href="https://www.edwardtufte.com/">Edward Tufte</a>, is a beautiful book. It's not
just well-written, it's really beautiful, you feel like every inch of the book
was planned and designed with great care. The book makes the case for better
data graphics, shows you several examples of great …</p><p><a href="https://www.edwardtufte.com/tufte/books_vdqi">The Visual Display
of Quantitative Information</a>,
by <a href="https://www.edwardtufte.com/">Edward Tufte</a>, is a beautiful book. It's not
just well-written, it's really beautiful, you feel like every inch of the book
was planned and designed with great care. The book makes the case for better
data graphics, shows you several examples of great graphics (some of them were
published centuries ago), plus some bad examples and how to improve them.</p>
<p><a href="https://www.edwardtufte.com/tufte/books_vdqi">
<img src="https://www.edwardtufte.com/tufte/graphics/vdqi_bookcover.gif" align="right" />
</a></p>
<p>After reading it, I feel much more prepared to create graphs and choose better
visualizations for the different kinds of data that may end up on my lap. Also,
while reading the book, I got a lot of ideas for new things to try – I don't
know if I'll ever be able to actually implement them, but it's been refreshing
anyway.</p>
<p>I've put down a few notes from the book just to whet your appetite, so here
you are.</p>
<h3>Good graphics tell a story</h3>
<p>Data graphics are not about aesthetic sensibility of the artist who created it,
nor making boring data a bit more fun. Great data graphics tell you a story
about something, communicates complex stuff in a clear way, makes you wonder
about the data on display, there is no need for distracting decorations.</p>
<p>That's also why good graphics are often about multivariate and complex data,
bringing new ways to look at it, enabling you to make comparisons and reason
about it.</p>
<p>A nice example used throughout the book is <a href="https://en.wikipedia.org/wiki/Charles_Joseph_Minard#Work">the graphic by Charles Minard
showing Napoleon's disastrous attempt to conquer
Russia</a>:</p>
<p><a href="https://en.wikipedia.org/wiki/File:Minard.png"><img alt="900px-Minard.png" src="https://lh4.googleusercontent.com/D1zpfFIzj6ExFTso1a4fCr7RA2PWSQQ2FIBbNu03Ey1CPKzkumOdT7eiXhw7i116WelNxBRtMFXJXljwR0ZC6aXKE1_HSj90_gkgY9uLEymrRjS5ssDGdd3SoDLeyTwdJA"></a></p>
<h3>Good graphics don't lie</h3>
<p>It's all about conveying precise information, so any tricks to distract the
viewer from the truth are a bad idea. It's not much different than the written
words, after all.</p>
<p>Therefore, when constructing data graphics, make the physical representation of
numbers in the paper or the screen always directly proportional to the
quantities they represent. Do not bend rules in a way that may distort the data
and induce erroneous comparisons. Do not use 2D graphics for 1D data. Finally,
do not quote data out of context: show the full history of the measurements and
take inflation into account when showing money-over-time.</p>
<h3>Above all else show the data</h3>
<p><a href="https://www.infovis-wiki.net/index.php/Data-Ink_Ratio">Data-ink ratio</a> is the
proportion of a graphic's ink devoted to the non-redundant display of
data-information. Namely, it represents the parts of a graphic that cannot be
erased without loss of information.</p>
<p>The process of creating a great data graphic involves maximizing the data-ink
ratio, reducing all the non-relevant information.The folks at <a href="https://darkhorseanalytics.com/">DarkHorse
Analytics</a> have done a good demonstration of
this in <a href="https://speakerdeck.com/cherdarchuk">their neat Remove to Improve
slideshows</a> (<a href="https://darkhorseanalytics.com/blog/">read more about it on their
blog</a>).</p>
<h3>Friendly data graphics are accessible</h3>
<p>And this does not mean that you should "dumb down" the graphic to make it more
accessible, but that you need to have the viewer in mind while constructing it.</p>
<p>Therefore, you will spell out the words instead of using abbreviations,
annotate the graphic with helpful little messages instead of requiring
elaborated legends, use colors in a way that color-deficient people can also
make sense of the graphic (tip: use red-blue instead of red-green for
contrast), use clear, precise and modest font types, upper-and-lower case and
with serifs.</p>
<p>Liked it? <a href="https://www.amazon.com/The-Visual-Display-Quantitative-Information/dp/0961392142">Buy the book and read
it</a>,
it's worthy it.</p>
<p>Thanks <a href="https://twitter.com/skywy">Paul</a>, for the great book recommendation. =)</p>Web Scraping with Scrapy - first steps2014-08-30T19:29:00+02:002014-08-30T19:29:00+02:00Elias Dornelestag:eliasdorneles.com,2014-08-30:/2014/08/30/web-scraping-with-scrapy---first-steps.html<p><strong>Update:</strong> This tutorial isn't up to date with the latest and greatest of Scrapy. You should follow <a href="https://docs.scrapy.org/en/latest/intro/overview.html">the official documentation instead</a>, I've worked together with other Scrapy developers to make it better. I'm leaving this article online for archival purposes only.</p>
<p><sub><a href="https://pythonhelp.wordpress.com/2014/08/05/web-scraping-com-scrapy-primeiros-passos/">Leia a versão em Português</a></sup></p>
<hr>
<p>Imagine you want to …</p><p><strong>Update:</strong> This tutorial isn't up to date with the latest and greatest of Scrapy. You should follow <a href="https://docs.scrapy.org/en/latest/intro/overview.html">the official documentation instead</a>, I've worked together with other Scrapy developers to make it better. I'm leaving this article online for archival purposes only.</p>
<p><sub><a href="https://pythonhelp.wordpress.com/2014/08/05/web-scraping-com-scrapy-primeiros-passos/">Leia a versão em Português</a></sup></p>
<hr>
<p>Imagine you want to extract content from the Web that isn't all in only one
page: you need a way tonavigate through the site to get to the pages that
contain the useful information. For example, maybe you want to get the
latest <a href="http://mentalfloss.com/big-questions">"big questions" articles</a> of
the <a href="http://mentalfloss.com/">Mental Floss</a> website, but only those in
theOrigins andFact Check categories.</p>
<p><img alt="mentalfloss-big-questions.png" src="https://lh6.googleusercontent.com/AjDSrHs8cDBjc7KfD2ljUpYm42lwClr3PSU2baGiDcDIUVWScyD7TfEKqeTA8gi3mzCik0tljsRj5QV-dl2kH1n2F15IME_OFqFOwUNhgPqcYLFZ_GsHF31HFekHUysQ3g"></p>
<p>If you have an interest in Python and web scraping, you may have already played
with the nice <a href="http://docs.python-requests.org/">requests library</a> to get
content of pages from the Web. Maybe you have toyed around using
<a href="http://www.crummy.com/software/BeautifulSoup/">BeautifulSoup</a> or
<a href="http://lxml.de/">lxml</a> to make the content extraction easier. Well, now we are
going to show you how to use the <a href="http://scrapy.org/">Scrapy framework</a>, which
has all these functionalities and many more, so that solving the sort of
problem we introduced above is a walk in the park.</p>
<p>It is worth noting that Scrapy tries not only to solve the content extraction
(called <a href="https://en.wikipedia.org/wiki/Web_scraping">scraping</a>), but also the
navigation to the relevant pages for the extraction
(called <a href="https://en.wikipedia.org/wiki/Web_crawler">crawling</a>). To achieve that,
a core concept in the framework is theSpider -- in practice, a Python object
with a few special features, for which you write the code and the framework is
responsible for triggering it.</p>
<p>Just so that you have an idea of what it looks like, come on take a peek at the
code of a little program below that uses Scrapy to extract some information
(link, title and number of views) from a YouTube channel. Don't worry about
understanding this code yet, we're just showing it here so that you have a
feeling of a code using Scrapy. By the end of this tutorial, you'll be able to
understand and write programs like this one. =)</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">scrapy</span>
<span class="kn">from</span> <span class="nn">scrapy.contrib.loader</span> <span class="kn">import</span> <span class="n">ItemLoader</span>
<span class="k">class</span> <span class="nc">YoutubeVideo</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Item</span><span class="p">):</span>
<span class="n">link</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">title</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">views</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">YoutubeChannelLister</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Spider</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="s1">'youtube-channel-lister'</span>
<span class="n">youtube_channel</span> <span class="o">=</span> <span class="s1">'LongboardUK'</span>
<span class="n">start_urls</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'https://www.youtube.com/user/</span><span class="si">%s</span><span class="s1">/videos'</span> <span class="o">%</span> <span class="n">youtube_channel</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="k">for</span> <span class="n">sel</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s2">"ul#channels-browse-content-grid > li"</span><span class="p">):</span>
<span class="n">loader</span> <span class="o">=</span> <span class="n">ItemLoader</span><span class="p">(</span><span class="n">YoutubeVideo</span><span class="p">(),</span> <span class="n">selector</span><span class="o">=</span><span class="n">sel</span><span class="p">)</span>
<span class="n">loader</span><span class="o">.</span><span class="n">add_xpath</span><span class="p">(</span><span class="s1">'link'</span><span class="p">,</span> <span class="s1">'.//h3/a/@href'</span><span class="p">)</span>
<span class="n">loader</span><span class="o">.</span><span class="n">add_xpath</span><span class="p">(</span><span class="s1">'title'</span><span class="p">,</span> <span class="s1">'.//h3/a/text()'</span><span class="p">)</span>
<span class="n">loader</span><span class="o">.</span><span class="n">add_xpath</span><span class="p">(</span><span class="s1">'views'</span><span class="p">,</span> <span class="s2">".//ul/li[1]/text()"</span><span class="p">)</span>
<span class="k">yield</span> <span class="n">loader</span><span class="o">.</span><span class="n">load_item</span><span class="p">()</span>
</code></pre></div>
<p>Before we talk more about Scrapy, make sure you have the latest version
installed using the command (depending on your environment, you may need to use
<code>sudo</code> or the <code>--user</code> option for <code>pip install</code>):</p>
<div class="highlight"><pre><span></span><code>pip install --upgrade scrapy
</code></pre></div>
<blockquote>
<p><strong>Note:</strong> depending on your Python environment, the installation may be a bit
tricky because of the dependency on <a href="https://twistedmatrix.com/">Twisted</a>. If
you use Windows, check out <a href="http://scrapy.readthedocs.org/en/latest/intro/install.html#platform-specific-installation-notes">the specific instructions in the official
installation
guide</a>.
If you use a Debian-based Linux distro, you may want to use the <a href="http://scrapy.readthedocs.org/en/latest/topics/ubuntu.html#topics-ubuntu">official
Scrapy APT
repository</a>.</p>
</blockquote>
<p>To be able to follow this tutorial, you'll need Scrapy version 0.24 or above.
You can check your installed Scrapy version using the command:</p>
<div class="highlight"><pre><span></span><code><span class="n">python</span> <span class="o">-</span><span class="n">c</span> <span class="s1">'import scrapy; print scrapy.__version__'</span>
</code></pre></div>
<p>The output of this command in the environment we used for this tutorial is like
this:</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span> <span class="n">python</span> <span class="o">-</span><span class="n">c</span> <span class="s1">'import scrapy; print scrapy.__version__'</span>
<span class="mf">0.24.2</span>
</code></pre></div>
<h3>The anatomy of a spider</h3>
<p><center><img alt="anatomy of a spider" width="400" src="https://lh6.googleusercontent.com/1OLnj7-I1_85hnfnovq6WbRDl3EQTs2xNxc_QpAZ7x2_twrGG0Olb3ZYG7wxA-QFaJVlxfLxNa14yVFSY4JxmlnTVLSJQ30isc4oifxUnFawhQC3PrIGhYxPOayRJHutZg" /></center></p>
<p>A Scrapy spider is responsible for defining how to follow the links
"navigating" through a website (that's the so-called crawling part) and how to
extract the information from the pages into Python data structures.</p>
<p>To define a minimal spider, create a class extending
<a href="http://doc.scrapy.org/en/latest/topics/spiders.html#scrapy.spider.Spider">scrapy.Spider</a>
and give it a name using thename attribute:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">scrapy</span>
<span class="k">class</span> <span class="nc">MinimalSpider</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Spider</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""The smallest Scrapy-Spider in the world!"""</span>
<span class="n">name</span> <span class="o">=</span> <span class="s1">'minimal'</span>
</code></pre></div>
<p>Put this in a file with the name <code>minimal.py</code> and run your spider to check if
everything is okay, using the command:</p>
<div class="highlight"><pre><span></span><code>scrapy runspider minimal.py
</code></pre></div>
<p>If everything is fine, you'll see in the screen some messages from the log
marked as <code>INFO</code> and <code>DEBUG.</code> If there is any message marked as <code>ERROR</code>, it
means that there is something wrong and you need to check for errors in your
spider code.</p>
<p>The life of a spider starts with the generation of HTTP requests (<a href="http://doc.scrapy.org/en/latest/topics/request-response.html">Request
objects</a>) to put
in motion the framework engine. The part of the spider responsible for this is
the <code>start_requests()</code> method, that returns an
<a href="https://docs.python.org/2/glossary.html#term-iterable">iterable</a> with the
first requests to be done for the spider.</p>
<p>Adding this element to our minimal spider, we have:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">scrapy</span>
<span class="k">class</span> <span class="nc">MinimalSpider</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Spider</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""The smallest Scrapy-Spider of the world, maybe"""</span>
<span class="n">name</span><span class="o">=</span><span class="s1">'minimal'</span>
<span class="k">def</span> <span class="nf">start_requests</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">[</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="k">for</span> <span class="n">url</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">'http://www.google.com'</span><span class="p">,</span> <span class="s1">'http://www.yahoo.com'</span><span class="p">]]</span>
</code></pre></div>
<p>The <code>start_requests()</code> method must return an
<a href="https://docs.python.org/2/glossary.html#term-iterable">iterable</a> of
<a href="http://doc.scrapy.org/en/latest/topics/request-response.html">scrapy.Request</a>
objects, which represent an HTTP request to be made by the framework (these
contain data like URL, parameters, cookies, etc) and define a function to be
called when the request is complete -- a callback.</p>
<p><strong>Note:</strong> if you are familiar with implementing AJAX in JavaScript, this way of
work dispatching requests and registering callbacks may sound familiar.</p>
<p>In our example, we return a simple list of requests to Google and Yahoo
websites, but the <code>start_requests()</code> method could also be implemented as a <a href="https://wiki.python.org/moin/Generators">Python
generator</a>.</p>
<p>If you have tried to execute the example like it is now, you may noticed that
there is something still missing, because Scrapy will show two messages marked
as ERROR, complaining that a method was not implemented:</p>
<div class="highlight"><pre><span></span><code><span class="o">...</span>
<span class="w"> </span><span class="nx">File</span>
<span class="s">"/home/elias/.virtualenvs/scrapy/local/lib/python2.7/site-packages/scrapy/spider.py"</span><span class="p">,</span>
<span class="nx">line</span><span class="w"> </span><span class="mi">56</span><span class="p">,</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="nx">parse</span>
<span class="w"> </span><span class="nx">raise</span><span class="w"> </span><span class="nx">NotImplementedError</span>
<span class="nx">exceptions</span><span class="p">.</span><span class="nx">NotImplementedError</span><span class="p">:</span>
</code></pre></div>
<p>This happens because, as we didn't register a callback for the Request objects,
Scrapy tried to call the default callback, which is the <code>parse()</code> method of the
Spider object. Let's add this method to our minimal spider, so that we can
execute it:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">scrapy</span>
<span class="k">class</span> <span class="nc">MinimalSpider</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Spider</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""The 2nd smallest Scrapy-Spider of the world!"""</span>
<span class="n">name</span> <span class="o">=</span> <span class="s1">'minimal'</span>
<span class="k">def</span> <span class="nf">start_requests</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="k">for</span> <span class="n">url</span> <span class="ow">in</span> <span class="p">[</span><span class="s1">'http://www.google.com'</span><span class="p">,</span> <span class="s1">'http://www.yahoo.com'</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s1">'GETTING URL: </span><span class="si">%s</span><span class="s1">'</span><span class="o">%</span> <span class="n">response</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
</code></pre></div>
<p>Now, when you execute it using the command:scrapy runspider minimal.py you
should see something like this in the output:</p>
<div class="highlight"><pre><span></span><code><span class="mi">2014</span><span class="o">-</span><span class="mi">07</span><span class="o">-</span><span class="mi">26</span><span class="w"> </span><span class="mi">15</span><span class="err">:</span><span class="mi">39</span><span class="err">:</span><span class="mi">56</span><span class="o">-</span><span class="mi">0300</span><span class="w"> </span><span class="o">[</span><span class="n">minimal</span><span class="o">]</span><span class="w"> </span><span class="nl">DEBUG</span><span class="p">:</span><span class="w"> </span><span class="n">Crawled</span><span class="w"> </span><span class="p">(</span><span class="mi">200</span><span class="p">)</span><span class="w"> </span><span class="o"><</span><span class="k">GET</span><span class="w"> </span><span class="nl">http</span><span class="p">:</span><span class="o">//</span><span class="n">www</span><span class="p">.</span><span class="n">google</span><span class="p">.</span><span class="n">com</span><span class="p">.</span><span class="n">br</span><span class="o">/</span><span class="vm">?</span><span class="n">gfe_rd</span><span class="o">=</span><span class="n">cr</span><span class="o">&</span><span class="n">ei</span><span class="o">=</span><span class="n">_PXTU8f6N4mc8Aas1YDABA</span><span class="o">></span><span class="w"> </span><span class="p">(</span><span class="nl">referer</span><span class="p">:</span><span class="w"> </span><span class="k">None</span><span class="p">)</span>
<span class="mi">2014</span><span class="o">-</span><span class="mi">07</span><span class="o">-</span><span class="mi">26</span><span class="w"> </span><span class="mi">15</span><span class="err">:</span><span class="mi">39</span><span class="err">:</span><span class="mi">56</span><span class="o">-</span><span class="mi">0300</span><span class="w"> </span><span class="o">[</span><span class="n">minimal</span><span class="o">]</span><span class="w"> </span><span class="nl">DEBUG</span><span class="p">:</span><span class="w"> </span><span class="n">GETTING</span><span class="w"> </span><span class="nl">URL</span><span class="p">:</span><span class="w"> </span><span class="nl">http</span><span class="p">:</span><span class="o">//</span><span class="n">www</span><span class="p">.</span><span class="n">google</span><span class="p">.</span><span class="n">com</span><span class="p">.</span><span class="n">br</span><span class="o">/</span><span class="vm">?</span><span class="n">gfe_rd</span><span class="o">=</span><span class="n">cr</span><span class="o">&</span><span class="n">ei</span><span class="o">=</span><span class="n">_PXTU8f6N4mc8Aas1YDABA</span>
<span class="mi">2014</span><span class="o">-</span><span class="mi">07</span><span class="o">-</span><span class="mi">26</span><span class="w"> </span><span class="mi">15</span><span class="err">:</span><span class="mi">39</span><span class="err">:</span><span class="mi">57</span><span class="o">-</span><span class="mi">0300</span><span class="w"> </span><span class="o">[</span><span class="n">minimal</span><span class="o">]</span><span class="w"> </span><span class="nl">DEBUG</span><span class="p">:</span><span class="w"> </span><span class="n">Redirecting</span><span class="w"> </span><span class="p">(</span><span class="mi">302</span><span class="p">)</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="o"><</span><span class="k">GET</span><span class="w"> </span><span class="nl">https</span><span class="p">:</span><span class="o">//</span><span class="n">br</span><span class="p">.</span><span class="n">yahoo</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="vm">?</span><span class="n">p</span><span class="o">=</span><span class="n">us</span><span class="o">></span><span class="w"> </span><span class="k">from</span><span class="w"> </span><span class="o"><</span><span class="k">GET</span><span class="w"> </span><span class="nl">https</span><span class="p">:</span><span class="o">//</span><span class="n">www</span><span class="p">.</span><span class="n">yahoo</span><span class="p">.</span><span class="n">com</span><span class="o">/></span>
<span class="mi">2014</span><span class="o">-</span><span class="mi">07</span><span class="o">-</span><span class="mi">26</span><span class="w"> </span><span class="mi">15</span><span class="err">:</span><span class="mi">39</span><span class="err">:</span><span class="mi">58</span><span class="o">-</span><span class="mi">0300</span><span class="w"> </span><span class="o">[</span><span class="n">minimal</span><span class="o">]</span><span class="w"> </span><span class="nl">DEBUG</span><span class="p">:</span><span class="w"> </span><span class="n">Crawled</span><span class="w"> </span><span class="p">(</span><span class="mi">200</span><span class="p">)</span><span class="w"> </span><span class="o"><</span><span class="k">GET</span><span class="w"> </span><span class="nl">https</span><span class="p">:</span><span class="o">//</span><span class="n">br</span><span class="p">.</span><span class="n">yahoo</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="vm">?</span><span class="n">p</span><span class="o">=</span><span class="n">us</span><span class="o">></span><span class="w"> </span><span class="p">(</span><span class="nl">referer</span><span class="p">:</span><span class="w"> </span><span class="k">None</span><span class="p">)</span>
<span class="mi">2014</span><span class="o">-</span><span class="mi">07</span><span class="o">-</span><span class="mi">26</span><span class="w"> </span><span class="mi">15</span><span class="err">:</span><span class="mi">39</span><span class="err">:</span><span class="mi">58</span><span class="o">-</span><span class="mi">0300</span><span class="w"> </span><span class="o">[</span><span class="n">minimal</span><span class="o">]</span><span class="w"> </span><span class="nl">DEBUG</span><span class="p">:</span><span class="w"> </span><span class="n">GETTING</span><span class="w"> </span><span class="nl">URL</span><span class="p">:</span><span class="w"> </span><span class="nl">https</span><span class="p">:</span><span class="o">//</span><span class="n">br</span><span class="p">.</span><span class="n">yahoo</span><span class="p">.</span><span class="n">com</span><span class="o">/</span><span class="vm">?</span><span class="n">p</span><span class="o">=</span><span class="n">us</span>
</code></pre></div>
<p>To make our code even cleaner, we can take advantage of the default
implementation of <code>start_requests()</code>: if you don't define it, Scrapy will
create requests for a list of URLs in the attribute named <code>start_urls</code> -- the
same kind of thing we're doing above. So, we'll keep the same functionality and
reduce the code, using:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">scrapy</span>
<span class="k">class</span> <span class="nc">MinimalSpider</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Spider</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""A menor Scrapy-Aranha do mundo!"""</span>
<span class="n">name</span> <span class="o">=</span> <span class="s1">'minimal'</span>
<span class="n">start_urls</span> <span class="o">=</span> <span class="p">[</span>
<span class="s1">'http://www.google.com'</span><span class="p">,</span>
<span class="s1">'http://www.yahoo.com'</span><span class="p">,</span>
<span class="p">]</span>
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s1">'GETTING URL: </span><span class="si">%s</span><span class="s1">'</span><span class="o">%</span> <span class="n">response</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
</code></pre></div>
<p>Like in the <code>parse()</code> method shown above, every callback gets the content of
the HTTP response as an argument (in a
<a href="http://scrapy.readthedocs.org/en/latest/topics/request-response.html#scrapy.http.Response">Response</a>
object). So, inside this callback, where we already have the content of the
page, that's where we'll do the information extraction, i.e., the data scraping
itself.</p>
<p><center><img alt="Little kid smiling: I can't wait to write my own spider to watch prices of games for my new console!" width="500" src="https://lh3.googleusercontent.com/fTtt8VFXX5jcaTlMj9okmgKJxovkhZhKO392KqHkopX0oCmpPp0d8HA9tBY7vkTvE8NXlYR2NjAyeRJF0FW3A3BE01uI2YMH1Pkcq369Sx9pgARuSKH71mHM5TEumlOqFw" /></center></p>
<h3>Callbacks, Requests & Items</h3>
<p>Functions registered as callbacks for the requests can return an iterable of
objects, in which every object can be:</p>
<ul>
<li>
<p>an instance of a subclass of
<a href="http://doc.scrapy.org/en/latest/topics/items.html">scrapy.Item</a>, which you
define to contain the data to be collected from the page</p>
</li>
<li>
<p>an object of type
<a href="http://doc.scrapy.org/en/latest/topics/request-response.html">scrapy.Request</a>
representing yet another request to be made (possibly registering
anothercallback)</p>
</li>
</ul>
<p>With this mechanism of requests and callbacks that may generate new requests
(with new callbacks), you can program the navigation through a site
generating requests for the links to be followed, until getting to the
pages that contain the items you're interested. For example, for a
spider that needs to extract products from the website of an online
store navigating through categories, you could use a structure like the
following:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">scrapy</span>
<span class="k">class</span> <span class="nc">SkeletonSpider</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Spider</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="s1">'spider-mummy'</span>
<span class="n">start_urls</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'http://www.some-online-webstore.com'</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="p">[</span><span class="o">...</span><span class="p">]:</span>
<span class="n">url_category</span> <span class="o">=</span> <span class="o">...</span>
<span class="k">yield</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="n">url_category</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">parse_category_page</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">parse_category_page</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="k">for</span> <span class="n">p</span> <span class="ow">in</span> <span class="p">[</span><span class="o">...</span><span class="p">]:</span>
<span class="n">url_product</span> <span class="o">=</span> <span class="o">...</span>
<span class="k">yield</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="n">url_product</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">parse_product</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">parse_product</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="o">...</span>
</code></pre></div>
<p>In the above structure, the default callback --parse() method -- handles the
response of the first request to the online store website and generates new
requests for the pages of the categories, registering another callback to
handle them -- the <code>parse_category_page()</code> method. This last method does
something similar, generating the requests for the product pages, this time
registering a callback that extracts the item objects with the product data.</p>
<h4>Why do I need to define classes for the items?</h4>
<p>Scrapy proposes that you create a few classes that represent the items you
intend to extract from the pages. For example, if you want to extract the
prices and details of products from an online store, you could use a class like
the following:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">scrapy</span>
<span class="k">class</span> <span class="nc">Product</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Item</span><span class="p">)</span>
<span class="n">description</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">price</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">brand</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">category</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
</code></pre></div>
<p>As you can see, the item classes are just subclasses
from <a href="http://doc.scrapy.org/en/latest/topics/items.html">scrapy.Item</a> in which
you add the desired fields (instances of the
class <a href="http://doc.scrapy.org/en/latest/topics/items.html#scrapy.item.Field">scrapy.Field</a>).
You can then use an instance of this class like if it were a Python dictionary:</p>
<div class="highlight"><pre><span></span><code>>>> p = Product()
>>> p['price'] = 13
>>> print p
{'price':13}
</code></pre></div>
<p>The biggest difference from a traditional dictionary is that an Item by default
does not allow you to assign a value to a key that was not declared as a field:</p>
<div class="highlight"><pre><span></span><code>>>> p['silly_walk']=54
...
KeyError:'Product does not support field: silly_walk'
</code></pre></div>
<p>The advantage of defining classes for items is that it allows you to take
advantage of other features of the framework that works for these classes. For
example, <a href="http://scrapy.readthedocs.org/en/latest/topics/feed-exports.html">you can use the feed exports
mechanism</a> to
export the collected items to <a href="https://en.wikipedia.org/wiki/JSON">JSON</a>,
<a href="https://en.wikipedia.org/wiki/Comma-separated_values">CSV</a>,
<a href="https://en.wikipedia.org/wiki/XML">XML</a>, etc. You can also exploit the <a href="http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html">item
pipeline</a>
features, that allows you to plug-in other processing on top of the collected
items (things like validating the extracted data, removing duplicated items,
storing in a database, etc).</p>
<p>Now, let's do some scraping!</p>
<p>To do the scraping itself, i.e., extracting the data from the page, it's nice
if you know <a href="https://en.wikipedia.org/wiki/XPath">XPath</a>, a language created for
doing queries in XML content which is core to the <a href="http://doc.scrapy.org/en/latest/topics/selectors.html">selectors mechanism of the
framework</a>. If you
don't know XPath, you can use <a href="https://en.wikipedia.org/wiki/Cascading_Style_Sheets#Selector">CSS
selectors</a> in
Scrapy just as well. We encourage you to learn some XPath nevertheless, because
it allows for expressions much more powerful than just CSS (in fact, the CSS
functionality in Scrapy works by converting your CSS expressions to XPath
expressions). We'll put some links to useful resources about these at the end
of the article.</p>
<p>So, you can test the result of XPath or CSS expressions for a page using the
<a href="http://doc.scrapy.org/en/latest/topics/shell.html">Scrapy shell</a>. Run the
command:</p>
<div class="highlight"><pre><span></span><code>scrapy shell http://stackoverflow.com
</code></pre></div>
<p>This command makes a request to the informed URL and opens a Python shell (or
IPython, if you have it installed) while making available some objects for you
to explore. The most important object is the variable <code>response</code>, which contains
the response of the HTTP request and corresponds to theresponse argument
received by the callbacks.</p>
<p><center><img width="500" alt="Happy dog: dude!! it even has a shell!! love the shell! love the shell! love the shell!" src="https://lh3.googleusercontent.com/kdW_fmpWTyloxYfesyGVQdB-rx54lM-r1LIptocDvhxd6TsJ3__w4mWXMHI6o8SXvaO3tN19HhIf9kZ7iwZTztRpdF8g6HoHNA6aer7E-mk8jlM63o8taJVdPSA9EooORg" /></center></p>
<div class="highlight"><pre><span></span><code><span class="o">>>></span><span class="w"> </span><span class="nt">response</span><span class="p">.</span><span class="nc">url</span>
<span class="s1">'http://stackoverflow.com'</span>
<span class="o">>>></span><span class="w"> </span><span class="nt">response</span><span class="p">.</span><span class="nc">headers</span>
<span class="p">{</span><span class="err">'Cache-Control':'public,</span><span class="w"> </span><span class="err">no-cache="Set-Cookie",</span><span class="w"> </span><span class="err">max-age=49',</span>
<span class="err">'Content-Type':'text/html</span><span class="p">;</span><span class="w"> </span><span class="err">charset=utf-8',</span>
<span class="err">'Date':'Sat,</span><span class="w"> </span><span class="err">09</span><span class="w"> </span><span class="err">Aug</span><span class="w"> </span><span class="err">2014</span><span class="w"> </span><span class="err">03:47:31</span><span class="w"> </span><span class="err">GMT',</span>
<span class="err">'Expires':'Sat,</span><span class="w"> </span><span class="err">09</span><span class="w"> </span><span class="err">Aug</span><span class="w"> </span><span class="err">2014</span><span class="w"> </span><span class="err">03:48:20</span><span class="w"> </span><span class="err">GMT',</span>
<span class="err">'Last-Modified':'Sat,</span><span class="w"> </span><span class="err">09</span><span class="w"> </span><span class="err">Aug</span><span class="w"> </span><span class="err">2014</span><span class="w"> </span><span class="err">03:47:20</span><span class="w"> </span><span class="err">GMT',</span>
<span class="err">'Set-Cookie':'prov=5a8741f7-7ee3-4993-b723-72142d48696c</span><span class="p">;</span><span class="w"> </span><span class="err">domain=.stackoverflow.com</span><span class="p">;</span><span class="w"> </span><span class="err">expires=Fri,</span><span class="w"> </span><span class="err">01-Jan-2055</span><span class="w"> </span><span class="err">00:00:00</span><span class="w"> </span><span class="err">GMT</span><span class="p">;</span><span class="w"> </span><span class="err">path=/</span><span class="p">;</span><span class="w"> </span><span class="err">HttpOnly',</span>
<span class="err">'Vary':'*',</span>
<span class="err">'X-Frame-Options':'SAMEORIGIN'</span><span class="p">}</span>
</code></pre></div>
<p>You can use the <code>xpath()</code> and <code>css()</code> methods of the <code>response</code> object to query
the HTML content in the response:</p>
<div class="highlight"><pre><span></span><code>>>> response.xpath('//title') # gets the title via XPath
[<Selector xpath='//title' data=u' '>]
>>> response.css('title')# gets the title via CSS
[<Selector xpath=u'descendant-or-self::title' data=u' '>]
>>> len(response.css('div'))# counts the number of div elements
1345
</code></pre></div>
<p>The result of calling one of these methods is a list object containing selector
objects resulting from the query. This list object has an <code>extract()</code> method which
extracts the HTML content from all the selectors together. The selectors, on
the other hand, besides having their own <code>extract()</code> method to extract their
content, also have <code>xpath()</code> and <code>css()</code> methods that you can use to do new queries
in the scope of each selector.</p>
<p>Take a look at the examples below in the same Scrapy shell, that will help
clearing up things a little bit.</p>
<p>Extracts HTML content from <code><title></code> element, calling the <code>extract()</code> method
from the selector list (note that the result is a Python list):</p>
<div class="highlight"><pre><span></span><code>>>><span class="w"> </span>response.xpath('//title').extract()
[u'<span class="nt"><title></span>Stack<span class="w"> </span>Overflow<span class="nt"></title></span>']
</code></pre></div>
<p>Stores the first selector of the result in a variable and calls the <code>extract()</code>
method on the selector (see how the result now is just a string):</p>
<div class="highlight"><pre><span></span><code>>>><span class="w"> </span>title_sel=<span class="w"> </span>response.xpath('//title')[0]
>>><span class="w"> </span>title_sel.extract()
u'<span class="nt"><title></span>Stack<span class="w"> </span>Overflow<span class="nt"></title></span>'
</code></pre></div>
<p>Applies the XPath expression <code>text()</code> to get the text content of the selector,
and calls the extract() method from the resulting list:</p>
<div class="highlight"><pre><span></span><code>>>> title_sel.xpath('text()').extract()
[u'Stack Overflow']
</code></pre></div>
<p>Prints the extraction of the first selector resulting of the XPath expression
<code>text()</code> applied to selector in variable <code>title_sel</code>:</p>
<div class="highlight"><pre><span></span><code>>>> print title_sel.xpath('text()')[0].extract()
StackOverflow
</code></pre></div>
<p>Well, when you have a good grip on this way to work with selectors, the simple
way to extract an item is just to create an instance of the desired Item class
and fill the values obtained using this selectors API.</p>
<p>Here, take a look at the code of a spider using this technique to get the most
frequently asked questions of<a href="http://stackoverflow.com/">StackOverflow</a>:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">scrapy</span>
<span class="kn">import</span> <span class="nn">urlparse</span>
<span class="k">class</span> <span class="nc">Question</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Item</span><span class="p">):</span>
<span class="n">link</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">title</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">excerpt</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">tags</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">StackoverflowTopQuestionsSpider</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Spider</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="s1">'so-top-questions'</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">tag</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="n">questions_url</span> <span class="o">=</span> <span class="s1">'http://stackoverflow.com/questions'</span>
<span class="k">if</span> <span class="n">tag</span><span class="p">:</span>
<span class="n">questions_url</span> <span class="o">+=</span> <span class="s1">'/tagged/</span><span class="si">%s</span><span class="s1">'</span> <span class="o">%</span> <span class="n">tag</span>
<span class="bp">self</span><span class="o">.</span><span class="n">start_urls</span> <span class="o">=</span> <span class="p">[</span><span class="n">questions_url</span> <span class="o">+</span> <span class="s1">'?sort=frequent'</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="n">build_full_url</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">link</span><span class="p">:</span> <span class="n">urlparse</span><span class="o">.</span><span class="n">urljoin</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">url</span><span class="p">,</span> <span class="n">link</span><span class="p">)</span>
<span class="k">for</span> <span class="n">qsel</span> <span class="ow">in</span> <span class="n">response</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s2">"#questions > div"</span><span class="p">):</span>
<span class="n">it</span> <span class="o">=</span> <span class="n">Question</span><span class="p">()</span>
<span class="n">it</span><span class="p">[</span><span class="s1">'link'</span><span class="p">]</span> <span class="o">=</span> <span class="n">build_full_url</span><span class="p">(</span>
<span class="n">qsel</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s1">'.summary h3 > a'</span><span class="p">)</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s1">'@href'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">extract</span><span class="p">())</span>
<span class="n">it</span><span class="p">[</span><span class="s1">'title'</span><span class="p">]</span> <span class="o">=</span> <span class="n">qsel</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s1">'.summary h3 > a::text'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">extract</span><span class="p">()</span>
<span class="n">it</span><span class="p">[</span><span class="s1">'tags'</span><span class="p">]</span> <span class="o">=</span> <span class="n">qsel</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s1">'a.post-tag::text'</span><span class="p">)</span><span class="o">.</span><span class="n">extract</span><span class="p">()</span>
<span class="n">it</span><span class="p">[</span><span class="s1">'excerpt'</span><span class="p">]</span> <span class="o">=</span> <span class="n">qsel</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="s1">'div.excerpt::text'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">extract</span><span class="p">()</span>
<span class="k">yield</span> <span class="n">it</span>
</code></pre></div>
<p>As you can see, the spider defines an Item class named <code>Question</code>, and uses the
Selectors API to iterate through the HTML elements of the questions (obtained
with the CSS selector <code>#questions > div</code>) and generating a Question object for
each one of these elements, filling all the fields (link, title, tags and
question excerpt).</p>
<p>There are two interesting things worth noticing in the extraction done in the
<code>parse()</code> callback: the first one is that we use a pseudo-selector <code>::text</code> to
get the text content of the elements, avoiding the HTML tags. The second is how
we use the function
<a href="https://docs.python.org/2/library/urlparse.html">urlparse.urljoin()</a> to
combine the URL of the request with the content of thehref attribute, making
sure that the result of this will be a correct absolute URL.</p>
<p>Put this code in a file named <code>top_asked_so_questions.py</code> and run it using the
command:</p>
<div class="highlight"><pre><span></span><code>scrapy runspider top_asked_so_questions.py -o questions.json
</code></pre></div>
<p>If everything went well, Scrapy will show in the screen the scraped items and
also write a file namedquestions.json containing them. At the end of the
output, you should see some stats, including the item scraped count:</p>
<div class="highlight"><pre><span></span><code><span class="mi">2014</span><span class="o">-</span><span class="mi">08</span><span class="o">-</span><span class="mi">02</span><span class="w"> </span><span class="mi">14</span><span class="p">:</span><span class="mi">27</span><span class="p">:</span><span class="mi">37</span><span class="o">-</span><span class="mi">0300</span><span class="w"> </span><span class="p">[</span><span class="n">so</span><span class="o">-</span><span class="n">top</span><span class="o">-</span><span class="n">questions</span><span class="p">]</span><span class="w"> </span><span class="n">INFO</span><span class="p">:</span><span class="w"> </span><span class="n">Dumping</span><span class="w"> </span><span class="n">Scrapy</span><span class="w"> </span><span class="n">stats</span><span class="p">:</span>
<span class="w"> </span><span class="p">{</span><span class="s1">'downloader/request_bytes'</span><span class="p">:</span><span class="w"> </span><span class="mi">242</span><span class="p">,</span>
<span class="w"> </span><span class="s1">'downloader/request_count'</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span>
<span class="w"> </span><span class="o">...</span>
<span class="w"> </span><span class="s1">'item_scraped_count'</span><span class="p">:</span><span class="w"> </span><span class="mi">50</span><span class="p">,</span>
<span class="w"> </span><span class="s1">'log_count/DEBUG'</span><span class="p">:</span><span class="w"> </span><span class="mi">53</span><span class="p">,</span>
<span class="w"> </span><span class="s1">'log_count/INFO'</span><span class="p">:</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span>
<span class="w"> </span><span class="o">...</span>
<span class="w"> </span><span class="s1">'start_time'</span><span class="p">:</span><span class="w"> </span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="p">(</span><span class="mi">2014</span><span class="p">,</span><span class="w"> </span><span class="mi">8</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="mi">17</span><span class="p">,</span><span class="w"> </span><span class="mi">27</span><span class="p">,</span><span class="w"> </span><span class="mi">36</span><span class="p">,</span><span class="w"> </span><span class="mi">912002</span><span class="p">)}</span>
<span class="mi">2014</span><span class="o">-</span><span class="mi">08</span><span class="o">-</span><span class="mi">02</span><span class="w"> </span><span class="mi">14</span><span class="p">:</span><span class="mi">27</span><span class="p">:</span><span class="mi">37</span><span class="o">-</span><span class="mi">0300</span><span class="w"> </span><span class="p">[</span><span class="n">so</span><span class="o">-</span><span class="n">top</span><span class="o">-</span><span class="n">questions</span><span class="p">]</span><span class="w"> </span><span class="n">INFO</span><span class="p">:</span><span class="w"> </span><span class="n">Spider</span><span class="w"> </span><span class="n">closed</span><span class="w"> </span><span class="p">(</span><span class="n">finished</span><span class="p">)</span>
</code></pre></div>
<blockquote>
<p><strong>Note:</strong> if you run this twice in a row, you need to remove the output file
<code>questions.json</code> file before each run. This is because Scrapy by default
appends to a file instead of overwriting it, which ends up making the JSON file
unusable. This is done for historical reasons, it made sense for spiders which
used the JSON Lines format (the previous default), and may change in the
future.</p>
</blockquote>
<p><center><img width="500" alt="SO: all your questions are belong to us" src="https://lh5.googleusercontent.com/8wSeSQMfk_DBDrTpejqaBlAhoazIg--pdjDWfk5vcIhB504FSu78MEULRtnuYPN-0FVjuX23OWnqIEzf_j0YorWy42EQcTnUVKfqF9-UfbpSu-nuZ4iXB5m15WPhXqBLXw" /></center></p>
<h4>Arachnoid arguments</h4>
<p>You may have noticed that the class for this spider has a constructor
accepting an optional argument called tag.
We can specify a value for this argument for the spider to get the
frequently asked questions with the python tag, using the <code>-a</code>
option:</p>
<div class="highlight"><pre><span></span><code>scrapy runspider top_asked_so_questions.py -o python-questions.json -a tag=python
</code></pre></div>
<p>Using this little trick you can write generic spiders, so that you just pass
some parameters and get a different result. For example, you may write one
spider for several sites that have the same HTML structure, making the URL of
the site a parameter. Or, a spider for a blog in which the parameters define a
time range of the posts and comments to extract.</p>
<h3>Putting it all together</h3>
<p>In the previous sections, you saw how to do web crawling with Scrapy,
navigating through the pages of a site using the mechanism of requests and
callbacks. You also saw how to use the <a href="http://doc.scrapy.org/en/latest/topics/selectors.html">Selector
API</a> to extract the
content of a page into items and execute the spider using the commandscrapy
runspider.</p>
<p>Now, we shall put it all together in a spider that solves the problem we
presented in the introduction: let's scrape the latest "big questions" articles
from <a href="http://mentalfloss.com/">mentalfloss.com</a>, offering an option to inform
the category (<a href="http://mentalfloss.com/big-questions/origins">Origins</a>, <a href="http://mentalfloss.com/big-questions/the-body">The
Body</a>, <a href="http://mentalfloss.com/big-questions/fact-check">Fact
Check</a>, etc). This way, if you
just run the spider, it should scrape all the articles in the blog; if you pass
in a category, it should scrape only the articles of that subject.</p>
<blockquote>
<p><strong>Note:</strong> Before writing a spider, it's useful to explore a little bit the
pages of the site using the browser's inspection capabilities and the scrapy
shell, so that you can see how the site is structured and you can also try a
few CSS or XPath expressions in the shell. There are also some browser
extensions that allow you to test XPath expressions directly in a page: <a href="https://chrome.google.com/webstore/detail/xpath-helper/hgimnogjllphhhkhlmebbmlgjoejdpjl?hl=en">XPath
Helper</a>
for Chrome and <a href="https://addons.mozilla.org/en-US/firefox/addon/xpath-checker/">XPath
Checker</a> for
Firefox. Discovering the best way to extract the content of a site using XPath
or CSS is more of an art than a science, therefore we won't try to explain much
here, but it's worthy telling you that you learn a lot after a little
experience.</p>
</blockquote>
<p>Have a look at the final code of the spider:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">scrapy</span>
<span class="kn">import</span> <span class="nn">urlparse</span>
<span class="k">class</span> <span class="nc">Article</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Item</span><span class="p">):</span>
<span class="n">title</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">content</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">link</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">author</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="n">date</span> <span class="o">=</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Field</span><span class="p">()</span>
<span class="k">class</span> <span class="nc">MentalFlossArticles</span><span class="p">(</span><span class="n">scrapy</span><span class="o">.</span><span class="n">Spider</span><span class="p">):</span>
<span class="n">name</span> <span class="o">=</span> <span class="s1">'mentalfloss-articles'</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="n">articles_url</span> <span class="o">=</span> <span class="s1">'http://mentalfloss.com/big-questions'</span>
<span class="k">if</span> <span class="n">category</span><span class="p">:</span>
<span class="n">articles_url</span> <span class="o">+=</span> <span class="s1">'/'</span> <span class="o">+</span> <span class="n">category</span>
<span class="bp">self</span><span class="o">.</span><span class="n">start_urls</span> <span class="o">=</span> <span class="p">[</span><span class="n">articles_url</span><span class="p">]</span>
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Gets the page with the article list,</span>
<span class="sd"> find the article links and generates</span>
<span class="sd"> requests for each article page</span>
<span class="sd"> """</span>
<span class="n">article_links</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span>
<span class="s2">"//header/hgroup/h1/a/@href"</span>
<span class="p">)</span><span class="o">.</span><span class="n">extract</span><span class="p">()</span>
<span class="k">for</span> <span class="n">link</span> <span class="ow">in</span> <span class="n">article_links</span><span class="p">:</span>
<span class="n">article_url</span> <span class="o">=</span> <span class="n">urlparse</span><span class="o">.</span><span class="n">urljoin</span><span class="p">(</span>
<span class="n">response</span><span class="o">.</span><span class="n">url</span><span class="p">,</span> <span class="n">link</span><span class="p">)</span>
<span class="k">yield</span> <span class="n">scrapy</span><span class="o">.</span><span class="n">Request</span><span class="p">(</span><span class="n">article_url</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">extract_article</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">extract_article</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">response</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Gets the article page and extract</span>
<span class="sd"> an item with the article data</span>
<span class="sd"> """</span>
<span class="n">article</span> <span class="o">=</span> <span class="n">Article</span><span class="p">()</span>
<span class="n">css</span> <span class="o">=</span> <span class="k">lambda</span> <span class="n">s</span><span class="p">:</span> <span class="n">response</span><span class="o">.</span><span class="n">css</span><span class="p">(</span><span class="n">s</span><span class="p">)</span><span class="o">.</span><span class="n">extract</span><span class="p">()</span>
<span class="n">article</span><span class="p">[</span><span class="s1">'link'</span><span class="p">]</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">url</span>
<span class="n">article</span><span class="p">[</span><span class="s1">'title'</span><span class="p">]</span> <span class="o">=</span> <span class="n">css</span><span class="p">(</span><span class="s2">"h1.title > span::text"</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">article</span><span class="p">[</span><span class="s1">'date'</span><span class="p">]</span> <span class="o">=</span> <span class="n">css</span><span class="p">(</span><span class="s1">'.date-display-single::text'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">article</span><span class="p">[</span><span class="s1">'content'</span><span class="p">]</span> <span class="o">=</span> <span class="s2">" "</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
<span class="n">css</span><span class="p">(</span><span class="s1">'#content-content p::text'</span><span class="p">))</span>
<span class="n">article</span><span class="p">[</span><span class="s1">'author'</span><span class="p">]</span> <span class="o">=</span> <span class="n">css</span><span class="p">(</span>
<span class="s2">"div.field-name-field-enhanced-authors"</span>
<span class="s2">" a::text"</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">yield</span> <span class="n">article</span>
</code></pre></div>
<p>Just like before, you can run the spider with:</p>
<div class="highlight"><pre><span></span><code>scrapy runspider mentalfloss.py -o articles-all.json
</code></pre></div>
<p>And to get the articles from each section, you can use commands like:</p>
<div class="highlight"><pre><span></span><code>scrapy runspider mentalfloss.py -o articles-origins.json -a category=origins
</code></pre></div>
<p>or:</p>
<div class="highlight"><pre><span></span><code>scrapy runspider mentalfloss.py -o articles-fact-check.json -a category=fact-check
</code></pre></div>
<p>The code for this spider has a very similar structure to the previous one, with
its argument handling and everything.</p>
<p>The main difference is that in this one, the first callback (the <code>parse()</code> method)
generates other requests for the article pages, which are handled by the second
callback: the <code>extract_article()</code> method, which scrapes the article data.</p>
<p>The content extraction also does a little bit more work. We created a <code>css()</code>
helper function to abbreviate calling <code>response.css(<selector>).extract()</code> and
used that to get the result of our selectors to fill the Article item. Note
also how we take advantage of <a href="https://docs.python.org/2/reference/lexical_analysis.html#string-literal-concatenation">Python's feature of concatenating literal
strings</a>
on the CSS selector for the author field, to break it in two lines.</p>
<h3>Final words</h3>
<p>If you made until here, congratulations! Here is a trophy for you:</p>
<p><center><img width="500" alt="Trophy Scrapy apprentice: champion of Reading Long Posts category" src="https://lh3.googleusercontent.com/EboKX-uRyuikN3lI8voa529LP3W6OnHn3vjWi21fvisFEpbuPu-fPY9be1Z3PB_CxT991AL0SquUnypXp4-sbiMTdVY8hiVu_zrbUdFPVhu5BixW6Mu3LUE9Jbz37Jn8Iw" /></center></p>
<p>Now that you have learned to write Scrapy spiders and therefore are enabled to
download the whole Internet to your home PC, try not to get banned by the
website hosts laying around! :)</p>
<p>Visit the <a href="http://doc.scrapy.org/">official documentation for Scrapy</a>, there is
a lot of good stuff there, like <a href="http://scrapy.readthedocs.org/en/latest/intro/tutorial.html">the tutorial teaching you how to create
complete Scrapy
projects</a>,
<a href="http://scrapy.readthedocs.org/en/latest/faq.html">frequently asked questions</a>,
<a href="http://scrapy.readthedocs.org/en/latest/topics/broad-crawls.html">tips for doing huge
crawls</a>, <a href="http://scrapy.readthedocs.org/en/latest/topics/debug.html">how
to debug a spider</a>,
<a href="http://scrapy.readthedocs.org/en/latest/topics/practices.html#avoiding-getting-banned">tips on how to avoid being
banned</a>
and a lot more.</p>
<p><strong>UPDATED:</strong> removed <code>-t json</code> from commands, unnecessary since Scrapy 0.24 (thanks, Mikhail!)</p>
<p><strong>UPDATED:</strong> added note about Scrapy default behavior of appending to output file (thanks again, Mikhail!)</p>
<h4>Useful resources:</h4>
<ul>
<li>
<p><a href="http://doc.scrapy.org/en/latest/">Scrapy Official Documentation</a></p>
</li>
<li>
<p><a href="https://github.com/scrapy/scrapy/wiki">Scrapy Wiki with links to videos, slides, articles and related projects</a></p>
</li>
<li>
<p><a href="http://groups.google.com/group/scrapy-users/">scrapy-users Google Group - mailing list</a> </p>
</li>
<li>
<p><a href="http://zvon.org/comp/r/tut-XPath_1.html">Nice XPath Tutorial</a></p>
</li>
<li>
<p><a href="http://blog.scrapinghub.com/2014/07/17/xpath-tips-from-the-web-scraping-trenches/">Some XPath tips</a></p>
</li>
<li>
<p><a href="http://code.tutsplus.com/tutorials/the-30-css-selectors-you-must-memorize--net-16048">The 30 CSS selectors you need to memorize</a> </p>
</li>
</ul>Steve Yegge's Rantings book2014-08-10T20:20:00+02:002014-08-10T20:20:00+02:00Elias Dornelestag:eliasdorneles.com,2014-08-10:/2014/08/10/steve-yegges-rantings-book.html<p>Those who know me well, know that I'm a bit of a <a href="https://steve-yegge.blogspot.com/">Steve
Yegge</a> fanboy. That's true, I love reading
Steve's mean jokes and I keep coming back to those long blog posts. That dude's
writing has been a great influence to me. I've even started to write long posts …</p><p>Those who know me well, know that I'm a bit of a <a href="https://steve-yegge.blogspot.com/">Steve
Yegge</a> fanboy. That's true, I love reading
Steve's mean jokes and I keep coming back to those long blog posts. That dude's
writing has been a great influence to me. I've even started to write long posts
myself, in a sort of cargo-cult-steve-yegge-wannabe behavior. I'm such a
fanboy. Steve would probably feel embarrassed for me.</p>
<p>Anyway, I discovered a while ago that he has quietly released a book called <a href="http://www.hyperink.com/A-Programmers-Rantings-On-Programminglanguage-Religions-Code-Philosophies-Google-Work-Culture-And-Other-Stuff-b40632A90DD">A
Programmer's Rantings: On Programming-Language Religions, Code Philosophies,
Google Work Culture and Other
Stuff</a>,
which is a collection of some of his articles put together with a few notes
adding a bit more context to each article. It was published by
<a href="http://hyperink.com/">HyperInk</a>, which seems to be a cool company. I bought
the ebook from their website and it offered me to send as a gift to a few
friends, so it was a nice deal.</p>
<p><center>
<a href="http://www.hyperink.com/A-Programmers-Rantings-On-Programminglanguage-Religions-Code-Philosophies-Google-Work-Culture-And-Other-Stuff-b40632A90DD"><img alt="Cover of Steve Yegge's Rantings book" src="https://3.bp.blogspot.com/-fsINtrFzTHs/U-f8-2QOj9I/AAAAAAAAAy4/7sWr2RZ8P8I/s1600/40632A90DD_thumb.jpg" title="A Programmer's Rantings: On Programming-Language Religions, Code Philosophies, Google Work Culture and Other Stuff"></a><a href="https://www.blogger.com/"></a>
</center></p>
<p>And the book is quite a journey. You get to read some of the first essays Steve
wrote when he was pretty unknown (just another bright young fellow at Amazon)
and also his latest rants posted on <a href="https://plus.google.com/110981030061712822816/posts">Google
Plus</a>, including the one
he made public accidentally and it ended up making him kind of famous outside
of the programming circles too.</p>
<p>I enjoyed reading this book a lot, although I suppose it would be expected
for me say that, what with me being a fanboy and all. That being said, it's a
quick read and lot's of fun -- highly recommended! Although it amounts to more
than two hundred pages it still does not make half of the stuff on
<a href="https://sites.google.com/site/steveyegge2/blog-rants">his</a>
<a href="https://steve-yegge.blogspot.com.br/">blogs</a>. So, if you like the book, you'll
probably want to check out the blogs. Or vice-versa, whatever.</p>Tips on Performance and Monitoring of Java Applications2014-06-16T20:06:00+02:002014-06-16T20:06:00+02:00Elias Dornelestag:eliasdorneles.com,2014-06-16:/2014/06/16/tips-on-performance-and-monitoring-of-java-applications.html<p>I cleaned up my desk this weekend and ended up finding some notes I wrote down
some time ago when I attended a course about monitoring JBoss application
servers. I haven't been doing much related to Java Web development lately, but
I'm going to try to make a quick summary …</p><p>I cleaned up my desk this weekend and ended up finding some notes I wrote down
some time ago when I attended a course about monitoring JBoss application
servers. I haven't been doing much related to Java Web development lately, but
I'm going to try to make a quick summary here because: 1) then I can safely
throw away the paper with the notes, and 2) I think some of the tips can still
be useful in the context of many long running JVM processes.</p>
<h3>Memory and GC load</h3>
<p>So, the most important thing to monitor in a long running JVM is arguably the
garbage collection stats. When some JVM is misbehaving, the first thing you
want to check is how much of the
<a href="https://en.wikipedia.org/wiki/Java_virtual_machine#Heap">heap</a> is being used
and how often the full GC is being called.</p>
<p>One quick tip to reduce GC load is to set the initial heap size to the same
amount of the maximum heap size, namely, you should use the same value for the
<code>-Xms</code> and <code>-Xmx</code> JVM options. When you do this the JVM will allocate the
maximum space it will ever use, right from the the start. This way you avoid
memory reallocation for the heap and some GC calls, and can even sometimes
speedup the startup of an application, it is usually the first thing I do when
I install a Java desktop app like Eclipse or Intellij IDEA.</p>
<p>There are
<a href="http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/">some</a>
<a href="http://www.cubrid.org/blog/dev-platform/how-to-monitor-java-garbage-collection/">nice</a>
<a href="http://www.cubrid.org/blog/textyle/428187">articles</a> about garbage collection
in Java available, it's a fairly big topic and I don't know much beyond the
basics to survive. You definitely want to know that full GC stops are bad and,
although you can't avoid them completely, you want to keep them to a minimum so
your application won't keep slogging.</p>
<p>Full GC stops happen when the area of memory reserved to objects that are "old"
(namely, objects that have been around for most of the time and therefore are
probably going to be around in the future) reaches its size limit. That means
that whatever application code was running will be stopped and only the GC will
execute for a moment, until some space is freed and your application code can
execute again (<a href="https://plumbr.eu/blog/understanding-java-lang-outofmemoryerror">or you'll be the misfortunate heir to
anOutOfMemoryError</a>).</p>
<p>As it happens, tuning the garbage collection is very specific to the type of
application you're running. The JVM can use different garbage collection
algorithms, and you may want to twiddle with them a little bit to see what
works best. For your typical Java Web application, it's usually better to run
several machines with moderate memory in a cluster than run all in one big
machine with several GiB of memory due to how the GC works. However, your
mileage may vary, so your best bet is to measure and monitor what's happening
with the heap. </p>
<h3>The number of threads vs backlog tradeoff</h3>
<p>Now, in the case of Web applications, the second most important thing you want
to watch is the busy threads count. Usually, it represents the number of
requests being handled at a given moment. There is an useful tradeoff to be
aware of that has to do with how these things happen inside the Web container,
so bear with me for a little bit with the inaccurate description.</p>
<p>Whenever your application server (or whatever it is you're using to deploy your
Java Web app) gets a new request, it tries to respond as soon as possible
creating a new thread to handle it, right? Then, when the configured maximum
number of threads is reached, all the new requests are kept on a queue
(sometimes called backlog or acceptCount), waiting until one of the current
busy threads finishes so that the server can then get the next request from the
queue and use another thread to handle it.</p>
<p>Well, okay, it's not <em>reaaally</em> like that, I think what
really happens is that each new request always goes to the backlog queue and
there are some threads responsible for request processing that keep getting
work from the backlog, but I thought it would be a bit easier to explain that
way.</p>
<p><center>
<img width="500" alt="I think my Tomcat can handle more work... Now, should I increase maxThreads or the backlog?"
src="https://3.bp.blogspot.com/-1Op2WBzfGno/U5928NTAtqI/AAAAAAAAAwQ/d1lxWxNcmHY/s1600/doubt-maxThreads_vs_backlog.jpg"/>
</center></p>
<p>But here is the little secret: it's usually much easier for the operating
system to manage queues than attend threads. So, often enough it's better to
let the queue get big than to increase the maximum number of threads for your
system to handle. Threads are often competing for resources, increasing its
number may even hurt performance instead of improve it, specially when you have
a peak load.</p>
<p>Of course the best thing to do will depend on the application you are serving
and the load patterns in your server, so you need to measure it and experiment
for a bit to figure out what numbers work best for you.</p>
<p>So, if there is any way to wrap-up all this, it would be: measure it, measure
it, measure it! Different types of long-running JVM applications will have
different effects on your system, so it's important to have data to make good
decisions. Measuring the heap stats to see how the GC is doing and the number
of busy threads to see the patterns in request handling (in the case of Web
applications) is a good start.</p>
<p>Thanks for the review, José Ricardo and Valdir Stumm!</p>
<p><a href="https://www.flickr.com/photos/24141546@N06/8097784516/in/photostream/">Image credits (CCBY)</a></p>So, here is a story2014-06-13T14:00:00+02:002014-06-13T14:00:00+02:00Elias Dornelestag:eliasdorneles.com,2014-06-13:/2014/06/13/so-here-is-a-story.html<p>Soon after graduating, I went to work as a software developer for a big public
company in Brazil. This company is responsible for a huge part of the country's
IT infrastructure, and they keep trying to build a reputation of being
innovative and pro open source, the kind of thing …</p><p>Soon after graduating, I went to work as a software developer for a big public
company in Brazil. This company is responsible for a huge part of the country's
IT infrastructure, and they keep trying to build a reputation of being
innovative and pro open source, the kind of thing that excited me a lot. I
thought: <em>"They
promote Linux and free software... Heck, their website is built with Plone.
I'll get to do cool stuff in Python all day!"</em> I
know it's naive, but that was my thinking back then.</p>
<p>So, initially I thought I had won the lottery. But that feeling didn't take
long to dissipate. What I ended up finding was NOT a place where engineers are
working together on great projects, embracing free software and releasing good
stuff to the world.</p>
<p>That company is weird. And the biggest problem for me was: I was young and
inexperienced, a child basically, surrounded mostly by other children. You
see, most developers there are pretty smart people. But they don't have much
say in the decisions about the software development, arguably the thing they
know best.</p>
<p>The software development department is run mostly by traditional managers who
don't seem to understand how software development actually works. It seems that
it has been on deficit for quite some time, though nobody cares too much --
hey, the taxpayers are still funding it.</p>
<p>So, those managers wanted the Big Ole' Software Factory. You know, those
imaginary places with human machinery resembling an assembly line that if you
set up just right and feed it with the right input, you'll get good software on
the other end.</p>
<p>Well, what they've got is a bunch of talented people managed in a very
paternalistic style. And that leads to painful frustration for the developers
who, being treated like children, end up behaving a lot like children (myself
included, I am ashamed to say).</p>
<p>I don't need to tell you that they don't produce great software. Well, when
they get to ship something, that is. But I'm not talking about the quality of
their software right now.</p>
<p>Right now, my point is: this kind of place is not a good place for someone
trying to grow into a good, mature engineer.</p>
<p>You need a healthy environment to build up maturity and excellence. And an
environment is not healthy if you are encouraged to simply follow orders and
maintain the status quo. Because you won't learn to make better decisions if
you are not supposed to be trusted to decide very basic things, like what
software to install in your development machine.</p>
<p>People at that company end up having serious trust issues with their bosses and
colleagues because of the unhealthy environment. The funny thing is, I think
most people are there because they like the job security, but they don't get to
feel really safe much. At least, not the majority of the people I knew there.
They are often afraid that "someone is out to get them".</p>
<p>I wish I had read the wonderful <a href="http://shop.oreilly.com/product/0636920018025.do">Team Geek
book</a> back then, and I wish
everybody there would read that book now and give it some serious thought. That
would bring some light to several of the issues they have there, and maybe the
place would be better than it is.</p>
<p>I remember getting there full of energy, eager to learn and do stuff.
Somewhere along the way, I kind of lost the will. I remember thinking: "Okay, I
give up, I don't know how to deal with this. I'll remain a mediocre performer,
as that seems what they want around here. I will focus on honing my guitar
skills, so that I won't want to kill myself."</p>
<p>Well, I moved on to greener pastures some time ago, though not before another
experience at another not-so-great government institution. And although I'm not
young anymore, I think I've managed to stay curious and I'm still eager to
learn and do stuff. That's the important thing, right?</p>
<p>But sometimes, looking back at how much I have improved after leaving that
place, I can't help but wonder what if I had never gone there in the first
place? Would I be able to enjoy working, learning and growing as I do now? Or
would I be like so many others out there, whining and thinking I would be
happier enjoying the job security of a public employee?</p>
<p>I guess I'll never know. It's probably better thinking it would be the latter,
though. That way I'll have no regrets. Thanks to my friends who reviewed
this.</p>Failing to finish a book2014-05-31T23:08:00+02:002014-05-31T23:08:00+02:00Elias Dornelestag:eliasdorneles.com,2014-05-31:/2014/05/31/failing-to-finish-a-book.html<p>Okay, here is a book I've been trying to read for almost two months already and
barely get to the half of it. <a href="http://shop.oreilly.com/product/0636920023784.do">Python for Data
Analysis</a> has left me with
mixed feelings. Of all the O'Reilly books I've got until now, this is probably
the one in worst shape …</p><p>Okay, here is a book I've been trying to read for almost two months already and
barely get to the half of it. <a href="http://shop.oreilly.com/product/0636920023784.do">Python for Data
Analysis</a> has left me with
mixed feelings. Of all the O'Reilly books I've got until now, this is probably
the one in worst shape.</p>
<p>It seems that the author (Wes McKinney, the author of the Pandas library -- a
great guy, no doubt, and that obviously possesses an extensive technical
knowledge) did not spend much time trying to get the book more digestible. The
Pandas library is great, kudos to him! The book however seems to be a pretty
half-assed work.</p>
<p>I was unsure if my difficulty reading it was mostly my own failure. But then I
talked to some friends who also read some of it, and they agreed that the book
is a very dry read.</p>
<p>Maybe I am trying to read the book in a suboptimal way (from cover to cover),
but the effort needed to grasp each little subject is making me cringe.</p>
<p>I buy books about technologies because I want a <em>better</em> way to learn them than
having to go through all the documentation. However, reading this book feels
much harder than following through the online documentation of the tools it
documents.</p>
<p>Now, the online docs for Pandas have syntax highlight, hyperlinking and even a
<a href="http://pandas.pydata.org/pandas-docs/stable/10min.html">10 minute tutorial</a>.
Maybe it's more merit for the online docs than demerit for the book, I'm not
sure.</p>
<p>It seems that the book content was written as a bunch of IPython notebooks, and
then everything was later concatenated into a big document in an order that
sort of made sense (and losing the good looks). Its examples are a bunch of
throwaway code, and are not presented in a way that the reader can care about
-- and believe me, I've been trying.</p>
<p>I guess when you are an expert in a subject, it can be hard to remember how it
is to be a beginner again. However, that's precisely the exercise that would
render a great book. I urge all tech authors to read and apply the principles
explained in the <a href="http://headrush.typepad.com/creating_passionate_users/2006/01/crash_course_in.html">Crash Course in Learning
Theory</a>.
This would surely render better books for all of us.</p>
<p>The book is not all bad. I've certainly learned something from it. The effort
to read all of it is just not worth it, though. For anyone who wants to learn
more about NumPy, Scipy and Pandas, my recommendation is to use the online
documentation. Thank you Zé Ricardo for revising this text.</p>Programando Erlang - 1 de Any2014-04-05T23:35:00+02:002014-04-05T23:35:00+02:00Elias Dornelestag:eliasdorneles.com,2014-04-05:/2014/04/05/programando-erlang---1-de-any.html<p>Na virada do ano, uma das minhas resoluções para 2014 foi a de que este ano
aprenderia <a href="http://www.erlang.org/">Erlang</a>. Eu queria brincar com alguma
linguagem que usasse ideias diferentes das que uso no trabalho e que me
ensinasse mais do que simplesmente outro jeito de escrever os programas que já
sei …</p><p>Na virada do ano, uma das minhas resoluções para 2014 foi a de que este ano
aprenderia <a href="http://www.erlang.org/">Erlang</a>. Eu queria brincar com alguma
linguagem que usasse ideias diferentes das que uso no trabalho e que me
ensinasse mais do que simplesmente outro jeito de escrever os programas que já
sei.</p>
<p>Como eu gostei de ler as ideias do <a href="http://joearms.github.io/">Joe Armstrong</a>
no livro <a href="http://www.codersatwork.com/">Coders at Work</a>, e as <a href="https://en.wikipedia.org/wiki/Erlang_(programming_language)">descrições de
Erlang</a> na Internet
me deixaram curioso, resolvi que em 2014 eu iria aprender Erlang. E assim,
decidi por comprar logo o livro <a href="http://pragprog.com/book/jaerlang2/programming-erlang">Programming
Erlang</a>, escrito pelo
próprio Joe, e tentar aprender por ele.</p>
<p>Ainda não terminei de ler o livro, estou curtindo o aprendizado, acho que foi
uma boa escolha de linguagem “extra” pra aprender. Mas como o livro fala sobre
bastante coisa, resolvi escrever alguma coisa logo porque se deixar para
escrever sobre o livro inteiro a tarefa vai ficar grande demais e eu vou fugir
correndo com medo dela.</p>
<p>Então... Erlang!</p>
<p>É uma linguagem divertida. =)</p>
<p>Erlang é uma linguagem funcional com tipagem dinâmica, de propósito geral,
focada em facilitar o desenvolvimento de programas concorrentes e que roda em
uma máquina virtual própria (também chamada
<a href="http://www.erlang-factory.com/upload/presentations/708/HitchhikersTouroftheBEAM.pdf">BEAM</a>).</p>
<p>Mas Erlang é mais do que uma linguagem, podemos dizer que Erlang é todo um
ambiente diferente. A VM de Erlang lembra um sistema operacional em muitas
formas, possuindo seu próprio shell, seu próprio gerenciador de processos, seu
esquema de atualização sem precisar parar nenhum processo e seus <a href="https://pt.wikipedia.org/wiki/Comunica%C3%A7%C3%A3o_entre_processos">mecanismos
disponíveis para comunicação entre
processos</a>.</p>
<p>Um processo Erlang não é nem um processo do sistema operacional nem uma thread:
é um <a href="https://en.wikipedia.org/wiki/Erlang_(programming_language)#Concurrency_and_distribution_orientation">processo
leve</a>,
muito mais leve que threads. A criação de um novo processo é praticamente
gratuita -- pode-se dizer que criar um novo processo em Erlang é tão comum e
tão sossegado quanto instanciar um novo objeto em Java.</p>
<p>Em Erlang, é idiomático encapsular funcionalidade em processos, e é comum um
sistema ter milhares desses processos concorrentes, cada um com sua
responsabilidade. Assim, esses processos encapsulando funcionalidades são
análogos a<a href="https://en.wikipedia.org/wiki/Service_(systems_architecture)">serviços em uma arquitetura orientada a
serviços</a>, só que
em Erlang eles aparecem numa forma bem natural na linguagem e mais integrada ao
ambiente.</p>
<p>Aqui, permita-me apresentar algumas coisinhas da linguagem pra você, bem
rapidão. Para acompanhar, <a href="http://www.erlang.org/download.html">instale Erlang</a>
(no Ubuntu: <code>sudo apt-get install erlang</code>).</p>
<h3>Super-quick-little-taste-of-Erlang</h3>
<p>Veja o seguinte esqueleto de um programa concorrente em Erlang:</p>
<p><a href="https://2.bp.blogspot.com/-HmS5hqh97EA/U0D7Y5iIeII/AAAAAAAAAtk/SVLNHGSIVHk/s1600/erlang-loop-menor.png"><img alt=""Esqueleto de programa Erlang"" src="https://2.bp.blogspot.com/-HmS5hqh97EA/U0D7Y5iIeII/AAAAAAAAAtk/SVLNHGSIVHk/s1600/erlang-loop-menor.png"></a></p>
<p>Note a recursão na função <code>loop</code>: é assim que se faz processos iterativos
(loops) em Erlang, que não tem sintaxe especial para isso. O compilador
implementa a otimização de “<a href="https://pt.wikipedia.org/wiki/Recursividade_(ci%C3%AAncia_da_computa%C3%A7%C3%A3o)#Fun.C3.A7.C3.B5es_recursivas_em_cauda">recursão de
cauda</a>”
(<a href="https://en.wikipedia.org/wiki/Tail_call">tail recursion</a>) para fazer uma
função escrita de maneira recursiva executar de forma iterativa -- isto é, sem
re-chamar a função aumentando a<a href="https://pt.wikipedia.org/wiki/Pilha_de_chamada">pilha de
chamada</a> (<a href="https://en.wikipedia.org/wiki/Call_stack">call
stack</a>). </p>
<p>Você pode testar esse código colocando-o em um arquivo <code>esqueleto.erl</code> e chamá-lo
do shell Erlang, conforme a sessão abaixo:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="err">$</span><span class="w"> </span><span class="n">erl</span>
<span class="w"> </span><span class="n">Erlang</span><span class="w"> </span><span class="n">R16B01</span><span class="w"> </span><span class="p">(</span><span class="n">erts</span><span class="o">-</span><span class="mf">5.10.2</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">source</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">64-bit</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">smp:4:4</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">async-threads:10</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">kernel-poll:false</span><span class="o">]</span>
<span class="w"> </span><span class="n">Eshell</span><span class="w"> </span><span class="n">V5</span><span class="mf">.10.2</span><span class="w"> </span><span class="p">(</span><span class="n">abort</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="o">^</span><span class="n">G</span><span class="p">)</span>
<span class="w"> </span><span class="mi">1</span><span class="o">></span><span class="w"> </span><span class="n">c</span><span class="p">(</span><span class="n">esqueleto</span><span class="p">).</span>
<span class="w"> </span><span class="err">{</span><span class="n">ok</span><span class="p">,</span><span class="n">esqueleto</span><span class="err">}</span>
<span class="w"> </span><span class="mi">2</span><span class="o">></span><span class="w"> </span><span class="n">Pid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nl">esqueleto</span><span class="p">:</span><span class="k">start</span><span class="p">().</span>
<span class="w"> </span><span class="o"><</span><span class="mf">0.41.0</span><span class="o">></span>
<span class="w"> </span><span class="mi">3</span><span class="o">></span><span class="w"> </span><span class="n">Pid</span><span class="w"> </span><span class="err">!</span><span class="w"> </span><span class="ss">"alo!"</span><span class="p">.</span>
<span class="w"> </span><span class="nl">Received</span><span class="p">:</span><span class="w"> </span><span class="ss">"alo!"</span>
<span class="w"> </span><span class="ss">"alo!"</span>
<span class="w"> </span><span class="mi">4</span><span class="o">></span><span class="w"> </span><span class="n">Pid</span><span class="w"> </span><span class="err">!</span><span class="w"> </span><span class="mf">1234.</span>
<span class="w"> </span><span class="nl">Received</span><span class="p">:</span><span class="w"> </span><span class="mi">1234</span>
<span class="w"> </span><span class="mi">1234</span>
<span class="w"> </span><span class="mi">5</span><span class="o">></span><span class="w"> </span><span class="n">Pid</span><span class="w"> </span><span class="err">!</span><span class="w"> </span><span class="err">{</span><span class="n">teste</span><span class="p">,</span><span class="w"> </span><span class="n">com</span><span class="p">,</span><span class="w"> </span><span class="n">uma</span><span class="p">,</span><span class="w"> </span><span class="n">tupla</span><span class="p">,</span><span class="w"> </span><span class="mi">123</span><span class="p">,</span><span class="w"> </span><span class="ss">"ola"</span><span class="err">}</span><span class="p">.</span>
<span class="w"> </span><span class="nl">Received</span><span class="p">:</span><span class="w"> </span><span class="err">{</span><span class="n">teste</span><span class="p">,</span><span class="n">com</span><span class="p">,</span><span class="n">uma</span><span class="p">,</span><span class="n">tupla</span><span class="p">,</span><span class="mi">123</span><span class="p">,</span><span class="ss">"ola"</span><span class="err">}</span>
<span class="w"> </span><span class="err">{</span><span class="n">teste</span><span class="p">,</span><span class="n">com</span><span class="p">,</span><span class="n">uma</span><span class="p">,</span><span class="n">tupla</span><span class="p">,</span><span class="mi">123</span><span class="p">,</span><span class="ss">"ola"</span><span class="err">}</span>
<span class="w"> </span><span class="mi">6</span><span class="o">></span>
</code></pre></div>
<p>Note os pontos finais no fim de cada comando: o comando não roda se você
esquecer deles. Em Erlang, o ponto <code>.</code> separa comandos e declarações, o
ponto-e-vírgula <code>;</code> separacláusulas, e a vírgula <code>,</code> separa expressões.</p>
<p>A primeira linha, <code>c(esqueleto).</code> manda compilar o módulo no arquivo
<code>esqueleto.erl</code>.</p>
<p>Na segunda linha, <code>Pid = esqueleto:start().</code> aciona a função <code>start()</code> do módulo
<code>esqueleto</code>, que vai gerar um novo processo e retornar o identificador do
processo (em inglês, process identifier), que armazenamos na variável <code>Pid</code>. </p>
<p>A seguir, na terceira linha usamos o comando! para envio de mensagens em
Erlang, enviando a mensagem“alo!” para o processo criado na linha anterior,
identificado porPid. O comando <code>receive</code> da função <code>loop()</code> vai receber a
mensagem e executar o código que imprime a mensagem na tela. A mensagem aparece
repetida na tela porque o retorno do comando de envio <code>Pid ! Mensagem</code> é a
mensagem enviada, e o shell sempre imprime o retorno do último comando
executado.</p>
<p>As linhas seguintes apenas repetem o mesmo feito da linha anterior, com outras
mensagens diferentes (um inteiro e uma tupla contendo átomos, inteiros e
strings).</p>
<p>O comando <code>receive</code> tem algumas habilidades especiais: além de bloquear a
execução do código até o processo receber uma mensagem (que também pode ter um
timeout definido), ele pode selecionar o bloco de código a ser executado
dependendo da forma ou conteúdo da mensagem, com o mecanismo chamado de
<a href="https://en.wikipedia.org/wiki/Pattern_matching">pattern matching</a> (ou,
<a href="https://pt.wikipedia.org/wiki/Casamento_de_padr%C3%B5es">casamento de
padrões</a>). </p>
<p>Por exemplo, usando pattern matching, podemos alterar o comando <code>receive</code> da
função <code>loop()</code> para executar um código diferente caso receba a mensagem
<code>"alo!"</code>: </p>
<div class="highlight"><pre><span></span><code><span class="n">loop</span><span class="p">()</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="n">receive</span>
<span class="w"> </span><span class="ss">"alo!"</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nl">io</span><span class="p">:</span><span class="nf">format</span><span class="p">(</span><span class="ss">"Alooooow, galerinha da paaishhh!"</span><span class="p">),</span>
<span class="w"> </span><span class="n">loop</span><span class="p">();</span>
<span class="w"> </span><span class="ow">Any</span><span class="w"> </span><span class="o">-></span>
<span class="w"> </span><span class="nl">io</span><span class="p">:</span><span class="nf">format</span><span class="p">(</span><span class="ss">"Received: ~p~n"</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">Any</span><span class="o">]</span><span class="p">),</span>
<span class="w"> </span><span class="n">loop</span><span class="p">()</span>
<span class="w"> </span><span class="k">end</span><span class="p">.</span>
</code></pre></div>
<p>Se você repetir os passos anteriores com esse novo código, receberá uma
resposta mais animada quando enviar a mensagem <code>"alo!"</code>. =)</p>
<p>Nesse exemplo, o padrão casado foi o conteúdo da mensagem, isto é, a string
<code>"alo!"</code>. Mas o mecanismo permite fazer vários tipos de verificações: você
pode, por exemplo, verificar se a mensagem é um número ou uma tupla, se é uma
tupla contendo um determinado elemento, se é uma lista com tantos elementos,
etc.</p>
<p>Quando alguém mais acostumado ao paradigma imperativo se depara com a ideia de
pattern matching (que existe em outras linguagens além de Erlang), usualmente
acha útil <a href="http://stackoverflow.com/questions/2502354/what-is-pattern-matching-in-functional-languages">pensar nele como um "switch-case em
esteróides"</a>,
uma espécie de Super Estrutura Condicional.</p>
<p>Em Erlang, todavia,pattern matching (ou casamento de padrões) aparece em mais
do que estruturas condicionais.</p>
<p>De fato, na expressão:</p>
<div class="highlight"><pre><span></span><code>X = 1.
</code></pre></div>
<p>o <code>=</code> (igual) é um acionamento do operador depattern matching de Erlang --
diferente de outras linguagens em que o igual é um operador de
<a href="https://pt.wikipedia.org/wiki/Atribui%C3%A7%C3%A3o_(computa%C3%A7%C3%A3o)">atribuição</a>.
Erlang não tem operador atribuição, que usualmente permite definir e redefinir
o conteúdo de variáveis.</p>
<p>O que acontece aqui é que o <a href="http://www.erlang.org/doc/reference_manual/patterns.html">operador de pattern
matching</a> liga um
valor a uma variável quando esta ainda não tem nenhum valor associado (isto é,
quando se trata de uma <a href="https://pt.wikipedia.org/wiki/Vari%C3%A1veis_livres_e_ligadas">variável
livre</a>, ou
<em>unbound variable</em>).</p>
<p>Na próxima vez que a variável for referenciada, ela terá o valor "casado"
(matched) anteriormente, veja:</p>
<div class="highlight"><pre><span></span><code><span class="mf">1</span><span class="o">></span><span class="w"> </span><span class="n">A</span><span class="mf">.</span>
<span class="o">*</span><span class="w"> </span><span class="mf">1</span><span class="p">:</span><span class="w"> </span><span class="n">variable</span><span class="w"> </span><span class="err">'</span><span class="n">A</span><span class="err">'</span><span class="w"> </span><span class="n">is</span><span class="w"> </span><span class="n">unbound</span>
<span class="mf">2</span><span class="o">></span><span class="w"> </span><span class="n">A</span><span class="o">=</span><span class="s">"oi"</span><span class="mf">.</span>
<span class="s">"oi"</span>
<span class="mf">3</span><span class="o">></span><span class="w"> </span><span class="n">A</span><span class="mf">.</span>
<span class="s">"oi"</span>
<span class="mf">4</span><span class="o">></span>
</code></pre></div>
<p>Uma vez ligada, a variável só casará com o valor original, e nunca mais com
outro. Caso tente casar a variável com outro valor (pensando que funcionaria
como atribuição), você obterá um erro avisando que falhou o casamento do
padrão:</p>
<div class="highlight"><pre><span></span><code><span class="mf">4</span><span class="o">></span><span class="w"> </span><span class="n">A</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"alô"</span><span class="mf">.</span><span class="w"> </span>
<span class="o">**</span><span class="w"> </span><span class="n">exception</span><span class="w"> </span><span class="n">error</span><span class="p">:</span><span class="w"> </span><span class="n">no</span><span class="w"> </span><span class="n">match</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">right</span><span class="w"> </span><span class="n">hand</span><span class="w"> </span><span class="n">side</span><span class="w"> </span><span class="nb">val</span><span class="n">ue</span><span class="w"> </span><span class="s">"alô"</span>
</code></pre></div>
<p>Isto porque em Erlang, as variáveis são imutáveis para o contexto local. Outra
forma de dizer é: em Erlang, as variáveis são de atribuição única (single
assignment variables). Uma vez atribuído um valor a uma variável, você não
pode alterá-lo -- como demonstrei acima.</p>
<p>Isto parece estranho no começo, para quem está acostumado com o paradigma
imperativo. Pensando bem, é a mesma estranheza que a gente sente quando aprende
a programar e é exposto a variáveis e atribuição pela primeira vez (“como
assim, x = x + 1?). Faz mais sentido pensar nas variáveis de Erlang como as
variáveis da Matemática, em que o valor de um nome é sempre o mesmo.”</p>
<p>A imutabilidade de variáveis tem como consequência algumas coisas
interessantes:</p>
<ul>
<li>
<p>força você a criar novas variáveis em algumas situações, mesmo que esteja com
pouca criatividade para dar um nome decente (no livro mesmo tem alguns
exemplos com <code>Word1</code>, <code>Word2</code> -- o que é meio feio)</p>
</li>
<li>
<p>evita alguns tipos debugs e simplifica a depuração, pois aumenta a
previsibilidade da execução do código (isto é, você pode confiar que o valor
de uma variável não vai mudar)</p>
</li>
<li>
<p>facilita a escrita de programas concorrentes e permite que sejam rodados em
paralelo, pois evita uma cacetada de problemas de memória compartilhada</p>
</li>
</ul>
<p>E esta última consequência compensa as dificuldades de dar nomes às variáveis.
Porque escrever programas multi-thread é difícil de fazer direito (você precisa
se preocupar com
<a href="https://en.wikipedia.org/wiki/Synchronization_(computer_science)">sincronização</a>
de processos e de memória), e o jeito Erlang de escrever programas concorrentes
que se comunicam via envio de mensagens (o <a href="http://c2.com/cgi/wiki?ActorsModel">modelo de
atores</a>) simplifica as coisas, de forma que
os programas são sempre paralelizáveis.</p>
<p>Isso faz com que aplicações escritas em Erlang escalem mais fácil do que
aplicações escritas em outras linguagens. Claro que vários problemas de
escalabilidade se manterão, principalmente os relacionados a hardware e
infraestrutura, mas problemas de software tendem a ser resolvidos mais fácil
com Erlang.</p>
<p>De fato, Erlang vem de fábrica com mecanismos de clusterização, e você pode
facilmente iniciar nós de um cluster em algumas máquinas e disparar chamadas
remotas de um nó para outro.</p>
<p>Para um exemplo rápido, inicie um nó do cluster em um terminal, dando um nome:</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">erl</span><span class="w"> </span><span class="o">-</span><span class="n">sname</span><span class="w"> </span><span class="n">lennon</span><span class="nv">@localhost</span>
<span class="n">Erlang</span><span class="w"> </span><span class="n">R16B01</span><span class="w"> </span><span class="p">(</span><span class="n">erts</span><span class="o">-</span><span class="mf">5.10.2</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">source</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">64-bit</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">smp:4:4</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">async-threads:10</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">kernel-poll:false</span><span class="o">]</span>
<span class="n">Eshell</span><span class="w"> </span><span class="n">V5</span><span class="mf">.10.2</span><span class="w"> </span><span class="p">(</span><span class="n">abort</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="o">^</span><span class="n">G</span><span class="p">)</span>
<span class="p">(</span><span class="n">lennon</span><span class="nv">@localhost</span><span class="p">)</span><span class="mi">1</span><span class="o">></span>
</code></pre></div>
<p>Em outro terminal, inicie outro nó e faça uma chamada remota ao nó anterior:</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="w"> </span><span class="n">erl</span><span class="w"> </span><span class="o">-</span><span class="n">sname</span><span class="w"> </span><span class="n">mccartney</span><span class="nv">@localhost</span>
<span class="n">Erlang</span><span class="w"> </span><span class="n">R16B01</span><span class="w"> </span><span class="p">(</span><span class="n">erts</span><span class="o">-</span><span class="mf">5.10.2</span><span class="p">)</span><span class="w"> </span><span class="o">[</span><span class="n">source</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">64-bit</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">smp:4:4</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">async-threads:10</span><span class="o">]</span><span class="w"> </span><span class="o">[</span><span class="n">kernel-poll:false</span><span class="o">]</span>
<span class="n">Eshell</span><span class="w"> </span><span class="n">V5</span><span class="mf">.10.2</span><span class="w"> </span><span class="p">(</span><span class="n">abort</span><span class="w"> </span><span class="k">with</span><span class="w"> </span><span class="o">^</span><span class="n">G</span><span class="p">)</span>
<span class="p">(</span><span class="n">mccartney</span><span class="nv">@localhost</span><span class="p">)</span><span class="mi">1</span><span class="o">></span><span class="w"> </span><span class="nl">rpc</span><span class="p">:</span><span class="k">call</span><span class="p">(</span><span class="n">lennon</span><span class="nv">@localhost</span><span class="p">,</span><span class="w"> </span><span class="k">file</span><span class="p">,</span><span class="w"> </span><span class="n">list_dir</span><span class="p">,</span><span class="w"> </span><span class="o">[</span><span class="n">"/"</span><span class="o">]</span><span class="p">).</span>
<span class="err">{</span><span class="n">ok</span><span class="p">,</span><span class="o">[</span><span class="n">"var","tmp","mnt","lib","boot","lib32","vmlinuz",</span>
<span class="n"> "proc","media","bin","lib64","sys","opt","sbin","srv",</span>
<span class="n"> "root","dev","usr","initrd.img","lost+found","cdrom","home",</span>
<span class="n"> "vmlinuz.old","run","etc","initrd.img.old"</span><span class="o">]</span><span class="err">}</span>
<span class="p">(</span><span class="n">mccartney</span><span class="nv">@localhost</span><span class="p">)</span><span class="mi">2</span><span class="o">></span>
</code></pre></div>
<p>O argumento <code>-sname</code> faz com que Erlang inicie um nó com o nome passado (note
como o nome do nó é mostrado no prompt). No comando que executamos no segundo
nó (<code>mccartney@localhost</code>) usamos a função <a href="http://erlang.org/doc/man/rpc.html">call do módulo
<code>rpc</code></a> para acionar uma função remotamente
em outro nó e obter o resultado -- neste caso, a função <code>os:listdir("/")</code> para
retornar a lista de arquivos do diretório raiz.</p>
<p>E tudo com código da distribuição padrão. (Try that in Java, biátch!)</p>
<p>Bom, tentei mostrar algumas coisas interessantes da linguagem aqui, mas Erlang
tem muito a oferecer ainda. Ela tem outros <a href="http://www.erlang.org/doc/reference_manual/data_types.html">tipos de dados
interessantes</a>
(átomos,
<a href="http://www.erlang.org/doc/efficiency_guide/binaryhandling.html">binaries</a>,
tuplas, <a href="http://www.erlang.org/doc/reference_manual/records.html">records</a>, e
na <a href="http://www.erlang.org/news/67">versão R17</a> terá
<a href="http://www.erlang.org/eeps/eep-0043.html">maps</a>), um <a href="http://www.erlang.org/doc/reference_manual/ports.html">mecanismo próprio de
comunicação com outros processos do sistema
operacional</a>, permite a
<a href="http://www.erlang.org/doc/reference_manual/typespec.html">especificação opcional de tipos para
funções</a>, um <a href="http://www.erlang.org/doc/man/mnesia.html">banco
de dados para aplicações
distribuídas</a>, vem com ferramentas
de fábrica para análise estática de código, depuração e profiling e com um
<a href="http://learnyousomeerlang.com/what-is-otp">conjunto de bibliotecas e funções para aplicações tolerante a falhas e
distribuídas</a>.</p>
<p>Só tem dois problemas de usabilidade que me incomodam um pouco:</p>
<ul>
<li>
<p>Nem todos os comandos ou exemplos de código funcionam no shell. Algumas
funcionalidades só estão disponíveis no shell, e outras apenas em módulos
compilados (<a href="http://stackoverflow.com/questions/2065990/defining-erlang-functions-in-the-shell">criar funções no
shell</a>,
por exemplo). Isso é uma espécie de “bug conhecido”: <a href="http://joearms.github.io/2013/05/31/a-week-with-elixir.html">Joe Armstrong, o criador
da linguagem, conta que seus cabelos embranqueceram de tanto explicar por que
a implementação ficou desse
jeito</a>.</p>
</li>
<li>
<p>O shell não tem histórico persistente, e não suporta atalhos comuns em
aplicações da linha de comando que usam a <a href="https://en.wikipedia.org/wiki/GNU_Readline">GNU
Readline</a>. Parece que o esquema
de IO do shell Erlang é meio complicado de manter -- no GitHub tem <a href="https://github.com/ferd/erlang-history">um
projeto que adiciona um histórico persistente
básico</a>, mas o FAQ não é muito
encorajador.</p>
</li>
</ul>
<p>O resto é fantástico. =)</p>
<p>Caso você tenha ficado curioso, pode querer conferir o livro <a href="http://learnyousomeerlang.com/">Learn You Some
Erlang</a> -- não li, mas já tirei algumas dúvidas
nele caindo de buscas do Google e pareceu muito bom. Have a nice journey! :)</p>
<p>Valeu pela revisão, Fredi e Denise.</p>Trabalho Eficaz com Código Legado2014-01-26T17:58:00+01:002014-01-26T17:58:00+01:00Elias Dornelestag:eliasdorneles.com,2014-01-26:/2014/01/26/trabalho-eficaz-com-codigo-legado.html<p><a href="http://www.grupoa.com.br/livros/engenharia-de-software-e-metodos-ageis/trabalho-eficaz-com-codigo-legado/9788582600320" title="Página do livro na editora brasileira">Trabalho Eficaz com Código
Legado</a> é o título em português do famoso
livro sobre código legado (título original: <em><a href="https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052">Working Effectively with Legacy
Code</a></em>)
escrito por <a href="https://twitter.com/mfeathers">Michael Feathers</a>, um <a href="http://www.objectmentor.com/omTeam/feathers_m.html">consultor
muito experiente e reconhecido na comunidade
Agile/XP</a>. Acabei de ler a
versão traduzida que um amigo emprestou, e a tradução …</p><p><a href="http://www.grupoa.com.br/livros/engenharia-de-software-e-metodos-ageis/trabalho-eficaz-com-codigo-legado/9788582600320" title="Página do livro na editora brasileira">Trabalho Eficaz com Código
Legado</a> é o título em português do famoso
livro sobre código legado (título original: <em><a href="https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052">Working Effectively with Legacy
Code</a></em>)
escrito por <a href="https://twitter.com/mfeathers">Michael Feathers</a>, um <a href="http://www.objectmentor.com/omTeam/feathers_m.html">consultor
muito experiente e reconhecido na comunidade
Agile/XP</a>. Acabei de ler a
versão traduzida que um amigo emprestou, e a tradução está bem decente -- bem
diferente da <a href="https://eljunior.wordpress.com/2013/01/15/aventuras-com-java-ee/" title="Aventuras apresentando Java EE a mim mesmo">última vez que li um livro técnico em
português</a>.</p>
<p><a href="http://www.grupoa.com.br/livros/engenharia-de-software-e-metodos-ageis/trabalho-eficaz-com-codigo-legado/9788582600320"><img alt="Capa do
livro" src="https://eljunior.files.wordpress.com/2014/01/trabalho_eficaz_codigo_legado.jpg?w=210"></a></p>
<p>Veja alguns links sobre o livro, e meu resumo/resenha a seguir:</p>
<ul>
<li><a href="http://c2.com/cgi/wiki?WorkingEffectivelyWithLegacyCode">Página sobre o livro na
WikiWikiWeb</a></li>
<li><a href="https://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052">Working Effectively with Legacy Code na
Amazon</a></li>
<li><a href="http://www.grupoa.com.br/livros/engenharia-de-software-e-metodos-ageis/trabalho-eficaz-com-codigo-legado/9788582600320">Página da versão traduzida no grupo de editoras Grupo
A</a></li>
<li><a href="http://programmers.stackexchange.com/questions/122014/what-are-the-key-points-of-working-effectively-with-legacy-code">Tópico no programmers.SE com resumo dos pontos chave do
livro</a></li>
<li><a href="http://www.objectmentor.com/resources/articles/WorkingEffectivelyWithLegacyCode.pdf">Paper do Michael Feathers que originou o
livro</a></li>
</ul>
<p>A definição do livro para código legado é basicamente, código sem
testes. Eis a resposta do livro à pergunta: “o que os testes têm a ver
com o código ser ruim?”:</p>
<blockquote>
<p>Código sem testes é código ruim. Não importa o quão bem escrito, nem
se ele é bonito, orientado a objetos ou se foi bem encapsulado. Com
testes, podemos alterar o comportamento de nosso código de maneira
rápida e verificável. Sem eles, não temos como saber se nosso código
está melhorando ou piorando.</p>
</blockquote>
<p>Quando você precisa alterar código que você mesmo fez, é um pouco mais
difícil de fazer isso de forma segura se o código não tem uma suíte de
testes (especialmente se faz mais de meses que você mexeu nele pela
última vez). Agora, se o código que você precisa alterar foi escrito por
outra pessoa, é um pouco mais difícil de alterar com segurança se ele
não tiver testes. Se esse código que você precisa alterar foi feito por
uma equipe de pessoas diferentes, misturando estilos diferentes, e não
tem uma suíte de testes, sua tarefa é um bom bocado mais difícil. E se
foi escrito por várias pessoas diferentes, em períodos de tempo
diferentes, passando por uma série de restrições de prazos e falhas de
comunicação: com testes já seria complicado, sem testes automatizados
certamente será uma tarefa muito lenta, laboriosa e propensa a erros.</p>
<p>Por isso, essa definição para código legado faz bastante sentido. Se
você está escrevendo código sem testes, você está escrevendo código
legado. Daí a importância desse livro: código legado não é apenas código
daquele projeto que você cai de pára-quedas e tem que tentar entender o
que os programadores que trabalharam nele fizeram. O seu próprio código
vira código legado em questão de minutos, caso você não esteja
escrevendo uma suíte de testes para ele.</p>
<p>Quando você tenta submeter a testes esse tipo de código que não foi
escrito para ser testável, você frequentemente descobre que não consegue
testá-lo sem refatorar algumas partes. Mas pra fazer refatorações com
segurança, você quer ter testes que verifiquem se as refatorações não
estão quebrando nada. E aí você fica sem nenhuma escolha boa:</p>
<p>1) ou você arrisca refatorar um pouco para adicionar testes depois e então
alterar com mais segurança</p>
<p>2) ou arrisca tudo de vez e sai alterando sem testes mesmo</p>
<p>Acho que todos nós fazemos isso de vez em quando -- pelo menos, eu sei
que sou culpado de escrever muito código legado. Manter uma cobertura de
testes alta é difícil quando você não tem treino ou confiança nesse
método de trabalhar. Além disso, infelizmente é muito fácil racionalizar
que você está melhor do que a maioria, porque tem <em>“muito código pior em
produção por aí”</em> -- o que não é uma atitude muito saudável.</p>
<p>Enfim, a utilidade dos testes de unidade é o tipo de coisa que talvez
você tenha que verificar por si próprio. Mas o livro do Michael Feathers
não é sobre testes. O propósito do livro é ensinar passo-a-passo a fazer
as pequenas cirurgias-refatorações necessárias para transformar um
trecho de código em algo testável, para a seguir você conseguir
submetê-lo a testes e fazer as alterações necessárias com mais
segurança.</p>
<p>Muitas vezes essas pequenas cirurgias elaboradas para serem minimamente
invasivas podem deixar o código um tanto feio, com uma estrutura
estranha. Mas não faz mal. A ideia nesse momento é deixá-lo testável,
permitindo-lhe alterá-lo com segurança. Depois de fazer as alterações
necessárias guiadas por testes, você poderá refatorar para uma estrutura
mais adequada, desta vez com a ajuda dos testes que você escreveu.</p>
<p>Para isso, o autor explica quais são as coisas necessárias para deixar
um código testável, e passa vários truques para transformar código
<em>spaghetti</em> em código testável, um degrau de cada vez. Alguns truques de
quebra de dependências você provavelmente já usou de uma forma ou outra,
embora talvez não com foco em melhorar a testabilidade. Muitos deles são
simples, mas nunca teriam me ocorrido antes do livro.</p>
<p>Um conceito central do livro é o modelo de <strong>pontos de extensão</strong>
(tradução de <em><a href="http://c2.com/cgi/wiki?SoftwareSeam">Software Seam</a></em> --
literalmente, <em>costura de software</em>). Pontos de extensão são os locais
do código que permitem embutir um comportamento diferente sem ser
necessário editar o código diretamente no local. Pontos de extensão
colocados nos lugares apropriados permitem que você <strong>isole</strong> o código
sendo testado do restante e também <strong>detecte</strong> as diferenças no
comportamento do código sendo exercitado pelos testes -- duas ideias
importantes para testabilidade que o livro também explica em mais
detalhes.</p>
<p>Um exemplo de ponto de extensão é a chamada de um <a href="https://pt.wikipedia.org/wiki/M%C3%A9todo_virtual">método
virtual</a> (isto é, um
método que pode ser sobrescrito) em uma linguagem orientada a objetos.
Se você tem um método <em>updateDb()</em> chamando um método virtual
<em>getConnection()</em> na mesma classe, você poderá criar uma nova classe que
estenda a anterior sobrescrevendo o método <em>getConnection()</em> para
retornar um objeto de conexão diferente. Nesse caso, a chamada ao método
virtual <em>getConnection()</em> corresponde ao que Feathers chama de um <em>ponto
de extensão de objeto</em>, por ser característico das linguagens orientadas
a objetos.</p>
<p>O livro é muito bem escrito, mas talvez lê-lo do começo ao fim como fiz
pode não ser o método mais eficiente de aproveitá-lo. Boa parte do livro
(a parte 2 das 3 que compõem o livro) foi escrita num formato de <em>FAQ -
Perguntas Frequentes</em>, cujos capítulos podem ser lidos mais ou menos em
qualquer ordem, são cheios de referências cruzadas e tornam o livro
perfeito para manter ao alcance e usar como referência na hora de
resolver um problema. A terceira parte do livro é um catálogo das
refatorações que foram referenciadas nos capítulos da parte 2, contendo
uma descrição e os passos para aplicar cada refatoração. Isso deixa o
conteúdo um pouco repetitivo se você lê todos os capítulos em sequência,
como eu fiz.</p>
<p>Mas a primeira parte, que tem um material mais introdutório, disseca a
mecânica de fazer alterações e consegue efetivamente vender a ideia da
importância de testes de unidade na manutenção de software. Além de
apresentar a motivação, Michael Feathers explica também as
características encontradas em bons testes de unidade:</p>
<ol>
<li>São executados rapidamente</li>
<li>Ajudam a localizar problemas de imediato</li>
</ol>
<p>Ele é incisivo: <strong>um teste de unidade que leve 1/10 de segundo para ser
executado é um teste lento</strong>.</p>
<p>Você quer rodar milhares desses testes ao mesmo tempo, por isso é desejável que
sua execução não seja lenta. Se você tem 3 mil classes com 10 testes de unidade
cada um levando 1/10 de segundo, levará cerca de 1 hora para rodar todos os
testes -- isso é muito tempo para ter feedback sobre uma alteração. Mesmo que
você não tenha 3 mil classes, os números não melhoram muito. Dez minutos é
tempo demais para esperar por feedback. Quando os testes estão demorando 10
minutos para executar, vale a pena rodar apenas um subconjunto deles quando
fazendo alterações; e rodar a suíte inteira talvez em intervalos de horas ou
antes de fazer <em>commit</em> no sistema de controle de versão. Mas é bom se esforçar
para obter uma suíte de testes que executem rapidamente.</p>
<p>Alguns testes se parecem com testes de unidade. Testes que acessam o
banco de dados, que usam a rede, que usam o sistema de arquivos, podem
se parecer com testes de unidade, mas não o são. Não quer dizer que não
são úteis: certamente são úteis! Mas é interessante separá-los dos
verdadeiros testes de unidade, que focam em um trecho específico do seu
código de produção e que você pode executar rapidamente quando estiver
fazendo alterações.</p>
<p>Bem, o livro é altamente recomendado, e não só por mim. Está destinado a
ser um clássico na biblioteca dos programadores profissionais por muito
tempo, sem dúvida. Leia o livro e mergulhe de cabeça.</p>Você devia aprender shell-script2014-01-11T16:34:00+01:002014-01-11T16:34:00+01:00Elias Dornelestag:eliasdorneles.com,2014-01-11:/2014/01/11/voce-devia-aprender-shell-script.html<p>Se você é programador, você devia aprender
<a href="https://pt.wikipedia.org/wiki/Shell_script">shell-script</a>. Ou pelo
menos, algo parecido.</p>
<p>Nem que seja apenas o básico para se virar: criar o arquivo e deixar
executável, ler e escrever variáveis, redirecionar entrada e saída,
encadear comandos, <a href="https://en.wikipedia.org/wiki/Grep">grep</a> e
<a href="https://en.wikipedia.org/wiki/Cut_(Unix)">cut</a> basicão.</p>
<p>Você pode ainda não saber que precisa da …</p><p>Se você é programador, você devia aprender
<a href="https://pt.wikipedia.org/wiki/Shell_script">shell-script</a>. Ou pelo
menos, algo parecido.</p>
<p>Nem que seja apenas o básico para se virar: criar o arquivo e deixar
executável, ler e escrever variáveis, redirecionar entrada e saída,
encadear comandos, <a href="https://en.wikipedia.org/wiki/Grep">grep</a> e
<a href="https://en.wikipedia.org/wiki/Cut_(Unix)">cut</a> basicão.</p>
<p>Você pode ainda não saber que precisa da habilidade de fazer
shell-scripts, e isso é um problema. Tem sido difícil para mim comunicar
a outros programadores que conheço como a vida deles seria mais fácil se
aprendessem um mínimo de shell-script. (Enquanto isso, meu irmão
sargento do Exército, que nem é programador profissional, usa o shell
regularmente para resolver pepinos impossíveis no trabalho dele. That's
a win!)</p>
<p>Os motivos que as pessoas dão para deixar de aprender shell-script são
mais ou menos os mesmos: “não tenho tempo, tem outras coisas me ocupando
no momento”, “isso não é da linha de comando? ninguém mais usa a linha
de comando, os anos 80 já se foram há muito tempo” e “por que você se
importa que eu aprenda essa linguagem velha e tosca?”.</p>
<p>Estou aqui para dizer que nenhum desses motivos é válido, vamos
destrinchá-los um por um.</p>
<p><strong>Motivo 1: não tenho tempo, tem outras coisas me ocupando no momento</strong></p>
<p>É claro que você não tem tempo e está ocupado, você ainda não sabe
shell-script! Se soubesse, teria resolvido uma penca de problemas antes
do tempo e estaria navegando no reddit. :D</p>
<p>Brincadeiras à parte: você acha o tempo pra estudar. Invista um pouco de
tempo agora, pra colher depois. Colhe em tempo e tranquilidade -- o que
antes você fazia manualmente, você agora só checa o resultado.</p>
<p><strong>Motivo 2: linha de comando é coisa do passado</strong></p>
<p>Bééééé, not really! Interfaces de linha de comando continuam a todo o
vapor. Mesmo os cool kids brincando com as <a href="http://nodejs.org/">últimas encarnações de
Javascript</a> não param de criar
<a href="https://npmjs.org/">uma</a> <a href="http://bower.io/">porção</a>
<a href="http://gruntjs.com/">de</a> <a href="http://yeoman.io/">ferramentas</a> para a linha
de comando, uma mais interessante que a outra.</p>
<p>A verdade é que as interfaces de linha de comando, apesar de não serem
muito intuitivas para um usuário leigo, são muito boas para nós,
programadores. Ou para qualquer pessoa que queira poder resolver os
próprios problemas computacionais sem depender de alguém haver
encontrado o mesmo problema antes e ser generoso a ponto de resolvê-lo e
compartilhar a solução.</p>
<p>É verdade também que a sintaxe pouco familiar de shell-script pode
assustar um pouco quem está começando. Mas a questão é que a vida fica
muito mais fácil depois que você destrincha o básico.</p>
<p>Experimente um pouco. Quem sabe, capaz de você acabar se divertindo
nessa brincadeira!</p>
<p><strong>Motivo 3: por que você se importa que eu aprenda essa velharia?</strong></p>
<p>Hã, esse não é bem um motivo, mas é uma reação esperada. E a resposta é:
porque eu só tenho a ganhar.</p>
<p>Veja só, se você aprender shell-script e
conseguir otimizar sua vida um pouquinho, vai sobrar tempo pra você
aprender ainda mais um pouquinho de shell-script e otimizar ainda mais e
assim por diante, então a tendência é o mundo melhorar, ha-ha!</p>
<p>Piadinhas à parte, a verdade é que aos poucos você vai começar a
perceber que pode resolver um monte de problemas que antes você nem se
dava conta que existiam. Problemas que, apesar de você não vê-los,
estavam lá atrasando sua vida, atrapalhando seu desempenho, deixando
você numa espécie de indefesa aprendida.</p>
<p><em>Shell-script</em> é uma ferramenta semelhante ao seu editor de textos ou
IDE, no sentido que vai acompanhar você pelo resto da vida. Por isso
vale a pena aprender, pois você terá retorno continuamente. E você
estará sempre descobrindo coisas novas e o domínio do shell vai
continuar consistentemente lhe recompensando, à medida que você vai
aprendendo outras coisas.</p>
<p>Essa é a beleza de shell-scripting, a de permitir você combinar várias
coisas, mesmo algumas que não tenham sido feitas para serem combinadas.
É a beleza da <a href="https://pt.wikipedia.org/wiki/Filosofia_Unix">filosofia
Unix</a>. <em>Thanks, <a href="https://pt.wikipedia.org/wiki/Douglas_McIlroy">Mr.
McIlroy</a>, we’ve seen the
light now</em>.</p>
<p>Um dos melhores investimentos do meu tempo na época que estava na faculdade foi
ler boa parte do <a href="http://www.tldp.org/LDP/abs/html/">Advanced Bash Scripting
Guide</a>, quando um dos rapazes do laboratório
imprimiu uma cópia em folha dupla e letra miúda pra ficar fácil de carregar. É
meio comprido, mas é uma excelente fonte para aprender: é recheada de exemplos,
ensina boas práticas e tem várias notas sobre portabilidade.</p>
<p>Mas se você não curte ler em inglês, não desanime. Pode <a href="http://aurelio.net/shell/">começar com a
página do Aurélio</a>, que é como comecei
também, no fim das contas. <a href="http://www.shellscript.com.br">Leia o livro
dele</a>.</p>
<p>Fuja das desculpas, e comece logo. O retorno é garantido.</p>Problemas da Filosofia2013-11-20T08:16:00+01:002013-11-20T08:16:00+01:00Elias Dornelestag:eliasdorneles.com,2013-11-20:/2013/11/20/problemas-da-filosofia.html<p>Um amigo indicou-me a leitura de <a href="https://en.wikipedia.org/wiki/The_Problems_of_Philosophy">The Problems of
Philosophy</a>
(<em>Os Problemas da Filosofia</em>), uma introdução a Filosofia escrita por
<a href="https://en.wikipedia.org/wiki/Bertrand_Russell">Bertrand Russell</a>,
filósofo e historiador britânico. O livro é excelente, esclareceu várias
dúvidas minhas e me fez pensar melhor sobre muitas coisas.</p>
<p>O texto original está <a href="http://www.gutenberg.org/ebooks/5827">disponível no Projeto
Gutenberg …</a></p><p>Um amigo indicou-me a leitura de <a href="https://en.wikipedia.org/wiki/The_Problems_of_Philosophy">The Problems of
Philosophy</a>
(<em>Os Problemas da Filosofia</em>), uma introdução a Filosofia escrita por
<a href="https://en.wikipedia.org/wiki/Bertrand_Russell">Bertrand Russell</a>,
filósofo e historiador britânico. O livro é excelente, esclareceu várias
dúvidas minhas e me fez pensar melhor sobre muitas coisas.</p>
<p>O texto original está <a href="http://www.gutenberg.org/ebooks/5827">disponível no Projeto
Gutenberg</a>, e existem também
<a href="http://criticanarede.com/problemasdafilosofia.html">algumas</a>
<a href="http://www.cfh.ufsc.br/~conte/russell.html">traduções</a> online.</p>
<p>Ele começa fazendo a pergunta: <em>“Existe algum conhecimento no mundo que
é tão certeiro que nenhum homem razoável poderia duvidar?”</em> Partindo
daí, ele segue mostrando por que responder essa pergunta é difícil,
apontando as hipóteses que comumente assumimos como verdadeiras e quais
motivos podemos ter para acreditar nelas ou não.</p>
<p>Demorei um pouco pra aceitar que o motivo porque acreditamos que o sol
vai nascer amanhã é, basicamente, porque ele já nasceu muitas vezes
antes! <em>I mean... dude, the shit is probabilistic!</em> Aparentemente, isso
é um choque pra quase todo mundo, então não estou sozinho.</p>
<p>É fascinante a quantidade de coisas que assumimos -- algumas com mais
motivos e outras com menos -- e o livro faz um bom trabalho de esmiuçar
várias dessas coisas. Ele é relativamente curto, mas é denso para
noviços como eu, então é meio difícil tentar resumir aqui o que se pode
tirar dele.</p>
<p>Mas tendo lido esse livro, me sinto mais seguro sobre algumas coisas em
que acredito e também mais capaz de analisar os motivos que tenho para
avaliar novas informações. Quando alguém vier com historinhas tipo <em>“não
existe verdade absoluta, só existem percepções”</em> com o intuito de me
confundir sobre os fatos -- como já me aconteceu antes -- estarei melhor
preparado para lidar com isso.</p>
<p>Entendo agora que não existe uma “verdade absoluta” sobre todos os
assuntos, que possa ser conhecida a uma mente, mas sei que existem
algumas verdades universais que podemos aplicar para raciocinar com
fatos, probabilidades e com hipóteses, conforme os motivos (ou falta de
motivos) que temos para acreditar nelas.</p>
<p>Quem tem curiosidade sobre como as coisas funcionam, como conhecimento
funciona, recomendo a leitura deste livro; vale a pena. Embora outra
introdução a Filosofia provavelmente sirva também.</p>
<p><em>Valeu, Flávio, pela recomendação do livro. =)</em></p>VI Melhorado2013-09-26T16:49:00+02:002013-09-26T16:49:00+02:00Elias Dornelestag:eliasdorneles.com,2013-09-26:/2013/09/26/vi-melhorado.html<p><a href="http://pragprog.com/book/dnvim/practical-vim">Practical Vim</a> é um livro sobre
o <a href="http://www.vim.org/">Vim</a> -- o editor de textos xodó dos programadores.
Muito bem escrito, recheado de exemplos e referências, kudos para o <a href="http://drewneil.com/">Drew
Neil</a>, autor dessa belezinha. Drew também faz vídeos
sobre o Vim, disponíveis gratuitamente em
<a href="http://vimcasts.org/">http://vimcasts.org</a>.</p>
<p><a href="http://pragprog.com/book/dnvim/practical-vim"><img alt="Edit Text at the Speed of
Thought" src="https://eljunior.files.wordpress.com/2013/09/dnvim.jpg?w=250" title="Practical Vim"></a></p>
<p>Se você ainda não conhece o …</p><p><a href="http://pragprog.com/book/dnvim/practical-vim">Practical Vim</a> é um livro sobre
o <a href="http://www.vim.org/">Vim</a> -- o editor de textos xodó dos programadores.
Muito bem escrito, recheado de exemplos e referências, kudos para o <a href="http://drewneil.com/">Drew
Neil</a>, autor dessa belezinha. Drew também faz vídeos
sobre o Vim, disponíveis gratuitamente em
<a href="http://vimcasts.org/">http://vimcasts.org</a>.</p>
<p><a href="http://pragprog.com/book/dnvim/practical-vim"><img alt="Edit Text at the Speed of
Thought" src="https://eljunior.files.wordpress.com/2013/09/dnvim.jpg?w=250" title="Practical Vim"></a></p>
<p>Se você ainda não conhece o Vim, talvez esse livro não seja um começo
adequado. É bom ter pelo menos seguido o
<a href="http://linuxcommand.org/man_pages/vimtutor1.html">vimtutor</a>. Se você
usa Vim há um bom tempo e está sentindo que não usa todo o potencial da
ferramenta, este livro pode ser o que você precisa.</p>
<p>O livro foi escrito num formato de dicas, demonstrando problemas e
soluções, começando com as mais simples e avançando para outras mais
refinadas, com referências cruzadas entre elas. Isso torna possível você
lê-lo aos poucos, não necessariamente em ordem, portanto fica uma
leitura leve -- como se fosse uma centena de blog posts. Mas eu li na
ordem mesmo assim. :P</p>
<p>Como o livro é extremamente prático e recheado de exemplos, e também como <a href="https://eljunior.wordpress.com/2013/04/07/coisas-sobre-o-vim-que-gostaria-de-ter-sabido-antes/">já
falei algumas coisas a respeito aqui
antes</a>,
vou só falar os destaques que pessoalmente me foram legais.</p>
<p>Um dos pontos centrais do livro é que para usar bem os recursos Vim,
devemos aprender os mecanismos de repetição que ele oferece. Repetir o
último comando, a última mudança no texto, a última macro, a última
busca -- essas funcionalidades ajudam bastante no trabalho de edição,
que é repetitivo por natureza, portanto vale a pena aprender bem como
elas funcionam.</p>
<p>Aprendi a lidar com registradores (<em>registers</em>) no Vim, finalmente! Muitas
vezes antes já senti falta e acabei fazendo a tarefa manualmente ou recorrendo
a uma ou outra mutreta... Você <a href="http://usevim.com/2012/04/13/registers/">pode aprender facilmente sobre os registers do
Vim em um tutorial online</a>, mas o
livro ensina com exemplos práticos, dando a motivação certa pra você aprender
cada comando. Eu já havia lido várias vezes sobre os <em>registers</em> online, mas só
depois de ler os pulos do gato no livro que estou me sentindo confortável para
usá-los. São bem úteis na hora de fazer refatorações em código, e montar ações
a serem repetidas com <a href="http://stackoverflow.com/questions/7325052/can-someone-explain-to-me-why-the-dot-command-is-so-useful-in-vim">o comando
ponto</a>.</p>
<p>Uma dica interessante do livro sobre
<a href="http://usevim.com/2012/08/10/macros/">macros</a> é uma maneira de criar
macros que “param automático”. A ideia é usar um movimento
(<em><a href="http://vimdoc.sourceforge.net/htmldoc/motion.html">motion</a></em>) que
falhe quando a macro não deve mais ser aplicada. Quando um movimento
falha na execução de uma macro, o restante da execução é cancelado.
Sabendo disso, podemos tirar proveito na hora de montar e executar a
macro, o que nos permite criar macros "infinitas" que não precisam de
contagem exata e pararão a execução no momento certo.</p>
<p>Descobri algumas coisas legais também sobre a busca do Vim. Se você faz uma
busca usando o comando <em>/</em> e depois aciona a substituição com a busca vazia
<code>:s//texto a repor/</code> o Vim reusa o padrão usado na última busca. Isso é legal
porque permite você refinar a busca visualmente primeiro, e então montar o
comando de substituição depois. Às vezes isso é mais prático do que usar a
busca e substituição pedindo confirmação com <code>:s/texto a substituir/texto a
repor/gc</code>. Ah, e quando estiver montando expressões regulares na busca, é uma
boa ideia começar as ERs com o escape <code>\v</code> que ativa o <a href="http://www.malloc.co/vim/using-very-magic-to-make-vim-regular-expressions-cleaner/">comportamento ”very
magic”</a>
-- muito mágico e muito mais fácil.</p>
<p>Outra dica boa sobre busca é <a href="https://github.com/nelstrom/vim-visual-star-search">o plugin que muda comportamento do * e # no
modo visual</a>. Por padrão, o
Vim buscará a palavra sob o cursor (coerente com o comportamento no modo
normal), estendendo a seleção. O plugin altera para ele buscar o texto que está
selecionado, o que é bem mais útil. =)</p>
<p>Curti também as explicações sobre a integração do Vim com
<a href="http://ctags.sourceforge.net/">ctags</a>,
<a href="https://en.wikipedia.org/wiki/Grep">grep</a> & <a href="http://beyondgrep.com/">ack</a>, o
funcionamento do corretor ortográfico, etc -- tem uma seção do livro dedicada a
esses assuntos. Ainda não coloquei muita coisa na prática, mas fiquei cheio de
ideias.</p>
<p>Num mundo em que existem <a href="http://www.jetbrains.com/idea/">ferramentas muito inteligentes para edição de
código</a> que por vezes até escrevem o código por
você, o Vim tem se mantido relevante porque permite a economia de movimentos em
qualquer tipo de texto. A longo prazo, o Vim ainda é um bom investimento para
quem precisa de uma edição de texto mais refinada, como muitos programadores.
Não todos, porque alguns programadores infelizmente só usarão as linguagens bem
suportadas pela sua IDE. Mas a trupe de teimosos da qual eu faço parte
provavelmente vai se manter usando Vim até o fim -- o benefício vem a longo
prazo.</p>
<p>Enfim, <a href="https://www.amazon.com/Practical-Vim-Thought-Pragmatic-Programmers/dp/1934356980">compre</a>
<a href="http://pragprog.com/book/dnvim/practical-vim">o livro</a>, <a href="http://vimcasts.org/">assista os
vídeos</a>, siga <a href="https://twitter.com/vimcasts">o twitter do
Vimcasts</a>...</p>
<p><sub>Ah, e quando programar em Java, sugiro <a href="http://confluence.jetbrains.com/display/IDEADEV/EAP">usar o Intellij IDEA</a> -- bem melhor que o Eclipse. :D</sub></p>Alguns programas úteis para usar no Ubuntu2013-08-14T22:24:00+02:002013-08-14T22:24:00+02:00Elias Dornelestag:eliasdorneles.com,2013-08-14:/2013/08/14/alguns-programas-uteis-para-usar-no-ubuntu.html<p>Ok, hoje estou tirando a preguiça do traseiro para escrever sobre algo
que há tempo queria fazer: uma lista de alguns programas úteis que uso
no <a href="http://www.ubuntu.com/" title="Ubuntu Linux">Ubuntu</a>. A maioria deles eu
demorei um pouco para descobri-los, por isso acho uma boa idéia falar
deles por aqui -- são aplicações bacanas que …</p><p>Ok, hoje estou tirando a preguiça do traseiro para escrever sobre algo
que há tempo queria fazer: uma lista de alguns programas úteis que uso
no <a href="http://www.ubuntu.com/" title="Ubuntu Linux">Ubuntu</a>. A maioria deles eu
demorei um pouco para descobri-los, por isso acho uma boa idéia falar
deles por aqui -- são aplicações bacanas que merecem uma boa propaganda.</p>
<h3>Meld</h3>
<p><a href="http://meldmerge.org/">Meld</a> é uma ferramenta muito útil para
programadores, mas que pode muito bem ser útil para outras pessoas
também. Ele ajuda você a ver as diferenças entre versões diferentes de
arquivos ou pastas, e permite copiar as coisas de um lado para outro e
vice-versa.</p>
<p>Comparando duas pastas com o Meld:</p>
<p><a href="https://eljunior.files.wordpress.com/2013/08/minha_pasta-outra_pasta-meld_004.png"><img alt="Comparando duas pastas com o Meld" src="https://eljunior.files.wordpress.com/2013/08/minha_pasta-outra_pasta-meld_004.png" title="Comparando duas pastas com o Meld"></a></p>
<p>Ele é uma mão-na-roda para o desenvolvedor na hora de fazer
<em><a href="https://en.wikipedia.org/wiki/Merge_(revision_control)" title="Artigo sobre merges na Wikipedia">merges</a></em>
complicados, e também para verificar a situação de projetos que foram
alterados por pessoas diferentes sem usar um sistema de controle de
versão decente (que aliás, se a escolha estiver em aberto pra você ou
caso ainda esteja usando CVS/SVN, recomendo dar uma boa olhada no
<a href="http://mercurial.selenic.com/">Mercurial</a> -- <a href="http://hginit.com/">pode começar por
aqui</a>).</p>
<p>Para instalar no Ubuntu, digite num terminal:</p>
<p><code>sudo apt-get install meld</code></p>
<blockquote>
<p><strong>Dica:</strong> um jeito rápido de copiar e colar linhas de comando do
navegador no terminal é dar um triplo-clique (clicar 3x) em qualquer
lugar da linha pra selecioná-la inteira, e depois clicar no terminal
com o botão do meio (isto é, com a rodinha do mouse) -- isto já copia
e cola incluindo até o <kbd>Enter</kbd>. É o "copiar e colar" mais
tradicional do Linux, pra mim é meio surpreendente como muitos
<em>power-users</em> desconhecem esse truque.</p>
</blockquote>
<h3>Shutter</h3>
<p><a href="http://shutter-project.org/">Shutter</a> é um programa que ajuda a fazer
capturas da tela, aka, <em>screenshots</em>. A maioria das pessoas está
acostumada a fazer esse tipo de coisa usando a tecla <kbd>Print
Screen</kbd>, mas o legal do Shutter é que você pode escolher um pedaço
específico da tela pra capturar, fazer alterações por cima, tudo no
mesmo passo.</p>
<p><a href="https://eljunior.files.wordpress.com/2013/08/shutter-yo_dawg.png"><img alt="Yo dawg, I heard you like taking screenshots!" src="https://eljunior.files.wordpress.com/2013/08/shutter-yo_dawg.png?w=640"></a></p>
<p>Ele também tem plugins para aplicar efeitos nas imagens, fazer upload
para ImgUr, TwitPic, ImageShack, Dropbox, etc.</p>
<p>Pra instalar no Ubuntu, digite num terminal:</p>
<p><code>sudo apt-get install shutter</code></p>
<h3>DBeaver</h3>
<p>O <a href="http://jkiss.org/">DBeaver</a> é uma aplicação cliente de banco de dados
SQL, que suporta vários bancos e plataformas. Não é muito espetacular,
mas de todas as aplicações open-source desse tipo que testei, é de longe
a que tem a melhor usabilidade. Ele baixa os <em>drivers</em> adequados para
conectar nos vários bancos diferentes, só esse recurso já é uma bela
duma ajuda.</p>
<p>Pra instalar no Ubuntu, você pode escolher entre baixar e instalar o
pacote Debian ou baixar e descompactar o zip do site
<a href="http://dbeaver.jkiss.org/download/">http://dbeaver.jkiss.org/download</a> -- ou
ainda, você também pode <a href="http://marketplace.eclipse.org/node/507775">instalar como
plugin</a> para o
<a href="http://www.eclipse.org/">Eclipse</a> se preferir.</p>
<h3>PlayItSlowly</h3>
<p>O <a href="http://29a.ch/playitslowly/">PlayItSlowly</a> é um programa muito legal
que permite reproduzir arquivos de áudio ou vídeo em velocidade e
frequência diferentes do áudio/vídeo original, até <a href="https://eljunior.wordpress.com/2011/07/28/tocar-video-ou-musica-em-outra-velocidade-mantendo-o-tom/">já andei falando
antes sobre ele por
aqui</a>.</p>
<p><a href="https://eljunior.files.wordpress.com/2013/08/play-it-slowly_012.png"><img alt="Can you guess from which band is this song?" src="https://eljunior.files.wordpress.com/2013/08/play-it-slowly_012.png"></a></p>
<p>Usando o PlayItSlowly você pode fazer andar mais rápido o vídeo daquela
palestra lenta que dá sono e também ouvir um trecho duma música
repetindo em velocidade mais lenta sem perder o tom original, pra você
poder perceber melhor as notas -- bem útil pra quem quer aprender a
tocar alguma música. Além disso, você também pode sacanear seus amigos
reproduzindo uma gravação deles conversando com a fala fina... Esse
programa é muito bacana, especialmente porque eu tenho uma pequena
parcela de contribuição no quão legal ele é: a última versão dele inclui
algumas melhorias na interface que eu implementei. =)</p>
<p>Se você está usando a última versão do Ubuntu, pode instalar digitando
no terminal:</p>
<p><code>sudo apt-get install playitslowly</code></p>
<p>Caso esteja usando uma versão mais antiguinha, considere <a href="http://29a.ch/playitslowly/">baixar o
pacote com a última versão do site</a> --
prometo que a interface melhora legal.</p>
<h3>Amphetype</h3>
<p><a href="https://eljunior.files.wordpress.com/2013/08/amphetype_001.png"><img alt="Amphetype: pratique digitação digitando e lendo seu texto preferido" src="https://eljunior.files.wordpress.com/2013/08/amphetype_001.png?w=640" title="Tela inicial do Amphetype"></a></p>
<p><a href="http://code.google.com/p/amphetype/">Amphetype</a> é um programa pra treinar
digitação com textos que você escolhe, que também gera umas estatísticas
joiadas. Infelizmente, não está mais sendo mantido e acho que nunca teve um
empacotamento de verdade pra Linux (<a href="https://code.google.com/p/amphetype/downloads/list" title="Instaladores do Amphetype para Windows e Mac">só tem instalador para Windows e
Mac</a>). Mesmo assim, continua sendo bem decente -- eu
uso uma versão que modifiquei levemente para facilitar a deleção dos textos
fontes. Um dia quem sabe eu tomo vergonha na cara e tento montar um pacote,
publicar o <em>patch</em>, etc.</p>
<p>Como falei, não tem um empacotamento pronto pra Linux, mas você consegue
rodar baixando o código-fonte, usando alguns comandos no terminal:</p>
<ol>
<li>Instale o subversion para poder baixar os fontes:<br>
<code>sudo apt-get install subversion</code></li>
<li>Use o subversion para baixar os fontes:<br>
<code>svn checkout http://amphetype.googlecode.com/svn/trunk/ amphetype-read-only</code></li>
<li>Execute o programa com o comando:<br>
<code>python Amphetype.py</code></li>
</ol>
<h3>Pinta</h3>
<p>O Pinta é um programa muito bem feitinho, pra editar imagens no estilo
do MS Paint -- uma coisa que demorou um pouquinho pra aparecer no Linux.
Um recurso legal dele é o <em>“Recolor”</em>, que pinta apenas em cima de uma
determinada cor. Funciona como aquelas canetas marca-texto, permitindo
chamar atenção para textos em outras imagens como nesse exemplo:</p>
<p><a href="https://eljunior.files.wordpress.com/2013/08/diffusionofinnovation-pinta_003.png"><img alt="É divertido pintar com o Pinta =)" src="https://eljunior.files.wordpress.com/2013/08/diffusionofinnovation-pinta_003.png?w=640"></a>
É divertido pintar com o Pinta =)</p>
<p>Instale no Ubuntu digitando num terminal:</p>
<p><code>sudo apt-get install pinta</code></p>
<h3>Programas para usar na linha de comando</h3>
<p>Além desses programas, gostaria ainda de falar rapidão de outros
programas úteis pra quem também gosta de usar a linha de comando:</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Quilt_(software)">quilt</a> é um conjunto
de shell-scripts que ajudam a lidar com diffes e patches, é uma
ótima ferramenta para um desenvolvedor ter na sua caixa, já me foi
útil várias vezes. Instale com:<br>
<code>sudo apt-get install quilt</code></li>
<li><a href="http://utopia.knoware.nl/~hlub/rlwrap/">rlwrap</a> é um programa que
adiciona os recursos da linha de comando de histórico e atalhos de
edição, em qualquer outro programa que leia comandos da entrada
padrão (Teste com <code>rlwrap ruby</code>, por exemplo). Instale com:<br>
<code>sudo apt-get install rlwrap</code></li>
<li><a href="http://stackoverflow.com/questions/3455625/linux-command-to-print-directory-structure-in-the-form-of-a-tree">tree</a>
é um programa bem simples, que lista os diretórios em forma de
árvore. Por algum motivo, levei anos pra descobrir que esse programa
existia. Instale com:<br>
<code>sudo apt-get install tree</code></li>
</ul>Programming Grails -- a aventura continua2013-07-28T10:12:00+02:002013-07-28T10:12:00+02:00Elias Dornelestag:eliasdorneles.com,2013-07-28:/2013/07/28/programming-grails----a-aventura-continua.html<p>Alguns dias atrás terminei de ler o <em><a href="http://shop.oreilly.com/product/0636920024750.do" title="Programming Grails - OReilly">Programming
Grails</a> (<a href="https://www.amazon.com/Programming-Grails-Burt-Beckwith/dp/1449323936">Amazon</a>)</em>,
um livro sobre <a href="http://www.grails.org/">o framework Grails</a> voltado para
desenvolvedores experientes, que explica como funcionam várias coisas do
framework e aponta vários caminhos das pedras. O autor é <a href="http://burtbeckwith.com/">Burt
Beckwith</a>, conhecido na comunidade Grails por
criar vários plugins úteis do Grails …</p><p>Alguns dias atrás terminei de ler o <em><a href="http://shop.oreilly.com/product/0636920024750.do" title="Programming Grails - OReilly">Programming
Grails</a> (<a href="https://www.amazon.com/Programming-Grails-Burt-Beckwith/dp/1449323936">Amazon</a>)</em>,
um livro sobre <a href="http://www.grails.org/">o framework Grails</a> voltado para
desenvolvedores experientes, que explica como funcionam várias coisas do
framework e aponta vários caminhos das pedras. O autor é <a href="http://burtbeckwith.com/">Burt
Beckwith</a>, conhecido na comunidade Grails por
criar vários plugins úteis do Grails, <a href="http://burtbeckwith.com/blog/">escrever sobre Grails no seu
blog</a>, <a href="http://stackoverflow.com/users/160313/burt-beckwith" title="Burt Beckwith no StackOverflow">responder perguntas no
StackOverflow</a>,
<a href="http://www.infoq.com/author/Burt-Beckwith">palestrar</a> em
<a href="http://gr8conf.eu/Speakers/Burt-Beckwith">conferências</a> e
também colaborar no desenvolvimento do próprio Grails.</p>
<p><a href="http://shop.oreilly.com/product/0636920024750.do"><img alt="Programming Grails -- Best Practices for Experienced Grails Developers" src="https://eljunior.files.wordpress.com/2013/07/cat.gif"></a></p>
<p>Comprei o livro na Amazon ainda antes do lançamento oficial porque sabia
que sendo material do Burt seria muito bom. Não me decepcionei: o livro
é excelente! Na mesma semana que comecei a ler já pude aplicar as idéias
do livro, e minha compreensão do framework melhorou bastante --
recomendo fortemente pra quem trabalha com o framework. O livro não é
para iniciantes, todavia -- para quem quer começar com Grails, pode ser
melhor pegar um livro como o <a href="http://www.manning.com/gsmith2/">Grails in
Action</a> ou o <a href="http://www.apress.com/java/java-ee/9781430243779">The Definitive Guide to
Grails 2</a>.</p>
<h3>Introdução a Groovy</h3>
<p>O texto começa com uma introdução à linguagem
<a href="http://groovy.codehaus.org/">Groovy</a>, a linguagem usada no
desenvolvimento com Grails, demonstrando várias particularidades da
linguagem e sua excelente interoperabilidade com Java, explicando alguns
detalhes da implementação e exemplificando as várias vantagens que a
linguagem oferece em relação a Java. Já estou usando Groovy há um bom
tempo, mas essa introdução esclareceu algumas coisas sobre a linguagem.</p>
<p>Um destaque dessa parte é a explicação sobre <a href="http://groovy.codehaus.org/Closures" title="Groovy Closures -- documentação oficial"><em>owner</em>, <em>delegate</em> e
<em>this</em> nas closures em
Groovy</a>.
Basicamente, numa closure em Groovy, <strong><em>this</em></strong> se refere à instância da
classe que contém a Closure, <strong><em>owner</em></strong> se refere ou a essa instância
ou a outra closure que esteja envolvendo a closure atual, e
<strong><em>delegate</em></strong> é uma variável mutável que por padrão aponta pra owner. O
interessante aqui é que você pode alterar o valor de <em>delegate</em> em tempo
de execução, e redefinir todo o comportamento da closure. Essa técnica é
bastante utilizada para criar as <a href="https://pt.wikipedia.org/wiki/Linguagem_de_dom%C3%ADnio_espec%C3%ADfico">mini-linguagens
(DSLs)</a>
em Grails, tipo as que você usa nos blocos <em>mapping</em> e <em>constraints</em>
numa classe de domínio.</p>
<p>Segue um exemplo pra ajudar a entender:</p>
<div class="highlight"><pre><span></span><code><span class="kd">class</span><span class="w"> </span><span class="nc">OutraClasse</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="kt">def</span><span class="w"> </span><span class="n">metodoDaOutraClasse</span><span class="o">()</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="n">println</span><span class="w"> </span><span class="s2">"metodoDaOutraClasse()"</span>
<span class="w"> </span><span class="o">}</span>
<span class="w"> </span><span class="o">}</span>
<span class="w"> </span><span class="kd">class</span><span class="w"> </span><span class="nc">ClasseMae</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="kt">def</span><span class="w"> </span><span class="n">minhaClosure</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="kt">def</span><span class="w"> </span><span class="n">subClosure</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">{</span>
<span class="w"> </span><span class="n">println</span><span class="w"> </span><span class="s2">"this: ${this.class}"</span>
<span class="w"> </span><span class="n">println</span><span class="w"> </span><span class="s2">"owner: ${owner.class}"</span>
<span class="w"> </span><span class="n">println</span><span class="w"> </span><span class="s2">"delegate: ${delegate.class}"</span>
<span class="w"> </span><span class="n">metodoDaOutraClasse</span><span class="o">()</span>
<span class="w"> </span><span class="o">}</span>
<span class="w"> </span><span class="n">subClosure</span><span class="o">.</span><span class="na">delegate</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">OutraClasse</span><span class="o">()</span>
<span class="w"> </span><span class="n">subClosure</span><span class="o">()</span>
<span class="w"> </span><span class="o">}</span>
<span class="o">}</span>
<span class="k">new</span><span class="w"> </span><span class="n">ClasseMae</span><span class="o">().</span><span class="na">minhaClosure</span><span class="o">()</span>
</code></pre></div>
<p>Nesse exemplo, por causa da redefinição do delegate da <em>subClosure()</em>,
podemos chamar métodos da <em>OutraClasse</em> dentro dele. O resultado de
rodar esse código é:</p>
<div class="highlight"><pre><span></span><code><span class="k">this</span><span class="o">:</span><span class="w"> </span><span class="kd">class</span><span class="w"> </span><span class="n">ClasseMaeowner</span><span class="o">:</span><span class="w"> </span><span class="kd">class</span><span class="w"> </span><span class="n">ClasseMae$_closure1delegate</span><span class="o">:</span><span class="w"> </span><span class="kd">class</span><span class="w"> </span><span class="n">OutraClassemetodoDaOutraClasse</span><span class="o">()</span>
</code></pre></div>
<p>Recomendo assistir a palestra <a href="http://gr8conf.eu/Presentations/Functional-Programming-in-Groo">Functional Programming in
Groovy</a>,
para ver um exemplo legal de uso do <em>delegate</em> simplificando uma API de
envio de email.</p>
<h3>Grails Internals</h3>
<p>O livro avança falando do framework Grails, das várias escolhas que
foram feitas na sua criação e evolução, e explica como criar e rodar uma
aplicação, narrando o que acontece quando você roda cada comando. A
seguir, Burt descreve todos os plugins incluídos na instalação padrão:
para o que servem, como foram implementados e como você pode
configurá-los ou desativá-los, se assim desejar.</p>
<p>Este capítulo define o tom do livro, no
sentido de que ele é bem voltado para quem deseja saber melhor como as
coisas funcionam. Por isso, ele pode ser um tanto entediante para alguém
que esteja buscando algo mais receita-de-bolo garantindo gratificação
imediata -- o livro fala bastante nos detalhes de implementação de
várias partes do framework, com a idéia de habilitar você a resolver
problemas em todos os níveis de abstração envolvidos no desenvolvimento
de uma aplicação Grails.</p>
<p>Acho que esse é o tipo de livro que é bom ter sempre por perto quando
estiver desenvolvendo para poder consultar. Várias vezes desejei
consultá-lo quando estava no trabalho, lembrando ter lido algo que ia
ajudar no problema que estava resolvendo. Então, a dica é mantê-lo ao
alcance -- agora eu carrego na mochila. :)</p>
<p>Bem, seguindo adiante, o Burt fala de persistência com o
<a href="http://grails.org/GORM">GORM</a> (Grails Object Relational Mapping),
passando dicas de configuração pra facilitar a vida na hora de depurar o
código -- configurar um método nas classes de domínio para mensagens de
erro mais amigáveis, um filtro pra converter brancos em nulos, entre
outros.</p>
<h3>Spring e Injeção de Dependência</h3>
<p>O capítulo seguinte é sobre o papel do
<a href="https://pt.wikipedia.org/wiki/Spring_Framework">Spring</a> e <a href="https://pt.wikipedia.org/wiki/Inje%C3%A7%C3%A3o_de_depend%C3%AAncia">injeção de
dependência</a>
no Grails, explicando o funcionamento dos serviços Grails (que são beans
do Spring com suporte a transação), vários detalhes de configuração que
funcionam em cima do Spring, incluindo como integrar com outras
aplicações Spring já existentes. Aqui você já deve entender que é a
flexibilidade do Spring e a riqueza do ecossistema em torno dele que
garantem bastante poder ao Grails e a facilidade de integrar com várias
tecnologias diferentes. Acho que o Grails é um bom exemplo de tecnologia
que aproveita bastante as outras soluções já existentes no mercado por
isso.</p>
<p>Aliás, apesar de conter vários pontos excelentes, esse capítulo sobre Spring
foi uma leitura um tanto árida -- em alguns momentos o texto descreve detalhes
de implementação de maneira complicada de entender, coisas tipo: “pra fazer
<code><algum recurso></code>, Grails instancia a classe <code><fully qualified name da classe
aqui></code>, que implementa a interface <code><outro fully qualified name aqui></code> e usa o
adapter <code><ainda outro fully qualified name></code>, registrando um bean <code><nome do
bean></code> ...“!</p>
<p>Ficou um pouco difícil de acompanhar, especialmente por eu não estar na
frente da IDE, sem poder conferir facilmente as definições das classes.
Bem, eu sabia onde estava me metendo quando peguei um livro avançado,
acho que o Burt fez um excelente trabalho com o livro, mas houveram
esses trechos que reli várias vezes e continuei sem entender. Talvez meu
conhecimento de <em>design patterns</em> esteja fraco -- nunca fiz questão de
estudá-los muito, de qualquer forma.</p>
<h3>Hibernate</h3>
<p>A seguir, vem o maior capítulo do livro, dissecando o uso do Hibernate com
Grails, tanto com e sem o GORM. Aqui ele explica vários detalhes de
funcionamento do mapeamento objeto-relacional e como usá-lo para obter o máximo
de benefício. Burt sugere brincar com uma aplicação configurada com Hibernate
puro (isto é, sem o plugin do Hibernate pro Grails & GORM) como um exercício
útil pra entender o que Grails provê de graça pra você.</p>
<p>Um trecho muito legal desse capítulo é a parte sobre <em>caching</em>, em que ele
mostra como configurar o mecanimo de cache do Grails (usando
<a href="http://ehcache.org/">Ehcache</a>) e testar usando o console do Grails (<em>grails
console</em>), conferindo as saídas do log. Compreendi melhor como funciona o
esquema de cache do Grails e como tirar vantagem dele minimizando os riscos de
acontecer merda. Tem <a href="http://www.infoq.com/presentations/GORM-Performance">uma apresentação do Burt relacionada a esse assunto
disponível online</a>, vale
conferir.</p>
<p>Bem, ainda nesse capítulo (eu falei que era o maior do livro =P), vem
uma série de dicas sobre o uso do GORM com Hibernate, incluindo um
configurador de nomes para as chaves estrangeiras (porque os
<em>FK1236718237</em> que o Hibernate gera por padrão são crípticos demais na
hora de depurar), como mapear views e subclasses, diferenças entre
<a href="http://grails.org/doc/latest/ref/Domain%20Classes/get.html">get</a>/<a href="http://grails.org/doc/latest/ref/Domain%20Classes/load.html">load</a>/<a href="http://grails.org/doc/latest/ref/Domain%20Classes/read.html">read</a>
e algumas dicas sobre performance. Sobre esse assunto, também recomendo
ler os posts do Peter Ledbrook da série GORM Gotchas, seguem os links:</p>
<ol>
<li><a href="http://blog.springsource.org/2010/06/23/gorm-gotchas-part-1/">http://blog.springsource.org/2010/06/23/gorm-gotchas-part-1/</a></li>
<li><a href="http://blog.springsource.org/2010/07/02/gorm-gotchas-part-2/">http://blog.springsource.org/2010/07/02/gorm-gotchas-part-2/</a></li>
<li><a href="http://blog.springsource.org/2010/07/28/gorm-gotchas-part-3/">http://blog.springsource.org/2010/07/28/gorm-gotchas-part-3/</a></li>
</ol>
<p>Especificamente sobre o comportamento do <a href="http://grails.org/doc/latest/ref/Domain%20Classes/save.html" title="save()">método
save()</a>
explicado no primeiro post dessa série GORM Gotchas, eu <a href="https://eljunior.wordpress.com/2013/06/03/aventurando-se-com-grails/">penso um pouco
diferente</a>
dos autores do framework e sempre configuro a chave
<code>grails.gorm.failOnError=true</code> no <em>Config.groovy</em> logo após criar um
projeto novo em Grails. Acho que é especialmente importante fazer isso
quando a equipe de desenvolvedores é um pouco heterogênea ou recém está
começando a usar o framework -- você evita muitas sessões de depuração
quando o <em>save()</em> sempre ou salva ou erra berrantemente.</p>
<h3>Integração</h3>
<p>Em sequência tem um capítulo sobre integração, em que o livro cobre as
facilidades do Grails para usar mensageria com JMS, enviar emails de
forma assíncrona, criar e acessar WebServices SOAP usando os plugins
<a href="http://grails.org/plugin/cxf">CXF</a> e <a href="http://grails.org/plugin/cxf-client">CXF
client</a>, criar e acessar
WebServices REST com os plugins <a href="http://grails.org/plugin/jaxrs">JAX-RS</a>
e <a href="http://grails.org/plugin/rest-client-builder">REST Client Builder</a> e
também como habilitar gerenciamento e monitoração com o <a href="http://grails.org/plugin/jmx">plugin
JMX</a>. Ah, outra coisa legal que o Burt
mostra nesse capítulo é como usar o <a href="http://grails.org/plugin/tcpmon">plugin
TCPMon</a> para depurar as requisições que
chegam no servidor rodando em desenvolvimento -- ele funciona como um
<em>proxy</em> rodando em outra porta e tem uma interface desktop pra
inspecionar os dados da requisições, bem interessante.</p>
<h3>Configuração</h3>
<p>Depois tem um capítulo dedicado ao assunto de configuração, que ensina uma
série de truques para organizar suas configurações. É bem útil, porque no
Grails as configurações podem ficar um pouco bagunçadas, então é legal dar uma
arrumada na casa de vez em quando. Como alguns arquivos suportam algumas
funcionalidades especiais, às vezes são necessários alguns truques pra
modularizá-los ou fazer as configurações específicas por ambiente.</p>
<h3>Plugins</h3>
<p>Esse capítulo é bem legal, explica como funciona o mecanismo de plugins
do Grails e ensina as boas práticas na hora de criar seu próprio plugin.
Curti bastante o esquema de plugins do Grails, é realmente bem poderoso:
a estrutura de um plugin é bem parecida a de uma aplicação, podendo
adicionar classes de domínio, controllers, filtros, recursos estáticos
(Javascript, CSS), beans do Spring, e tudo o mais.</p>
<p>Isso quer dizer que é fácil de quebrar suas aplicações em vários
plugins, bastando você manter as relações de dependências adequadas
entre as classes -- e o livro tem uma seção dedicada a fazer justamente
isso, incluindo publicar os plugins num repositório local com o
<a href="http://www.jfrog.org/">Artifactory</a>.</p>
<p>Nesse mesmo capítulo, o Burt demonstra sua experiência no
desenvolvimento de vários plugins detalhando seu workflow para
desenvolver e testar vários plugins, usando diferentes versões do
framework -- muitas dicas úteis.</p>
<h3>Segurança</h3>
<p><em>“O propósito desse capítulo é assustar você.”</em> É assim que começa o capítulo
do Programming Grails sobre segurança -- que é excelente, por sinal! Aqui, Burt
explica vários riscos (os <a href="https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project">Top Ten da
OWASP</a>, o livro
usou os de 2010, mas já saiu uma lista atual) aos quais sua aplicação pode
estar vulnerável caso você não tome certos cuidados.</p>
<p>O livro dá várias dicas de como melhorar a segurança das aplicações, e
explica como usar alguns plugins interessantes que ajudam a melhorar
alguns aspectos de segurança. Como o assunto é complicado, vou apenas
dizer aqui alguns pontos muito importantes que todo mundo usando Grails
precisa ficar ligado:</p>
<p><strong>1)</strong> Considere configurar o codec de HTML por padrão para as páginas
GSP, no <em>Config.groovy</em>:</p>
<div class="highlight"><pre><span></span><code><span class="n">grails</span><span class="o">.</span><span class="na">views</span><span class="o">.</span><span class="na">default</span><span class="o">.</span><span class="na">codec</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'html'</span>
</code></pre></div>
<p>Dessa forma, as variáveis usadas nas páginas GSP serão escapadas com
HTML por padrão -- a configuração (<em>'none'</em>) não escapa nada, uma
escolha infeliz que tem sido mantida pra não quebrar compatibilidade.</p>
<p><strong>2)</strong> Não implemente seu próprio mecanismo de autenticação e autorização. Use
os plugins/frameworks testados e aprovados pela comunidade (uso e recomendo o
<a href="http://www.springsource.org/spring-security">Spring Security</a>, cujo <a href="http://grails.org/plugin/spring-security-core">plugin
pro Grails</a> foi feito por
ninguém menos que o próprio Burt Beckwith). Tem muitos tutoriais de Grails na
Internet ensinando a fazer autorização usando filtros, implicando que é fácil
de fazer autorização -- dica: não é! À medida que vai desenvolvendo a
aplicação, você descobre que precisa de vários outros recursos relacionados:
<em>hash</em> decente para as senhas, gerenciamento da sessão, fluxo para “esqueci a
senha”, etc. Se você implementar esses recursos você mesmo, aumenta bastante o
risco de acabar fazendo alguma coisa errada. Portanto, faça uso do que está
disponível, invista em estudar os plugins disponíveis -- vale a pena.</p>
<p><strong>3)</strong> Capriche. Teste sua segurança com testes funcionais, não com testes
unitários ou de integração que usam mocks e stubs. Faça revisão de código com a
equipe para procurar vulnerabilidades em potencial. Mantenha-se atualizado
sobre as atualizações do framework. Aprenda <a href="http://blog.springsource.org/2012/03/28/secure-data-binding-with-grails/">a fazer data binding com
segurança</a>.</p>
<h3>Cloud, AOP e Upgrade</h3>
<p>O livro dedica um breve capítulo explicando o deploy no Cloud, falando das
vantagens/desvantagens, e explicando passo-a-passo como fazer deploy de
aplicações que usam banco de dados no <a href="http://www.cloudfoundry.com/">Cloud
Foundry</a> e <a href="http://www.heroku.com/">Heroku</a>, e
algumas configurações para fazer escalar. Curti! =)</p>
<p>A seguir, vem um trecho interessante sobre as técnicas de <a href="https://pt.wikipedia.org/wiki/Programa%C3%A7%C3%A3o_orientada_a_aspecto">programação
orientada a
aspectos</a>
disponíveis por padrão no Grails (basicamente, as mesmas já disponíveis no
Spring só que empoderadas pela linguagem Groovy), e também como adicionar
outras capacidades usando o <a href="http://grails.org/plugin/aspectj">plugin AspectJ</a>.
Burt ilustra AOP com uma maneira de avisar se algum método das classes de
domínio que altera o estado do banco está sendo chamado fora de um contexto de
transação -- <em>pretty cool stuff</em>!</p>
<p>Por fim, o último capítulo detalha os procedimentos para fazer upgrade de
aplicações para versões mais novas do Grails (Burt usa um método sofisticado
que inclui fazer um <em>diff</em> com uma aplicação nova criada com a mesma versão da
aplicação legada, pra saber com precisão o que foi alterado), e faz um breve
histórico das mudanças nas versões mais importantes do Grails, explicando as
novidades e rumos tomados no framework.</p>
<p>A maior mudança foi na versão 2.0, que trouxe vários plugins novos, adotou a
jQuery e muitas melhorias - e algumas quebras de compatibilidade. Algumas das
mudanças que causam quebra são: os métodos nos controllers também são
considerados como actions (antes eram apenas closures), os JOINs com Criteria
são INNER joins em vez de LEFT joins, alguns nomes dos recursos na configuração
dos logs mudaram e a inclusão do <a href="http://grails.org/plugin/resources">plugin
resources</a> pode forçar algumas alterações.
Sempre vale conferir <a href="http://grails.org/doc/latest/guide/upgradingFromPreviousVersionsOfGrails.html">a documentação oficial na hora de fazer o
upgrade</a>.
O Peter Ledbrook também tem algumas <a href="http://pledbrook.github.io/grails-howtos/en/upgradeToGrails2.html">dicas para o upgrade para Grails
2</a>.</p>
<h3>Conclusão</h3>
<p>Enfim, o livro é muito bom, recomendo fortemente pra quem esteja usando
Grails, descobri várias coisas novas e ainda quero botar em prática
várias idéias que aprendi nele. Como já disse no início, para quem quer
começar com Grails pode ser mais adequado usar outro material antes, mas
logo depois de pegar o jeito já pode partir para o <em>Programming Grails</em>
-- a satisfação é garantida.</p>
<p><em>That’s all, folks! =)</em></p>Goodbye, JSF!2013-06-23T13:31:00+02:002013-06-23T13:31:00+02:00Elias Dornelestag:eliasdorneles.com,2013-06-23:/2013/06/23/goodbye-jsf.html<p>Ok, se você não é javeiro, talvez nunca tenha ouvido falar em JSF. <em>No
worries</em>, você não está perdendo muita coisa.</p>
<p>Porém, se você aprendeu a programar em Java, talvez nem tenha procurado
aprender outra linguagem de propósito geral (... <em>ainda</em>, I hope) mas já
se interessou por programar para a …</p><p>Ok, se você não é javeiro, talvez nunca tenha ouvido falar em JSF. <em>No
worries</em>, você não está perdendo muita coisa.</p>
<p>Porém, se você aprendeu a programar em Java, talvez nem tenha procurado
aprender outra linguagem de propósito geral (... <em>ainda</em>, I hope) mas já
se interessou por programar para a Web, nesse caso provavelmente já
ouviu falar, talvez deu uma conferida, ou quem sabe está ferrado tendo
que manter aplicações escritas com o <a href="https://pt.wikipedia.org/wiki/JavaServer_Faces">Java Server Faces -- aka
JSF</a>.</p>
<p>Os motivos para o meu ranço com JSF são vários. Alguns problemas que eu
vejo são técnicos, outros são culturais e outros são meio filosóficos,
mesmo.</p>
<p>Há uns anos atrás, quando tive meu primeiro contato com JSF, odiei a
tecnologia com todas as minhas forças. Meu background com Web era
principalmente
<a href="https://en.wikipedia.org/wiki/LAMP_(software_bundle)">LAMP</a> -- muito PHP
e um pouquinho de Python/Django -- e todo aquele mundo JSF de
componentes no servidor era uma coisa <strong>muito</strong> distante. Continua sendo
distante de certa forma, mas hoje a coisa até que está melhorzinha para
o JSF.</p>
<p>Enfim, pude ter uma compreensão melhor da coisa quando, depois de passar
2 anos reclamando, resolvi brigar de volta. Decidi lutar com o dragão,
ia aprender como a bagaça funcionava, pra depois poder xingar com
propriedade -- em um post comprido no blog! :P</p>
<p>Comecei a acompanhar a <a href="http://stackoverflow.com/tags/jsf/" title="JSF taginfo">tag JSF no
StackOverflow</a>, li e
reli as respostas e perguntas dos top usuários e comecei a tentar
responder as perguntas de outros -- a velha tática de aprender tentando
resolvendo problemas mais ou menos reais.</p>
<p>Nesse caminho, acabei aprendendo bastantes coisas, e à medida que fui
dominando mais a parada eu estava até já quase começando a gostar -- mas
aí aconteceu que <a href="http://grails.org">Grails</a> meio que <a href="https://eljunior.wordpress.com/2013/06/03/aventurando-se-com-grails/">se meteu no meio
da
história</a>
e o meu ranço com JSF voltou. Aliás, estou atualmente lendo o livro
<a href="http://shop.oreilly.com/product/0636920024750.do" title="Programming Grails - pagina do livro">Programming
Grails</a> e
estou descobrindo tudo tão mais fácil que Java/JSF, que decidi
compartilhar logo meu <em>rant</em> antes que eu apague da memória. :P</p>
<h1>Problema técnico chato de JSF</h1>
<p>O grosso da lógica de UI fica no lado servidor. <em>Yeah</em>, os browsers
estão cada vez mais espertos, a tendência tem sido
<em>fat-client/thin-server</em> já há algum tempo, e JSF ainda tá nessa de usar
o servidor pra controlar quase tudo da interface. Isto significa que
mesmo para pequenas atualizações na tela do lado cliente, você
<strong>precisa</strong> fazer novas requisições AJAX ao servidor.</p>
<p>Pior, para suportar isso, o objeto que representa a árvore de
componentes (view state) de cada página XHTML é armazenada no servidor.
Para cada acesso... Para cada usuário... Por várias requisições
consecutivas... [1]</p>
<p>Está vindo aí no <a href="http://jdevelopment.nl/jsf-22/" title="JSF 2.2">JSF 2.2</a> o
suporte a <a href="https://jsfcorner.blogspot.com.br/2013/05/jsf-22-stateless-views-explained.html">Stateless
Views</a> (basicamente,
páginas que não precisem de armazenar a árvore no servidor) para amainar
o problema, mas como para usá-las você precisa abrir mão de várias
comodidades do framework
(<a href="http://docs.oracle.com/javaee/6/api/javax/faces/bean/ViewScoped.html">@ViewScoped</a>,
por exemplo), não percebo tanto avanço assim. [2]</p>
<h1>Problema filosófico chato de JSF</h1>
<p><a href="https://en.wikipedia.org/wiki/Design_by_committee">Design by comittee</a>
-- no caso, não só de JSF, mas de <a href="https://en.wikipedia.org/wiki/Java_Platform,_Enterprise_Edition">Java
EE</a> em
geral. As coisas demoram muito pra evoluir esperando pelos comitês de
<em>experts</em> resolverem as coisas, e não ficam com a melhor qualidade por
causa disso. Spring está aí sustentando a controvérsia há já alguns anos
-- existe uma velha discussão Spring (projeto graúdo open source
tradicional, evolui sem especificação) vs Java EE (uma cacetada de
especificações, todo um processo para sugestão de melhorias,
implementações de referência de cada especificação espalhadas em
projetos open source mundo afora e reunidas no
<a href="https://glassfish.java.net">Glassfish</a>) que já está meio gasta mas
<a href="http://stackoverflow.com/questions/2822812/spring-3-0-vs-java-ee-6-0">ainda
sobrevive</a>.</p>
<p>Uma das coisas chatas desse problema é que seguidamente algum ingênuo
que pensa de forma conservadora vai dizer pra você que é melhor usar
Java EE porque é “<em>standardized</em>”, querendo dizer que é padronizado,
especificado e tudo o mais. Escolhendo Java EE você supostamente não se
prenderia a nenhum fabricante (já que tem várias implementações das
espeficações), e evita o “lock-in” que você está sujeito se usar Spring.
<em>OH NO, vamos ficar presos à uma solução “proprietária”</em>! Nevermind que
o Spring é open source, e que existem muitos empreendimentos por aí
usando .NET e outras coisas <em>realmente</em> proprietárias, do tipo em que o
<em>lock-in</em> é real, e tudo continua funcionando mesmo assim. Dá pra
imaginar?</p>
<p>Fora que você não ganha muita liberdade de escolha indo com Java EE. O
que acaba acontecendo é que você acaba escolhendo um servidor de
aplicação, pelo menos uma biblioteca de componentes e fica preso neles
até o fim. Experimenta mudar pra ver se você não está em <em>vendor
lock-in</em>... E agora?</p>
<p>Enfim, na minha opinião, esses argumentos são balela. As reais vantagens
e desvantagens que diferenciam um e outro estão relacionadas a políticas
de configuração. Com Spring, o <em>deploy</em> é usualmente obter um WAR que já
tem todas as configurações que a aplicação precisa dentro, e basta
jogá-lo no servidor de aplicação -- a configuração de ambiente é
usualmente feita em tempo de <em>build</em>. Com Java EE, você precisa fazer
todas as configurações necessárias para a aplicação (datasources, filas,
etc) no servidor de aplicação (ainda bem que a interface pra configurar
é padrão em todos os servidores de aplicação... <em>NOT!</em>), e geralmente
tem alguém responsável pela configuração que acaba mexendo nos WARs,
EARs e JARs da vida. Como algumas empresas têm equipes dedicadas para
cuidar da infra Java (e têm medo de deixar os desenvolvedores mexer no
banco de produção), o Java EE é jogo pra elas.</p>
<h1>Problema cultural chato de JSF</h1>
<p>Acabo classificando esse problema como cultural porque é uma coisa que
fica meio "aceita" pelo pessoal, e se reflete na maioria das aplicações.
Basicamente, a curva de aprendizado é escarpada e longa <strong>demais</strong>!
Fazer JSF de um jeito decente exige aprender o famoso <a href="http://docs.oracle.com/javaee/6/tutorial/doc/bnaqq.html">ciclo de
vida</a> (um
<a href="https://javaserverfaces.java.net/nonav/docs/2.0/javadocs/javax/faces/lifecycle/Lifecycle.html">objeto</a>
usado pra controlar toda a putaria que exige programação Web baseada em
componentes com Java), sacar que o código dentro do seu XHTML passa por
várias fases de execução diferentes (construção da view, renderização da
view, HTML renderizado rodando no browser) e uma cacetada enorme de
pegadinhas não-intuitivas. Aprender todas essas coisas leva um tempo
danado!</p>
<p>O resultado é que você só aprende a coisa pela metade, decidindo que não
vale a pena ir muito a fundo, acaba se conformando com as soluções
existentes e fica esperando que alguém mais encarnado resolva os
problemas parecidos com os que você está tentando resolver -- pra depois
você copiar a solução. A galera que programa em JSF acaba conhecendo o
<a href="https://balusc.blogspot.com" title="BalusC's blog">BalusC</a> de uma maneira ou
outra, basicamente porque ele resolve a maioria dos problemas práticos
de JSF antes de todo mundo. Esse cara é um herói de Java EE -- ele manja
mais de JSF que os próprios desenvolvedores da parada!</p>
<p>Ele faz algumas coisas importantíssimas que mantêm JSF vivo: mantém o
<a href="http://code.google.com/p/omnifaces">OmniFaces</a> (um projeto de código
aberto simplesmente imperdível pra quem programa JSF 2.x), escreve
tutoriais <a href="https://balusc.blogspot.com">bem completos e compreensíveis no seu
blog</a>, e responde ativamente as <a href="http://stackoverflow.com/tags/jsf*" title="tag JSF no SO">perguntas
no Stackoverflow</a>.
Aprendi muito desse cara -- além de ser um
<a href="https://en.wikipedia.org/wiki/Maven">maven</a> de Java/JSF, é um cara muito
generoso compartilhando seu conhecimento e sempre atencioso. <em>Hey,
Bauke, all the JSF devs in the world thank their gods for your very
existence and spetacular work. You rock, dude!</em></p>
<p>Bem, mas como ele é ele, e eu sou eu, ele provavelmente está nesse
momento estudando, produzindo, escrevendo ou <a href="http://stackoverflow.com/tags/jsf/">ajudando a galera no
SO</a>, enquanto eu tô aqui, escrevendo
só mais um <em>rant</em> no blog.</p>
<p>Enfim, para esse post não ficar só na reclamação, vou usar o velho
truque de jornalista e colocar aqui...</p>
<h1>10 coisas que todo desenvolvedor JSF precisa saber</h1>
<p>Ok, está mais para 10 perguntas e respostas do StackOverflow que todo
desenvolvedor JSF precisa ler, mas tá valendo! :)</p>
<h2>1. <a href="http://stackoverflow.com/questions/3106452/how-do-servlets-work-instantiation-session-variables-and-multithreading">Como funcionam os tais servlets? O que acontece quando eu inicio uma aplicação, e em que ordem?</a></h2>
<p>Entender como funcionam os servlets, filtros, listeners, as sessões e
como funciona tudo isso em cima do protocolo HTTP ajuda bastante na hora
de resolver problemas -- são os fundamentos de Java Web. A explicação
concisa e bem completa contida nessa resposta do BalusC simplesmente não
tem preço.</p>
<h2>2. <a href="http://stackoverflow.com/questions/2090033/why-jsf-calls-getters-multiple-times">Porque os métodos getters são chamados várias vezes durante a mesma requisição?</a></h2>
<p>Boa pergunta! Leia essa pra saber por que você não deve fazer chamadas
de acesso ao banco dentro de um método <em>getAlgumaCoisa()</em> nos seus
backing beans. E sim, eu também já fiz isso antes e tive que mudar
tudo... Contra-intuitivo, ou não?</p>
<h2>3. <a href="http://stackoverflow.com/questions/2118656/hcommandlink-hcommandbutton-is-not-being-invoked">Meu botão ou link não está sendo acionado! Ai mel dels, e agora?</a></h2>
<p>Rá! Você caiu na armadilha! Leia todos os itens possíveis nessa
resposta, é uma excelente checklist na hora de depurar problemas. Você
vai acabar aprendendo um bocadinho de JSF, vai se dar conta que o BalusC
é um herói por conseguir fazer as coisas acontecerem mesmo JSF sendo a
droga que é -- e escrever respostas completíssimas no SO.</p>
<p>Quero dizer, olhe para aquela lista! Ninguém devia ter TANTO possíveis
problemas afetando se um botão vai realmente fazer o esperado! Talk
about bad developer UX...</p>
<h2>4. <a href="http://stackoverflow.com/questions/4317684/when-should-i-use-houtputlink-instead-of-hcommandlink">Quando devo usar links e quando usar commandLinks?</a></h2>
<p>HTTP: GET vs POST. Navegação/favoritabilidade vs. ações do tipo altera/cria
alguma coisa. A maioria dos desenvolvedores JSF levaram 10 anos para aprender
<a href="http://www.w3.org/2001/tag/doc/whenToUseGet.html">quando usar GET vs POST</a>.
Alguns ainda não aprenderam... </p>
<h2>5. <a href="http://stackoverflow.com/questions/4994458/how-can-i-pass-a-parameter-to-a-commandlink-inside-a-datatable">Como passar parâmetro para um commandLink dentro de um datatable?</a></h2>
<p>Datatables são basicamente inúteis se você não puder fazer uma ação para
agir no registro de uma linha. Isso às vezes é mais difícil do que
parece. Leia essa para não sofrer na próxima vez que precisar fazer
isso. E não seja bobo: se estiver usando um container antigo, <a href="http://stackoverflow.com/questions/3284236/invoke-direct-methods-or-methods-with-arguments-variables-parameters-in-jsf">use a
JBoss-EL logo e largue de
frescura</a>!</p>
<h2>6. <a href="http://stackoverflow.com/questions/10726653/by-default-jsf-generates-unusable-ids-which-are-incompatible-with-css-part-of">Meu jQuery não tá funcionando! #comofas</a></h2>
<p>JSF gera ids no HTML usando o dois-pontos <strong>':'</strong> como separador, isso
acaba gerando alguma confusão porque o dois-pontos é um separador com
significado diferente para a nossa <em><a href="http://www.jquery.com" title="jQuery rocks!">beloved Javascript library
jQuery</a></em>. Aprenda como evitar ser
mordido por esse problema.</p>
<p>Talvez você possa aproveitar o ensejo pra mudar de hábito: como atrelar
comportamento pelo <em>id</em> do elemento HTML não escala, há quem digo que é
melhor usar sempre <em>classes</em>. Dizem que é como o Gmail faz, mas nunca
conferi... (sim, eu tenho medo do JavaScript compilado do Gmail).</p>
<h2>7. <a href="http://stackoverflow.com/tags/composite-component/info">Como usar Composite Components?</a></h2>
<p>Ok, dessa vez o link não é para uma pergunta/resposta no SO, mas para a
wiki da tag composite-component. Aí tem um tutorial bacana ensinando a
criar um <a href="http://docs.oracle.com/javaee/6/tutorial/doc/giqzr.html">Composite
Component</a>. Se
você está usando JSF 2.x e ainda não fez algo do tipo, tire uma meia
horinha pra seguir o tutorial lá, vale muito a pena -- é a maneira mais
efetiva de reuso para as páginas JSF.</p>
<h2>8. <a href="http://stackoverflow.com/questions/6822000/when-to-use-uiinclude-tag-files-composite-components-and-or-custom-componen">Facelets templates, Facelets tags, Composite Components, Custom Components, aaargh! WTF are they about, anyway?</a></h2>
<p>Pois é, era de esperar que reuso em um framework baseado em componentes
fosse algo trivial, claro, tranquilo e sussa. <em>Hmmmm, not really</em>! Você
ainda precisa ficar ligado em muita coisa pra fazer as coisas
funcionarem do jeito que você quer.</p>
<p>Acho que a dica maior aqui é que os ids dos objetos dentro dos
componentes são únicos para a própria instância, isto é, cada vez que
você usar o componente numa página, os outros componentes dentro dele
terão identificador prefixado pelo id do componente que você criou. Isso
facilita na hora de fazer componentes AJAX reusáveis, porque o alvo das
alterações (o que você usa no render) sempre terá uma identificação
única para aquele componente.</p>
<h2>9. <a href="https://balusc.blogspot.com.br/2011/09/communication-in-jsf-20.html">Comunicação em JSF 2.0 -- como passar os dados que eu quero para onde eu preciso</a></h2>
<p>Bom... se você está usando JSF 2.x, provavelmente já chegou esse artigo
antes. Eu nem precisaria postar, porque é tão batata que todo mundo
usando JSF 2.x deve cair nele toda hora, mas como tenho a impressão que
meu eleitorado não gosta de textos grandes, é bom colocar na lista. Você
não vai ler agora mesmo, então sugiro favoritar a página e ir lendo aos
poucos durante a semana.</p>
<h2>10. <a href="http://stackoverflow.com/questions/3623911/what-are-the-main-disadvantages-of-java-server-faces-2-0">Por fim, uma breve história de JSF</a></h2>
<p>Apesar de reclamar um bocado sobre JSF, reconheço que ele está
melhorando, e nos últimos anos tem andado melhor do que antes. É bom
estar a par de como a coisa começou, os problemas foram aparecendo, como
eles foram sendo (lentamente) resolvidos, como outros apareceram no
processo, e como alguns ainda estão esperando solução. Toda tecnologia
acaba tendo um certo ciclo de vida, e é sempre bom saber o caminho que
está seguindo as ferramentas que você está investindo.</p>
<p>Eu, por exemplo, comecei a me afastar de JSF depois que <a href="http://www.infoq.com/news/2012/01/jsf-update-2.x">o Ed Burns
(lead developer de JSF) confirmou que JSF vai continuar sempre mantendo
a maior parte da lógica de UI no lado
servidor</a>. Realmente
faz sentido pra JSF se manter assim, afinal, sempre vai existir
desenvolvedores que não estão muito a fim de aprender coisas novas,
empresas que vão postergar upgrades por anos, enfim... Ainda vai ter
muita aplicação JSF pra ser mantida nos próximos 20 anos. Mas eu prefiro
investir numa tecnologia que me ajude a alavancar as demais tecnologias
da Web (especialmente as que eu preciso conhecer de qualquer forma, como
HTML/CSS/HTTP), e não uma em que as <a href="https://en.wikipedia.org/wiki/Leaky_abstraction" title="abstrações vazadas na Wikipedia em inglês">abstrações simplesmente vazam
demais</a> e
dificultam usar os outros blocos da construção. Para mim, JSF está
definitivamente no último grupo. So... <em>Goodbye, JSF!</em></p>
<p>[1] No Mojarra, a implementação de referência de JSF, o default é
armazenar a <em>view</em> por 15 requisições consecutivas; outras
implementações/configurações podem variar.</p>
<p>[2] A idéia de stateless views em JSF foi implementada pela primeira vez
por um consultor australiano, que pelo jeito <a href="http://www.industrieit.com/blog/2011/11/stateless-jsf-high-performance-zero-per-request-memory-overhead/">compartilha a mesma idéia
de que UI no servidor é
roubada</a>.</p>Aventurando-se com Grails2013-06-03T20:09:00+02:002013-06-03T20:09:00+02:00Elias Dornelestag:eliasdorneles.com,2013-06-03:/2013/06/03/aventurando-se-com-grails.html<p>Estou usando <a href="http://www.grails.org">Grails</a> ativamente há alguns meses
atrás. Comecei fazendo manutenção numa aplicação legada usando uma
versãozinha do Grails já bem gasta. Eventualmente, acabei migrando de
vez, usando Grails 2.x para praticamente todas as aplicações novas lá no
trampo. O bichinho é muito bom!</p>
<p>Quem caiu aqui para ler …</p><p>Estou usando <a href="http://www.grails.org">Grails</a> ativamente há alguns meses
atrás. Comecei fazendo manutenção numa aplicação legada usando uma
versãozinha do Grails já bem gasta. Eventualmente, acabei migrando de
vez, usando Grails 2.x para praticamente todas as aplicações novas lá no
trampo. O bichinho é muito bom!</p>
<p>Quem caiu aqui para ler uma simplificação grosseira, lá vai: Grails é
Rails pra <a href="http://groovy.codehaus.org">Groovy</a>, e
<a href="http://groovy.codehaus.org/">Groovy</a> é Ruby + Java. <a href="#f1">[1]</a></p>
<p>Groovy, pelo menos, inspira-se bastante em ambas as linguagens. De fato,
Groovy é um “Ruby” para os programadores Java que têm preguiça de
aprender outra linguagem. Qualquer programador fluente na linguagem Java
pode <a href="http://groovy.dzone.com/news/java-groovy-few-easy-steps">aprender o básico de Groovy em uma horinha de boa
vontade</a> e há
<a href="http://streetsaheadllc.com/article/ten-reasons-every-java-developer-should-learn-groovy--part-1-">vários</a>
<a href="http://streetsaheadllc.com/article/ten-reasons-every-java-developer-should-learn-groovy--part-2-">motivos</a>
muito bons para fazer isso.</p>
<p>Mas não vou ficar explicando aqui <a href="https://pt.wikipedia.org/wiki/Groovy">o que é
Groovy</a> e <a href="https://pt.wikipedia.org/wiki/Grails">o que é
Grails</a>, a Wikipedia tá aí pra
isso. Só quero anotar algumas coisas, mesmo -- também não é como se você
estivesse com as expectativas lá muito altas. :P</p>
<p>Como você talvez já se deu conta, as tais <a href="https://pt.wikipedia.org/wiki/Linguagem_de_dom%C3%ADnio_espec%C3%ADfico">linguagens de domínio
específico
(DSLs)</a>
representam hoje <a href="https://eljunior.wordpress.com/2012/12/03/fatos-e-falacias-da-engenharia-de-software-notas-do-livro/">nossa melhor chance de conseguir reuso em grande
escala</a>
-- isto é, reuso de soluções para problemas genéricos. Groovy, a
linguagem que empodera Grails, tem vários <a href="http://docs.codehaus.org/display/GROOVY/Writing+Domain-Specific+Languages">recursos justamente pra
facilitar a criação de
DSLs</a>.</p>
<p>E Grails é recheado dessas linguagenzinhas. <a href="#f2">[2]</a> Tem DSLs para as
configurações em diferentes ambientes, pra customizar o mapeamento de
tabelas no banco de dados, pra configurar recursos estáticos (arquivos
CSS, JS, etc), pra fazer consultas no banco de maneira mais legível, pra
declarar regras de validação, enfim, pra uma pancada de coisa. E tem uma
pancada de <a href="http://grails.org/plugins/">plugins extras</a> pra você usar
que adicionam ainda outras.</p>
<p>Isso é muito legal porque significa que você consegue fazer muito
escrevendo bem pouco. Compressão. Eu curto. :)</p>
<p>Bem, o caso é que eu tô curtindo muito ter <a href="http://grails.org/plugin/console">um REPL dentro da própria
aplicação</a>, que permite eu vasculhar
os objetos que estão escondidos lá no servidor de aplicação, executar
queries no mesmo banco que a aplicação tá usando, checar a configuração
da aplicação rodando e até mesmo esboçar um novo <em>feature</em>.</p>
<p>Além disso, várias coisas que você sofre pra configurar nas aplicações
Java Web comuns (gerenciamento de dependências, build automatizado fora
da IDE, maneira fácil de rodar os testes unitários e de integração,
gerenciamento dos recursos estáticos), com Grails você já ganha tudo
prontinho de graça, bem organizado e em geral, muito mais fácil de
manter.</p>
<p>Nem tudo são flores, todavia. Não curto muito o comportamento default do
<a href="http://www.grails.org/doc/latest/ref/Domain%20Classes/save.html">save()</a>,
essa parada de ele falhar silenciosamente quando a validação não passa.
Estou a par dos <a href="http://blog.springsource.com/2010/06/23/gorm-gotchas-part-1/">motivos que levaram os desenvolvedores do Grails a
fazer dessa
forma</a>,
mas isso é simplesmente contrário ao esperado -- <em>not the best UX, guys,
and you know it</em>. Já que não podíamos ter o parzinho <em>save</em> e <em>save!</em>
como no Rails, bem que o comportamento poderia ter sido invertido aqui
-- <em>save()</em> e <em>saveQuietly(),</em> talvez?</p>
<p>De qualquer forma, tarde demais. Ainda assim, agora é só a gente lembrar
de colocar <code>grails.gorm.failOnError=true</code> lá no <code>Config.groovy</code> sempre
que criar uma aplicação nova, e todo mundo fica feliz de novo. :)</p>
<p><a name="f1"></a><strong>[1]</strong> É, eu sei, Rails hoje em dia é um animal bem
diferente, mas o fato é que Grails tem muita semelhança com as primeiras
versões do Rails e ainda se inspira muito nele.</p>
<p><a name="f2"></a><strong>[2]</strong> Não, as sintaxes das DSLs não são um problema
-- todas elas são meio parecidas, justamente porque usam as mesmas
<a href="http://groovy.codehaus.org/Closures">construções básicas</a>. Você nem
precisa saber que são DSLs. ;-)</p>Desenvolvimento de software é um esporte de equipe2013-04-27T20:22:00+02:002013-04-27T20:22:00+02:00Elias Dornelestag:eliasdorneles.com,2013-04-27:/2013/04/27/desenvolvimento-de-software-e-um-esporte-de-equipe.html<p>Dãã, <em>grande notícia</em>, certo? Todo mundo sabe disso, não precisa nenhum
anúncio. Bem, pelo menos não era pra precisar. Todavia, pelo que converso com outros amigos
desenvolvedores e pela minha própria experiência mesmo, seria muito bom
se fôssemos lembrados disso mais vezes.</p>
<p>Há uns dias li o fantástico
livrito <a href="https://shop.oreilly.com/product/0636920018025.do"><em>Team …</em></a></p><p>Dãã, <em>grande notícia</em>, certo? Todo mundo sabe disso, não precisa nenhum
anúncio. Bem, pelo menos não era pra precisar. Todavia, pelo que converso com outros amigos
desenvolvedores e pela minha própria experiência mesmo, seria muito bom
se fôssemos lembrados disso mais vezes.</p>
<p>Há uns dias li o fantástico
livrito <a href="https://shop.oreilly.com/product/0636920018025.do"><em>Team Geek, a Software Developer’s Guide to Working Well with
Others</em></a> (ou <em>Equipe
Geek, um Guia do Desenvolvedor para Trabalhar Bem com Outros</em>). Deixa
ver, como descrever... Um exercício catártico! Um banho na alma! Todo
mundo envolvido em desenvolvimento de software deveria ler esse livro e
colocar nos seus <em>top 10</em>! E a capa é joinha:</p>
<p><center>
<a href="https://www.amazon.com/Team-Geek-Software-Developers-Working/dp/1449302440">
<img width="300" src="https://akamaicovers.oreilly.com/images/0636920018025/lrg.jpg" />
</a>
</center></p>
<p>Contrastando com
<a href="https://www.amazon.com/Peopleware-Productive-Projects-Teams-Second/dp/0932633439"><em>Peopleware</em></a>,
que está por aí (sendo ignorado) há já alguns anos e é mais voltado para
gerentes, <a href="https://www.amazon.com/Team-Geek-Software-Developers-Working/dp/1449302440"><em>Team
Geek</em></a>
é para os desenvolvedores/engenheiros de software aprenderem a trabalhar
com humanos -- e justamente por isso que é tão urgente.</p>
<p>Bem, andaram me reclamando do tamanho dos posts, por isso vou tentar pegar leve
dessa vez aqui, mas você terá que ler o livro -- até porque ele é curto (194
páginas) e barato (10 dólares a edição Kindle). Além disso, tenho receio de
tentar resumi-lo: além de deixar grande demais, eu esqueceria coisas
importantes e você acabaria não lendo o livro -- o que você deve. Serve também
como uma boa desculpa para a minha preguiça, é claro. Mas ei, eu tenho outros
livros pra ler, ok? Faz meses que estou em 30% do <em><a href="https://www.amazon.com/Agile-Principles-Patterns-Practices-C/dp/0131857258" title="link do livro na Amazon">Agile Principles, Patterns
and Practices in
C#</a></em> e tremo só de pensar em escrever sobre!</p>
<p>Enfim, hoje você terá que se contentar com minha tradução livre de algumas
quotes não muito selecionadas, e depois decidir se vai <a href="https://www.amazon.com/Team-Geek-Software-Developers-Working/dp/1449302440">ler o livro
sofregamente</a>
ou ver <a href="https://www.youtube.com/watch?v=q-7l8cnpI4k" title="Programming Well with Others -- Social Skills for Geeks">algum</a>
<a href="https://www.youtube.com/watch?v=0SARbwvhupQ" title="The Myth of the Genius Programmer">dos</a> <a href="https://www.youtube.com/watch?v=-F-3E8pyjFo" title="Open Source Projects and Poisonous People">vídeos</a> <a href="https://www.youtube.com/watch?v=OTCuYzAw31Y" title="The Art of Organizational Manipulation">da
dupla</a> <a href="http://www.red-bean.com/fitz/" title="Brian Fitzpatrick">Fitz</a> e <a href="http://www.red-bean.com/sussman/">Ben
Sussman</a> antes. </p>
<h3>Citações -- livre tradução:</h3>
<blockquote>
<p>O fator que vai fazer ou ferrar<code>*</code> sua carreira é quão bem você colabora com outras
pessoas.</p>
</blockquote>
<p><code>*</code> Tenho uma tradução alternativa um pouco mais colorida para esse verbo que
rima com o primeiro, mas que cai melhor numa conversa de bar... :D</p>
<hr>
<blockquote>
<p>Pessoas são inerentemente imperfeitas.
Mas antes de entender os bugs em seus colegas, você precisa entender
os bugs em você mesmo.</p>
</blockquote>
<hr>
<blockquote>
<p>O Mito do Programador Gênio* é só mais um aspecto da nossa insegurança. A
maioria dos programadores temem compartilhar um trabalho que recém começaram
porque isto significa que os colegas vão enxergar seus erros e saber que o
autor do código não é um gênio. [...] A reação natural a isso é se esconder
em uma caverna e trabalhar sozinho. [...] Se você está trabalhando sozinho,
você está aumentando o risco de falhar e reduzindo seu potencial de
crescimento.</p>
</blockquote>
<p>* No Youtube tem <a href="https://www.youtube.com/watch?v=CUF3y-H5jOs">um vídeo dos dois autores em busca do programador
gênio</a>, funny stuff.</p>
<hr>
<blockquote>
<p>Trabalhar sozinho é mais arriscado do que trabalhar com outros. Você pode
estar com medo que alguém roube sua idéia ou descubra que você não é um
gênio, mas você deveria estar com mais medo de gastar enormes quantidades de
tempo e energia trabalhando na coisa errada.</p>
</blockquote>
<hr>
<blockquote>
<p>Os três pilares que fundamentam toda interação e colaboração saudável são: </p>
<ul>
<li><strong>Humildade:</strong> você não é o centro do Universo, não é onisciente e nem
infalível. você está aberto a se melhorar:</li>
<li><strong>Respeito:</strong> Você se importa genuinamente com as pessoas com quem
trabalha, trata-os como seres humanos e aprecia suas habilidades e
realizações.</li>
<li><strong>Confiança:</strong> Você acredita que os outros são competentes e farão a coisa
certa, e está confortável em deixá-los pilotar quando apropriado. [..]
Quase todo conflito social pode ser rastreado a uma falta de humildade,
respeito ou confiança.</li>
</ul>
</blockquote>
<hr>
<p><center>
<a href="https://eljunior.files.wordpress.com/2013/04/i_don_know_what_do_you_think-balloon.png"><img alt="Às vezes, a melhor coisa a se fazer é apenas dizer: "Eu não sei."" src="https://eljunior.files.wordpress.com/2013/04/i_don_know_what_do_you_think-balloon.png"></a></p>
<h5>Às vezes, a melhor coisa a se fazer é apenas dizer: "Eu não sei."</h5>
<p></center></p>
<blockquote>
<p>Quanto mais você for aberto a influência, mais você conseguirá influenciar;
quanto mais vulnerável você for, mais forte você parece. [...] Lembre-se que
para ser ouvido adequadamente, você precisa primeiro ouvir os outros. [...]
Admitir que você errou engloba os três pilares: você demonstra <strong>humildade</strong>,
é um sinal que você <strong>confia</strong> na opinião dos outros, e as pessoas acabarão
por <strong>respeitar</strong> sua honestidade e integridade.</p>
</blockquote>
<hr>
<blockquote>
<p>Políticos profissionais são notórios por não admitir erro ou
ignorância, mesmo quando está patentemente óbvio que estão errados ou
não têm conhecimento sobre um assunto, e por causa disso as pessoas
não acreditam em nenhuma palavra do que eles dizem. Este comportamento
existe porque os políticos estão constantemente sob ataque dos
oponentes. Contudo, quando você está desenvolvendo software, é
desnecessário estar num estado constante de defesa -- seus colegas são
colaboradores, não competidores.</p>
</blockquote>
<hr>
<blockquote>
<p>Uma forte cultura de equipe está aberta a mudanças que a melhorem e
resistente a mudanças radicais que a prejudiquem.</p>
</blockquote>
<hr>
<blockquote>
<p>Se você é um gerente e está se sentindo inseguro por algum motivo, uma
maneira de fazer que ninguém questione sua autoridade ou ameace seu
emprego é contratar pessoas que você pode manipular mais facilmente.
[...] Em vez disso, você deve se esforçar para contratar pessoas que
são mais inteligentes que você e que possam substituí-lo.
</p>
</blockquote>
<hr>
<blockquote>
<p>Esperança não é uma estratégia. Todavia, esperança é muito usada como
estratégia ao lidar com um funcionário que não está rendendo bem.</p>
</blockquote>
<hr>
<blockquote>
<p>Falhar é uma opção. Se você não está falhando de vez em quando, é
sinal que não está sendo inovador nem tomando riscos o suficiente.</p>
</blockquote>
<p>So... that's it for today and thank you very much. :)</p>Coisas sobre o VIM que gostaria de ter sabido antes2013-04-07T15:41:00+02:002013-04-07T15:41:00+02:00Elias Dornelestag:eliasdorneles.com,2013-04-07:/2013/04/07/coisas-sobre-o-vim-que-gostaria-de-ter-sabido-antes.html<p>O <a href="http://www.vim.org">Vim</a> ainda é o meu editor predileto. Tentei substituí-lo
várias vezes, e as únicas alternativas que chegaram perto de ameaçá-lo foram
<a href="http://www.gnu.org/software/emacs/">Emacs</a> e <a href="http://www.sublimetext.com">Sublime
Text</a>: o primeiro pela quantidade de recursos, o
segundo pela interface joiada. Mas sempre que precisava resolver um problema
rapidão, acabava voltando pro <a href="http://arstechnica.com/information-technology/2011/11/two-decades-of-productivity-vims-20th-anniversary/" title="Texto sobre os 20 anos de Vim"><em>good ol' …</em></a></p><p>O <a href="http://www.vim.org">Vim</a> ainda é o meu editor predileto. Tentei substituí-lo
várias vezes, e as únicas alternativas que chegaram perto de ameaçá-lo foram
<a href="http://www.gnu.org/software/emacs/">Emacs</a> e <a href="http://www.sublimetext.com">Sublime
Text</a>: o primeiro pela quantidade de recursos, o
segundo pela interface joiada. Mas sempre que precisava resolver um problema
rapidão, acabava voltando pro <a href="http://arstechnica.com/information-technology/2011/11/two-decades-of-productivity-vims-20th-anniversary/" title="Texto sobre os 20 anos de Vim"><em>good ol'</em>
Vim</a>.</p>
<blockquote>
<p>Ah, só antes de continuar, uma palavrinha para os perdidos: <strong>Vim</strong> não é o
mesmo que <strong>vi</strong>, okay? Eu não suportaria usar o vi... :P</p>
</blockquote>
<p>Mesmo que sempre gostasse do Vim, por um bom tempo me senti envergonhado por
continuar usando ele, pensando que nunca me esforçei de verdade em sair da zona
de conforto e usar outra coisa. Mas hoje, considerando que uso regularmente as
full-blown IDEs nos projetos Java - além de ter brincado bastante com Emacs e
ST2 --, se eu continuo voltando para o Vim, talvez não seja tanto assim por
falta de esforço meu pra sair da zona de conforto. Talvez seja porque ele seja
uma ferramenta que se encaixe bem no meu modo de pensar -- o meu <em><a href="http://www.joelonsoftware.com/uibook/fog0000000249.html">user
model</a></em>. Talvez seja
porque ele é uma ferramenta <a href="https://en.wikipedia.org/wiki/Principle_of_good_enough">boa o
suficiente</a> pra mim.
Talvez, em vez de sentir vergonha de usar uma ferramenta com aparência
antiquada, eu deveria valorizá-lo mais e melhorar o meu próprio uso dele.</p>
<p>Preferir o Vim não faz de mim um programador menos capaz - a não ser que eu
deixe de refatorar um código só porque meu editor não oferece as mesmas
facilidades duma IDE. (ahn, não quero falar dos programadores que amam sua IDE
mas nunca usam os recursos de refatoração...) Toda escolha envolve <em>tradeoffs</em>,
e o Vim certamente tem suas desvantagens, mas é uma escolha muito válida e pode
ser mesmo muito divertida.</p>
<p>Enfim, por isso que resolvi finalmente comprar o livro <a href="http://pragprog.com/book/dnvim/practical-vim">Practical
Vim</a> do <a href="http://vimcasts.org">Drew
Neil</a>, que estou lendo (27%, me diz o Kindle) e curtindo
muito!</p>
<p>Acontece que o Vim, apesar de não ter uma boa usabilidade para usuários comuns,
é uma ferramenta muito boa pra programar ainda hoje. Quem não tem medo de
aprender novas linguagens e maneiras diferentes de fazer as coisas fica muito
bem com ele, obrigado. O foco do Vim não é usabilidade, mas eficiência. De
fato, é uma ferramenta ideal para <a href="http://www.vimgolf.com">nerds de
eficiência</a>.</p>
<p>Uma das primeiras coisas a sacar pra usar o Vim de maneira eficiente é que o
modo Normal não tem esse nome à toa: <a href="http://www.viemu.com/a-why-vi-vim.html">é o modo planejado pra você usar durante
a maior parte do tempo</a>. Se você tentar
maximizar o tempo no modo de inserção pra ter uma experiência mais parecida com
a dos outros editores, acabará perdendo as grandes vantagens do Vim -- como a
possibilidade de repetir ações, por exemplo.</p>
<p>Devo ter aprendido isso de alguma forma há um tempo atrás, e já estou até bem
confortável com esse estilo, mas tem algumas coisinhas que ainda me deixam pra
trás no Vim. O que segue são algumas pequenas dicas da minha redescoberta do
Vim dos últimos meses, que teriam feito minha vida um bocado mais fácil se
tivesse sabido delas antes.</p>
<p>1) É mais prático voltar para o modo Normal usando <code><Ctrl-C></code> em vez de <code><Esc></code>
-- especialmente se você mapeia a tecla <code><caps lock></code> para um <code><ctrl></code>
alternativo, como eu faço. Veja <a href="http://vim.wikia.com/wiki/Avoid_the_escape_key">outras maneiras de evitar o
<kbd>Esc</kbd></a>.</p>
<p>2) Se a meio caminho de uma seleção visual você se dá conta que começou do
lugar errado, você pode ir para o "outro lado" da seleção usando a tecla <code>o</code>
(caractere o minúsculo), modificar o começo da seleção conforme necessário. Use
<code>o</code> novamente pra voltar pro outro lado e continuar o que estava fazendo.</p>
<p>3) Acabou de fazer uma operação numa seleção visual e precisa fazer outra na
mesma seleção? Use <code>gv</code> pra reselecionar a última seleção, e mande ver.</p>
<p>4) No modo Normal, <code><ctrl-o></code> leva o cursor pra <a href="http://vim.wikia.com/wiki/Jumping_to_previously_visited_locations">última posição antes de um
pulo</a>.
<code><ctrl-i></code> faz o caminho inverso. Aprenda isso hoje e me conte depois como você
usou 35 vezes no mesmo dia.</p>
<p>5) Fazer scrolling com <code><ctrl-f></code>/<code><ctrl-b></code> (mesmo que
<code><pageup></code>/<code><pagedown></code>), <code><ctrl-u></code>/<code><ctrl-d></code> (up/down conforme a
configuração scroll) e <code><ctrl-y></code>/<code><ctrl-e></code> (sobe/desce uma linha) é mais
prático do que usar <code><pageup></code>/<code><pagedown></code>, setinhas e a rodinha do mouse.
Veja <a href="http://vim.wikia.com/wiki/All_the_right_moves">mais sobre movimentação no
Vim</a>.</p>
<p>6) Descobri que manter uma cópia impressa do <a href="http://www.viemu.com/a_vi_vim_graphical_cheat_sheet_tutorial.html"><em>cheatsheet</em>
gráfico</a> por
perto realmente ajuda a aprender mais coisas. Não tanto porque é fácil de
consultar, mas porque você acaba batendo o olho em alguma coisa útil quando
fica entediado. :)</p>
<p>Sobre plugins, existem muitos que valem a pena conferir (tenho pelo menos uns
vinte instalados), mas alguns se tornam essenciais bem rapidinho:</p>
<p>1) <a href="https://github.com/tpope/vim-pathogen">Pathogen</a> - ajuda a manter os
plugins atualizados e deixa muito fácil para experimentar plugins novos, só por
isso já vale muito a pena. Se ainda não conferiu o Pathogen, <a href="http://tammersaleh.com/posts/the-modern-vim-config-with-pathogen">comece por
aqui</a>.</p>
<p>2) <a href="http://kien.github.io/ctrlp.vim/">CtrlP</a> - ajuda a achar arquivos dentro do
diretório de um projeto. Se você usa Eclipse, pense <code><ctrl-shift-r></code>, só que
melhor, porque usa uma busca "fuzzy" por padrão.</p>
<p>3) <a href="https://github.com/tpope/vim-surround">Surround</a> - mão na roda na hora de
editar texto estruturado a la XML, HTML, etc. Veja um <a href="http://net.tutsplus.com/tutorials/other/vim-essential-plugin-surround/">tutorial do Surround com
vídeo</a>.</p>
<p>Por enquanto é isso! :)</p>Desenho de Interface do Usuário - para programadores2013-03-18T22:57:00+01:002013-03-18T22:57:00+01:00Elias Dornelestag:eliasdorneles.com,2013-03-18:/2013/03/18/desenho-de-interface-do-usuario---para-programadores.html<p><a href="http://www.joelonsoftware.com/">Joel Spolsky</a> é um cara batuta e muito
inteligente. Ele é uma das figuras por trás do
<a href="https://www.trello.com/">Trello</a> e do
<a href="http://stackoverflow.com/">StackOverflow</a> (e seus <a href="http://stackexchange.com/">sites
irmãos</a>), dois produtos show de bola que têm
sido parte da minha vida diária ultimamente. Ele também é bastante
conhecido pelos excelentes textos que escreveu no …</p><p><a href="http://www.joelonsoftware.com/">Joel Spolsky</a> é um cara batuta e muito
inteligente. Ele é uma das figuras por trás do
<a href="https://www.trello.com/">Trello</a> e do
<a href="http://stackoverflow.com/">StackOverflow</a> (e seus <a href="http://stackexchange.com/">sites
irmãos</a>), dois produtos show de bola que têm
sido parte da minha vida diária ultimamente. Ele também é bastante
conhecido pelos excelentes textos que escreveu no blog sobre vários
aspectos de desenvolvimento de software, cobrindo assuntos desde
gerenciamento de projetos, arquitetura e design de software, usabilidade
e também contratação de funcionários. Resumindo: HERÓI! Se você lê
inglês, ou quer aprender (e se você é programador, isso é altamente
recomendado), dê uma olhada por lá! Aqui, vou deixar fácil:
<a href="http://www.joelonsoftware.com/">http://www.JoelOnSoftware.com</a></p>
<p>Num fim de semana desses, gastei duas horinhas lendo <a href="http://www.joelonsoftware.com/uibook/fog0000000249.html">a versão online do
mini-livro dele voltado para programadores que trata desenho de
interfaces de
usuário</a> (tem
<a href="https://www.amazon.com/User-Interface-Design-Programmers-Spolsky/dp/1893115941">outra versão à venda na Amazon que parece ter mais
conteúdo</a>).
Tempo muito bem gasto, diga-se de passagem, porque o conteúdo é muito
bom! O Joel escreve bem pra caramba, a leitura é muito engajante e as
histórias que ele conta são bem divertidas.</p>
<p><strong>UPDATE:</strong> Recentemente, descobri que tem <a href="http://brazil.joelonsoftware.com/" title="Tradução dos posts do Joel">uma tradução dos posts do Joel Spolsky que fizeram o livro aqui</a>: <a href="http://brazil.joelonsoftware.com/">http://brazil.joelonsoftware.com</a>.</p>
<p>Ele comenta sobre o desgosto que alguns programadores têm de fazer
interfaces, provavelmente baseado no medo injustificado de ter que fazer
<a href="https://pt.wikipedia.org/wiki/Design_gr%C3%A1fico">design gráfico</a> (não,
não é a mesma coisa que <em>desenho de interface -- UI design</em>).
Programadores tendem a pensar sobre si mesmos como pessoas racionais,
com bom raciocínio mas fraco em arte. Todavia, Joel explica, desenho de
interface não é nenhuma arte misteriosa, e na verdade existem uma série
de regras e princípios que podem ser aplicados para melhorar a interface
dos programas para o usuário.</p>
<p>O caso é que a interface é importante porque afeta as emoções das
pessoas. Quando um usuário não consegue fazer o que ele queria com o
software, fica frustrado. Infeliz, mesmo! Mesmo que sejam algumas
pequenas frustraçõezinhas, elas tendem a se somar, principalmente num
software que é usado frequentemente. E o resultado é um grupo de
usuários bem infelizes, no fim do dia. E eles vão botar a culpa no seu
software!</p>
<p>Todavia, quando o usuário consegue fazer o que queria, o programa
funciona do jeito que ele esperava, o resultado é um usuário bem
animado. <em>Funcionou! Ripei um DVD! Que massa esse programa! \o/</em></p>
<p>Por isso, a primeira coisa importante a se ter em mente é:</p>
<h3>Uma interface é bem-feita quando o programa se comporta exatamente como o usuário esperava.</h3>
<p>Todas as regras e princípios restantes são corolários a esta.</p>
<p>Quando um usuário senta pra usar um programa, ele tem uma série de
expectativas sobre como ele acha que o programa vai funcionar. Se ele já
usou outros programas parecidos antes, vai achar que esse vai funcionar
mais ou menos como aquele outro. Essas expectativas que devemos tentar
descobrir, na hora de fazer uma interface pra o usuário. E você descobre
isso de um jeito muito científico, e muito simples: <strong>perguntando aos
usuários!</strong> Você não precisa <em>fazer</em> o que eles querem que você faça,
mas você deve pelo menos <em>ouvir</em> o que eles têm a dizer.</p>
<p>Em vez de ficar argumentando e discutindo qual o melhor jeito de tratar
determinado problema, simplesmente pergunte a alguns usuários o que eles
esperariam como solução. É claro que alguns podem não saber, não se
interessar ou simplesmente nunca ter pensado muito a respeito, mas se
você perguntar pra gente suficiente eventualmente vai começar a enxergar
uma espécie de consenso. E aí você já pode fazer um teste de usabilidade
usando um protótipo da interface e pedindo pra alguns usuários tentar
completar algumas tarefas, enquanto você observa.</p>
<p>Nessa hora você pode descobrir algumas coisas interessantes, tipo como
certos usuários tentam clicar em coisas que não são clicáveis, ou
procuram por uma certa opção num lugar diferente no menu. Talvez você
perceba que precisará melhorar o suporte a copiar e colar em alguns
campos, ou oferecer uma opção para desfazer certas ações, talvez
reescrever os rótulos de alguns botões, e outras coisas do tipo. O legal
é que você nem precisa fazer o teste com muitos usuários: mais de cinco
ou seis pessoas e os resultados já começarão a se repetir! Resumindo,
não requer nenhum investimento pesado em pesquisa.</p>
<p>Enfim, fazendo as coisas dessa maneira você consegue ter uma idéia
melhor do que é que os usuários esperam. Você pode descobrir que
melhorará a vida duma grande porcentagem dos usuários se construir sua
aplicação a respeito de tarefas dos usuários, em vez de uma série de
recursos genéricos não muito claros. Está no caminho para construir uma
interface que atenda essas expectativas.</p>
<p>Uma coisa que reforça esse assunto, é a questão da <a href="http://web.cs.wpi.edu/~matt/courses/cs563/talks/smartin/int_design.html">consistência
externa</a>,
isto é, a consistência com as outras ferramentas que o usuário está
acostumado (este assunto é também tratado <a href="https://eljunior.wordpress.com/2012/11/25/livro-effectiveui-minhas-notas/">no livro sobre experiência do
usuário que comentei há uns tempos
atrás</a>).
Quando as primeiras aplicações começaram a aparecer, todo mundo precisou
imaginar os próprios atalhos, menus e botões para determinadas coisas.
Ainda existe muito software daquela época que é assim até hoje, em que
mesmo o jeito de fechar o programa é bem diferente (<em>hello, Emacs... and
vim :</em>).</p>
<p>Hoje em dia, as aplicações Web tentam se aproximar bastante à
experiência oferecida pelas aplicações Desktop, porque corresponde
melhor às expectativas dos usuários. Estou escrevendo este texto no
Google Docs e sou grato ao Google por ter mantido no Docs a interface
familiar das outras suítes de Office -- menus
Arquivo/Editar/Formatar/etc, a barra de ferramentas, a maioria dos
atalhos para formatação também simplesmente funcionam. Imagina se eles
resolvessem: <em>“ei, nossa aplicação é Web, não tem nada a ver com o
Office tradicional, vamos então prover uma experiência totalmente nova!
Arquivos são coisas do passado, nós não temos arquivos, temos documentos
na nuvem, então esse item File no menu não faz sentido!”</em> Ainda bem que
não rolou nada disso, certo? (Certo, Google?)</p>
<p>Por isso, ao fazer a interface do seu programa, faça o favor de seguir
as convenções que os outros estão usando -- mesmo que elas tenham sido
estabelecidas por certas gigantes multinacionais pelas quais você não
tem muito carinho. Para construir interfaces usáveis deixe a ideologia
de lado, os usuários agradecem. Caso contrário, você corre o risco de
ser <a href="http://sivers.org/quirks">aquele hotel que resolveu fazer tudo diferente e deixou impossível
pra um recém-chegado descobrir como acender as luzes do quarto ou abrir
a torneira</a>.</p>
<p>A segunda grande regra de desenho de interface do Joel é:</p>
<h3>Cada vez que você apresenta uma opção, você está pedindo ao usuário para tomar uma decisão.</h3>
<p>O que não é necessariamente uma coisa ruim, é claro. Todo mundo gosta de
poder escolher certas coisas, é por isso que Subway, Spoletto e outros
restaurantes do tipo fazem sucesso. Todavia, ninguém gosta de escolher
coisas que <em>simplesmente não interessam</em>.</p>
<p><a href="https://eljunior.files.wordpress.com/2013/03/clippy-letter20110724-22047-qcxdai.png"><img alt="Lembra desse cara chato?" src="https://eljunior.files.wordpress.com/2013/03/clippy-letter20110724-22047-qcxdai.png"></a>
Lembra desse cara chato?</p>
<p>E a verdade é que a maioria dos usuários não se importam com tanta coisa
quanto você pode achar. Joel dá um exemplo do que não fazer, citando o
caso da ajuda do Windows, que em vez de mostrar a ajuda, abria um wizard
perguntando como você queria configurar o índice da ajuda... É igual
como quando você está tentando trabalhar em alguma coisa e alguém fica
interrompendo, exigindo sua atenção para um assunto inútil.</p>
<p>Outro exemplo de problema do tipo foi a possibilidade de configurar a
posição das barras de ferramentas... Você pode configurar tanto, que
pode inclusive extrair a barra pra uma janela separada (e depois lutar
bastante pra colocá-la de volta no lugar original). Aí você tem uma
coisa que ninguém quer, mas que acaba atrapalhando para todo mundo.</p>
<p>Resumindo: <em>pense muito bem antes de forçar o usuário decidir sobre uma
coisa</em>. Em geral, você deve tentar minimizar a quantidade de decisões,
deixando apenas o que realmente importa.</p>
<h2>Como criar interfaces para pessoas que têm mais o que fazer na vida</h2>
<p>Quando você desenha interfaces para o usuário, diz Joel, é uma boa idéia
manter dois princípios em mente:</p>
<ol>
<li><strong>Usuários não lêem o manual</strong></li>
<li><strong>Na verdade, usuários não lêem nada</strong></li>
</ol>
<p>Usuários não lêem o manual por diversos motivos. Às vezes, eles nem
<em>têm</em> o manual, mas não iam querer ler mesmo se tivessem. Em geral, seus
usuários estão tentando <em>fazer</em> alguma coisa. Para eles, ler o manual é
interromper a tarefa que estão fazendo, é mais perda de tempo (e tendo
em vista como tantos manuais são escritos mal, frequentemente eles estão
corretos em assumir isso).</p>
<p>E de fato, usuários não lêem nada! Isso pode soar meio bizarro, mas a
verdade é que existem muitas pessoas que simplesmente não lêem as
palavras que estão escritas na tela. Isso é muito azarado para o
programador, que geralmente gosta de imaginar tendo uma espécie de
diálogo com o usuário. Mas se você já parou para observar as outras
pessoas usando o computador, provavelmente já percebeu que algumas nunca
lêem o que aparece num diálogo e automaticamente clicam em <em>Ok</em> ou
<em>Cancelar</em> -- dependendo do nível de confiança de cada uma.</p>
<p>Eu conheço de perto um programador que se comporta exatamente dessa
forma. O bicho simplesmente não lê as mensagens que aparecem na tela,
mesmo quando vai usar um programa que não está acostumado, é incrível!
Incidentalmente, ele vive reclamando que os usuários dos programas dele
não lêem as mensagens na tela...</p>
<p>Mas é assim mesmo. Os usuários avançados usualmente pulam as instruções.
Iniciantes não gostam mesmo de ler muito. E os poucos usuários que realmente
tentam ler as instruções, muitas vezes acabam ficando ainda mais confusos
depois de lê-las! Por isso, os textos que você põe na tela devem ser polidos
para minimização. Substitua explicações por ações auto-explicativas. Dá mais
trabalho fazer assim porque você precisa pensar mais para conseguir reduzir os
textos, mas vale a pena. <strong>Menos é realmente mais.</strong></p>
<p>Ok. Joel fala de várias outras coisas também, mas este texto está ficando
grande demais, e você é um herói legendário tendo lido até aqui de qualquer
forma, então, prometo que já-já vou terminar.</p>
<p>Outra coisa que usuários também não são muito bons em fazer é controlar o
mouse. Pois é, eles não controlam o mouse muito bem. Meus pais mesmo tiveram
uma certa dificuldade de aprender o duplo clique. Certas tarefas são
particularmente complicadas de fazer com o mouse. E às vezes, mesmo se o
usuário sabe usar o mouse, ele não funciona muito bem. Eu mesmo cansei de
xingar aplicações com barras de rolagem muito chatas, em que algumas tarefas
simples viram um exercício de autocontrole pra não socar o monitor. E até hoje
ainda tenho alguns medinhos sobre clicar e arrastar...</p>
<p>Outra coisa a lembrar: Usuários não conseguem lembrar muita coisa.
Praticamente, nadica! E é por isso que menus são melhores interfaces que linhas
de comando crípticas. Por isso que escolher um arquivo de imagem selecionando
uma miniatura da imagem é melhor do que procurar o nome do arquivo numa lista.
E por isso que, mesmo quem jura que a linha de comando é uma interface melhor,
não larga do autocompletar. :)</p>
<p>E ei, eu sou um que vivo na linha de comando, uso na grande maioria das minhas
tarefas no PC. Mas não tem como negar que o Windows Explorer apresentando as
pastas em árvore é uma metáfora <em>beeem</em> melhor para o sistema de arquivos. Eu
na linha de comando é só eu na minha zona de conforto. Eu devia tentar usar
mais a interface gráfica, mas...</p>
<p>Ok, agora sim, estou finalizando! O que segue é provavelmente o ponto mais
importante de todo esse texto.</p>
<p>Alguém lendo este texto, pode achar que um princípio geral a ser seguido é:
<em>“pense que seus usuários são muito burros”</em>, e talvez achar que essa seja uma
atitude arrogante. Não muito, eu diria... <em>Uma arrogância muito pior é achar
que o seu software é tão bom e bem-feito que as outras pessoas simplesmente
devem se virar pra aprender a usá-lo</em>.</p>
<p><a href="https://eljunior.files.wordpress.com/2013/03/ui-usuarios-final.png"><img alt="UI-usuarios-final" src="https://eljunior.files.wordpress.com/2013/03/ui-usuarios-final.png"></a></p>
<p>Pense comigo. A grande maioria das pessoas sabe operar uma televisão.
Uma boa porção dessas pessoas deve ser capaz de usar o PC, navegar na
Internet e olhar email, criar tabela no Excel. Uma porção pequena dessas
pessoas deve saber usar Linux, talvez usar um pouco a linha de comando,
e usar o último <em>tablet</em> da moda. Pouquíssimas dessas pessoas saberão
programar. E das que sabem, muito poucas saberão programar em C++. (<em>Cá
entre nós, quase nenhuma mesmo, mas vai ter muitas que acham que sabem!
:D</em>)</p>
<p>O que podemos concluir disso é que <em>quando você melhora a interface do
seu programa, mesmo que em pequena quantidade, você aumenta
dramaticamente o número de pessoas que pode usá-lo</em> com facilidade.
Melhore a interface para o <em>noob</em> que mal e mal sabe usar a TV, e a
interface vai melhorar pra todo mundo -- inclusive para os hackers
barbudinhos! Tipo, melhore a interface em 10%, e ganhe 50% mais
usuários. Por isso também, que fazer pequenas melhoras numa aplicação
ruim que é usada largamente, pode valer muito mais a pena do que criar
uma aplicação nova toda perfeitinha, que talvez não tenha tanto público.</p>
<p>Então, não é que os seus usuários sejam tolos, mas sim que se você
seguir tentando fazer seu sistema à prova de tolos, você chegará num
programa fácil de usar pra todo mundo. De fato, se fazer de tolo é uma
boa maneira de avaliar a usabilidade de um programa ou tela. Não ler o
que tá escrito na tela, sair clicando onde acha que deve ser, usar o
mouse com um dedo só. Se a interface não aguenta você sendo imaturo e
impaciente, provavelmente ela pode ser melhorada um bocado.</p>
<p>Finalmente, o último conselho é: <strong>faça seu programa girar em torno de
atividades do usuário</strong>. Se você vai fazer um produto, não saia
simplesmente criando os recursos que acha que será necessário. Imagine
alguns usuários (Pedro, pai de família, usa o PC para ver vídeos no
YouTube e trocar emails com os amigos. Luana, filha adolescente de
Pedro, passa as tardes no Facebook e baixa MP3 via BitTorrent). Isso
deve ajudar a despertar empatia por eles. Então você pode imaginar
algumas <em>coisas</em> que esses usuários queiram <em>fazer</em> com seu programa. E
o passo seguinte é ter certeza de deixar bem óbvio como essas coisas
podem ser feitas, na interface do seu programa.</p>
<p>Dessa maneira você evita uma aplicação que os usuários tenham que ler o
manual (que ele não tem, lembra?) pra ver o que pode fazer com ela. De
cara, ele já pode descobrir como fazer o que precisa. <em>Ripar um CD</em>.
Enviar um cartão de Feliz Aniversário. <em>Criar álbum de fotos</em>. Imprimir
o artigo inteiro. <em>Achar uma imagem para ilustrar o texto</em>. Revisar os
últimos comentários postados.</p>
<p>Uma interface desenhada em torno de atividades sempre vai detonar uma
desenhada em cima de quantidade de recursos, tranquilamente e de mãos
atadas!</p>
<p>Era isso, chega por hoje! :)</p>Por que as estimativas em desenvolvimento de software normalmente estão erradas por um fator de 2-3?2013-02-26T06:34:00+01:002013-02-26T06:34:00+01:00Elias Dornelestag:eliasdorneles.com,2013-02-26:/2013/02/26/por-que-as-estimativas-em-desenvolvimento-de-software-normalmente-estao-erradas-por-um-fator-de-2-3.html<blockquote>
<p>Aviso 1: Esta é uma tradução livre de uma das melhores histórias sobre
estimativas de software já escritas. O original em inglês é uma
<a href="http://www.quora.com/Engineering-Management/Why-are-software-development-task-estimations-regularly-off-by-a-factor-of-2-3">resposta no Quora à pergunta do
título</a>,
e essa tradução foi realizada com o consentimento do autor <a href="http://about.me/michaelrwolfe" title="Michael Wolfe">Michael
Wolfe</a>. Caso a língua
não seja problema, recomendamos …</p></blockquote><blockquote>
<p>Aviso 1: Esta é uma tradução livre de uma das melhores histórias sobre
estimativas de software já escritas. O original em inglês é uma
<a href="http://www.quora.com/Engineering-Management/Why-are-software-development-task-estimations-regularly-off-by-a-factor-of-2-3">resposta no Quora à pergunta do
título</a>,
e essa tradução foi realizada com o consentimento do autor <a href="http://about.me/michaelrwolfe" title="Michael Wolfe">Michael
Wolfe</a>. Caso a língua
não seja problema, recomendamos fortemente a leitura do texto
original... simplesmente melhor e mais engraçado.</p>
<p>Aviso 2: Este post é resultado duma colaboração minha com o senhor
Crineu Tres. Isto é, ele fez tudo e eu só traduzi os palavrões.</p>
</blockquote>
<p>Vamos dar uma caminhada saindo da costa de San Francisco até Los Angeles
para visitar nossos amigos em Newport Beach. Pego meu mapa e desenho
nossa rota pela costa:</p>
<p><img alt="1" src="https://eljunior.files.wordpress.com/2013/02/1.png"><br>
O percurso é de aproximadamente 400 milhas; podemos caminhar 4 milhas
por hora, 10 horas por dia. Dessa forma chegaremos lá em 10 dias.
Ligamos para nossos amigos e marcamos uma janta para o próximo domingo
às 18h, quando chegaremos de forma triunfante! Eles mal podem esperar!</p>
<p>Acordamos cedo no dia seguinte altamente motivados para essa nova
aventura. Colocamos as mochilas, pegamos o mapa e a rota para o primeiro
dia. Olhamos então para o mapa. Ai ai:</p>
<p><a href="https://eljunior.files.wordpress.com/2013/02/2.png"><img alt="2" src="https://eljunior.files.wordpress.com/2013/02/2.png"></a><br>
Caramba, a costa tem um milhão de curvas e reentrâncias! Com apenas um
dia de caminhada de 40 milhas não chegaremos nem em Half Moon Bay. Essa
viagem tem pelo menos 500 milhas, e não 400! Ligamos para nossos amigos
e atrasamos o jantar para a terça-feira. É melhor sermos realistas. Eles
ficam meio desapontados, mas não vêem a hora de chegarmos. Além disso,
12 dias de San Francisco até Los Angeles não é um tempo ruim.</p>
<p>Bem, com essa inconveniência resolvida, partimos. Duas horas mais tarde,
não passamos nem do zoológico. Qual o problema? Olhamos novamente para
nossa trilha:</p>
<p><a href="https://eljunior.files.wordpress.com/2013/02/3.jpg"><img alt="3" src="https://eljunior.files.wordpress.com/2013/02/3.jpg"></a></p>
<p>Jesus, essa trilha não é fácil! Areia, água, escadas, riachos, lobos
marinhos furiosos! Estamos caminhando a no máximo 2 milhas por hora,
metade da velocidade pretendida... podemos então começar a caminhar 20
horas por dia ou ligar para nossos amigos e atrasar a janta mais uma
semana. Ok, vamos dividir o fardo: caminharemos 12 horas por dia e
atrasaremos a janta até o final de semana seguinte. Ligamos para nossos
amigos e remarcamos o jantar até o domingo seguinte. Eles ficam um pouco
irritados, mas confirmam o evento mesmo assim.</p>
<p>Montamos acampamento em Moss Beach após um dia duro de doze horas
caminhando. Cacilda, como é difícil montar barracas nesse vento! Não
conseguimos dormir antes da meia noite. Nada demais: iremos apertar o
passo amanhã.</p>
<p>Dormimos demais e acordamos doídos e cansados às.. 10 da manhã. Caralho!
Sem condições de fazer 12 horas hoje! Vamos caminhar 10 e compensaremos
com 14 amanhã. Juntamos os equipamentos e partimos.</p>
<p>Após um esforço redobrado nas primeiras horas, percebo nosso colega
mancando. Maravilha, bolhas nos pés... precisamos resolver isso agora.
Somos do tipo de grupo que resolve os problema individuais antes que
comecem a nos atrasar. Eu corro por 45 minutos, 3 milhas para longe da
costa até Pescadero, pego alguns band-aids e corro de volta para medicar
meu colega. Chego exausto e o sol está se pondo, então declaramos o dia
encerrado. Vamos dormir após fazer míseras 6 milhas. Mas temos
suprimentos novos. Ficaremos bem. Compensaremos amanhã.</p>
<p>Acordamos na manhã seguinte, protegemos nossos pés de futuras bolhas e
começamos a caminhar. Contornamos a encosta. Que?! Que porra é essa?</p>
<p><a href="https://eljunior.files.wordpress.com/2013/02/4.jpg"><img alt="4" src="https://eljunior.files.wordpress.com/2013/02/4.jpg"></a></p>
<p>O maldito mapa não mostra essa merda! Temos que caminhar 3 milhas para o
interior, contornar uma propriedade federal rodeada por cercas, nos
perder duas vezes, e somente então voltar à costa em torno do meio-dia.
A maior parte do dia foi gasta para realizar 1 milha de progresso. Ok,
<strong>não</strong> ligaremos para nossos amigos para atrasar mais uma vez a janta.
Caminharemos até meia-noite para voltar ao planejamento inicial.</p>
<p>Após uma terrível noite de sono sob a névoa, meu amigo acorda com uma
dor de cabeça infernal e febre. Pergunto se ele consegue continuar e ele
responde: <em>"O que você acha, panaca? Estou caminhando nessa névoa gelada
por 3 dias sem descanso!"</em>. Beleza... o dia de hoje está perdido. Vamos
descansar e nos recuperar. A partir de amanhã faremos 14 horas por dia,
já que estaremos descansados e preparados para tudo... são apenas mais
alguns dias, então obviamente podemos cumprir o prazo!</p>
<p>Acordamos moídos no dia seguinte. Olho o mapa:</p>
<p><img alt="5" src="https://eljunior.files.wordpress.com/2013/02/5.png"></p>
<p>Puta merda! Estamos no dia 5 de uma viagem de 10 dias e não saímos nem
da Bay Area! Isso é patético! Vamos trabalhar em uma estimativa mais
precisa e ligar para nossos amigos. Provavelmente seremos repreendidos,
mas teremos uma data realista pelo menos.</p>
<p>Meu amigo diz: <em>"Bem, fizemos 40 milhas em 4 dias, e é uma viagem de
pelo menos 600 milhas, então são 60 dias, provavelmente 70 considerando
uma margem para imprevistos"</em>. Eu respondo <em>"Nem fu...... Ok, eu posso
nunca ter feito essa caminhada antes, mas eu </em><em>sei</em><em> que não demora 70
dias para caminhar de São Francisco até Los Angeles. Nossos amigos irão
rir de nós se ligarmos avisando que só chegaremos na Páscoa!"</em></p>
<p>E continuo: <em>"Se vocês se comprometerem a caminhar 16 horas por dia,
podemos compensar o tempo perdido! Sei que será difícil, mas essa é a
reta final!"</em>. Meu colega grita de volta: <em>"Pra começo de conversa, não
fui eu que liguei dizendo que estaríamos lá no Domingo, tá? Você está
acabando com a gente por um erro seu!"</em></p>
<p>Um silêncio tenso recai sobre o grupo. A ligação não é realizada.
Ligarei amanhã, quando meu camarada voltar às suas faculdades mentais e
concordar em algo razoável.</p>
<p>Na manhã seguinte aguardamos em nossas barracas até o temporal passar.
Levantamos acampamento e saímos às 10h, esticando músculos doídos e
novas bolhas nos pés. Não comentamos nada sobre a briga do dia anterior,
embora eu tenha xingado um certo colega idiota que esqueceu a garrafa de
água e fez a gente gastar 30 minutos para buscá-la.</p>
<p>Faço uma nota mental lembrando que estamos sem papel higiênico e
precisamos parar na cidade mais próxima. Contornamos a enseada: um rio
está bloqueando nosso caminho. Sinto uma forte dor-de-barriga e a
sensação de diarréia iminente...</p>Aventuras apresentando Java EE a mim mesmo2013-01-15T07:45:00+01:002013-01-15T07:45:00+01:00Elias Dornelestag:eliasdorneles.com,2013-01-15:/2013/01/15/aventuras-apresentando-java-ee-a-mim-mesmo.html<blockquote>
<p><strong>Cuidado:</strong> o texto a seguir contém níveis perigosos de nerdice,
acrônimos e javeiragem em geral.</p>
</blockquote>
<p>Não sou nenhum fã de Java: a linguagem eu realmente <strong>não</strong> curto (não
tenho culpa de ter conhecido
<a href="http://www.python.org/" title="Python.org">Python</a> e
<a href="http://www.ruby-lang.org/" title="Ruby-Lang.org">Ruby</a> antes :P), todavia a
plataforma tem os seus apelos. Só que eu estava ficando …</p><blockquote>
<p><strong>Cuidado:</strong> o texto a seguir contém níveis perigosos de nerdice,
acrônimos e javeiragem em geral.</p>
</blockquote>
<p>Não sou nenhum fã de Java: a linguagem eu realmente <strong>não</strong> curto (não
tenho culpa de ter conhecido
<a href="http://www.python.org/" title="Python.org">Python</a> e
<a href="http://www.ruby-lang.org/" title="Ruby-Lang.org">Ruby</a> antes :P), todavia a
plataforma tem os seus apelos. Só que eu estava ficando com vergonha de
ainda desconhecer o <em>stack</em> do <a href="https://en.wikipedia.org/wiki/Java_EE">Java
EE</a>, ao passo que uso diariamente
várias tecnologias relacionadas no meu trabalho. Por isso, decidi que
iria tomar vergonha na cara e estudar um pouco mais da parada (e tentar
reclamar menos). Comprei <a href="http://antoniogoncalves.org/2009/02/13/java-ee-6-book/">o
livro</a> do
<a href="http://antoniogoncalves.org/">Antonio Goncalves</a> sobre <a href="https://en.wikipedia.org/wiki/Java_EE">Java
EE</a> 6, e caí em cima. Tendo
recentemente terminado sua leitura, registro aqui minhas impressões a
respeito.</p>
<hr>
<p><a href="https://www.amazon.com/Beginning-Java-Platform-GlassFish-Professional/dp/1430219548"><img alt="Read the original, dude!" src="https://eljunior.files.wordpress.com/2013/01/intro-javaee.png?w=300"></a>
Read the original, dude!</p>
<hr>
<p>Antes de começar, porém, já adianto uma coisa: apesar do conteúdo do
livro ser bem decente, a tradução dele é <strong>péssima</strong>. Me encontrei
frequentemente tendo que adivinhar como seria o texto original em inglês
para poder compreender o traduzido, pois este não fazia nenhum sentido.
A impressão é que o livro foi traduzido por várias pessoas diferentes
(estagiários?), que não sabem muito sobre orientação a objetos e muito
menos da plataforma Java EE, resultando numa confusão de palavreado
mal-traduzido bem difícil de entender. Resumindo: a tradução atrapalha
muito mais do que ajuda! Se soubesse que seria tão desleixada, jamais
teria comprado o livro traduzido. Portanto, se você já lê inglês,
obtenha <a href="https://www.amazon.com/Beginning-Java-Platform-GlassFish-Professional/dp/1430219548">a versão
original</a>
(mesmo que saia mais caro): você vai poupar sofrimento e a leitura será
mais tranquila. Se você não lê inglês, leia <a href="https://www.amazon.com/Beginning-Java-Platform-GlassFish-Professional/dp/1430219548" title="Beginning Java EE 6 Platform with Glassfish 3">a versão
original</a>
também e aproveite pra começar a aprender inglês logo: será mais
saudável pra sua carreira não depender de traduções fajutas! OK, fim da
reclamação.</p>
<p>O livro fornece uma visão geral da plataforma, e também tenta mostrar o
contexto histórico e motivações para o surgimento dos protocolos e APIs.
Após apresentar rapidamente o que consiste a plataforma e os programas
necessários para rodar os exemplos
(<a href="https://en.wikipedia.org/wiki/Java_Development_Kit">JDK</a>,
<a href="https://maven.apache.org/">Maven</a>, <a href="http://glassfish.java.net/">Glassfish
3</a>, <a href="https://en.wikipedia.org/wiki/JUnit">Junit
4</a> and
<a href="http://db.apache.org/derby">Derby</a>), o livro começa a apresentar as
APIs e conceitos da plataforma numa abordagem meio <em>bottom-up</em>: alguns
capítulos sobre mapeamento objeto-relacional com
<a href="https://en.wikipedia.org/wiki/Java_Persistence_API">JPA</a> -- a API
especificada para persistência com Java, depois alguns capítulos sobre
as partes de Java EE usadas principalmente para a lógica de negócio
(<a href="https://en.wikipedia.org/wiki/Enterprise_JavaBeans">EJBs</a>, Transações,
<a href="https://en.wikipedia.org/wiki/Aspect-oriented_programming">AOP</a> no
estilo Java EE com <em>Callbacks</em> e <em>Interceptors</em>), seguidos de uma visão
rápida das tecnologias usadas para a parte de apresentação na Web
(<a href="https://en.wikipedia.org/wiki/JavaServer_Faces">JSF</a>,
<a href="https://en.wikipedia.org/wiki/JavaServer_Pages">JSP</a>, e assuntos
relacionados), e culmina com os últimos 3 capítulos dedicados a
comunicação entre sistemas: mensageria com
<a href="https://en.wikipedia.org/wiki/Java_Message_Service">JMS</a>, <a href="https://en.wikipedia.org/wiki/Java_API_for_XML_Web_Services">Web Services
SOAP</a> e
<a href="https://en.wikipedia.org/wiki/Java_API_for_RESTful_Web_Services">RESTful</a>.</p>
<p>O conteúdo é bom pra <em>“designorantar-se”</em> dos conceitos e tecnologias
disponíveis na plataforma, acho que dá pra recomendar pra qualquer
pessoa envolvida com Java e ainda não conferiu o Java EE, ou que vem de
outras linguagens/frameworks e quer conhecer o padrão. Todavia, pelo que
tenho lido no StackOverflow e em alguns outros lugares, a API
especificada de Java EE sobre <a href="http://docs.oracle.com/javaee/6/tutorial/doc/gjbnr.html">Contextos e Injeção de
Dependência</a>
(CDI, na sigla em inglês) vem ganhando cada vez mais importância na
plataforma, então é um certo pecado o livro simplesmente ignorá-la -- em
nenhum lugar do texto é sinalizado a omissão de uma parte importante da
coisa.</p>
<p>Gostei bastante da cobertura de JPA, relativamente bem completa para um
livro de introdução à plataforma. Rapidamente encontrei material pra uso
no meu trabalho. A seção sobre EJBs pra mim foi interessante para
comparar com a minha experiência com os recursos substitutos do
<a href="https://en.wikipedia.org/wiki/Spring_Framework">Spring</a>. (Parece que os
meus <a href="https://en.wikipedia.org/wiki/Session_Beans#Stateless_Session_Beans">SLSBs</a>
são beans do Spring com
<a href="http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/transaction/annotation/Transactional.html">@Transactional</a>.
:) As partes exclusivamente sobre JSF não me reservaram muitas
surpresas, mas curti aprender mais sobre o contexto histórico do
framework, com a seção descrevendo o surgimento de
<a href="https://en.wikipedia.org/wiki/JavaServer_Pages">JSP</a>,
<a href="https://en.wikipedia.org/wiki/JavaServer_Pages_Standard_Tag_Library">JSTL</a>,
<a href="https://en.wikipedia.org/wiki/Facelets">Facelets</a>,
<a href="https://en.wikipedia.org/wiki/Unified_Expression_Language">EL</a>, etc.
Achei muito boa também a exposição sobre a API Javascript que ganhou
especificação no JSF 2, usada para as requisições Ajax.</p>
<p>Por fim, os 3 últimos capítulos sobre interoperabilidade também estão
interessantes, embora eu me arrastei na leitura deles. Sobre JMS, não
tinha muita novidade (a API andou meio parada por algum tempo, e deverá
ter novidades no <a href="http://jcp.org/en/jsr/detail?id=342">Java EE 7</a> com o
<a href="http://jcp.org/en/jsr/detail?id=343">JMS 2</a>). Fato curioso: o capítulo
sobre serviços REST conseguiu ser mais enfadonho do que o de serviços
SOAP (e olha que eu tendo a favorecer REST). Começou entrando demais nos
conceitos dos protocolos antes de mostrar um exemplo prático que
demonstrasse as vantagens da coisa -- o que provavelmente teria criado
um engajamento melhor com a exposição da API. Mas bem, o estilo REST é
relativamente novo no mundo Java, talvez à medida que mais gente compre
a idéia, ele deve receber mais atenção no futuro.</p>
<p>Os exemplos do livro servem apenas como um chute inicial mesmo, é só pra
você ter uma idéia mesmo do que é possível de atingir com as APIs que
estão sendo explicadas. Quase nada dos códigos de exemplo parecem
aproveitáveis para uma aplicação real -- muito longe de código de
produção. Nesse sentido, o livro provavelmente não está longe da vasta
maioria das documentações técnicas para programadores, infelizmente.</p>
<p>Apesar de tudo, ler esse livro foi muito bom pra mim, pois expandiu um
bocado minha compreensão sobre algumas tecnologias que trabalho e sobre
as possibilidades da tal plataforma Java EE. E como uso bastante JPA e
JSF no meu trabalho atual, fiquei por dentro de vários recursos úteis
dessas APIs que eu desconhecia. Por exemplo, apesar de usar JPA há já
uns 2 anos, eu desconhecia os mecanismos de mapeamento com
<a href="http://docs.oracle.com/javaee/6/api/javax/persistence/ElementCollection.html">@ElementCollection</a>
e
<a href="http://docs.oracle.com/javaee/6/api/javax/persistence/Embeddable.html">@Embeddable</a>.
Também, mesmo usando JSF há um bom tempo, desconhecia o
<a href="http://docs.oracle.com/javaee/6/javaserverfaces/2.0/docs/pdldocs/facelets/composite/insertChildren.html">composite:insertChildren</a>
(meus olhos devem ter pulado essa tag na listagem da documentação mais
de uma vez). Essas e outras coisas encontraram uso bem rapidinho no
código da aplicação que estou trabalhando. Meio besta eu não saber disso
antes, né? Mas bem, isso é pra ser um dos benefícios esperados ao se
sentar pra ler uma josca dessas até o final. :)</p>
<p>No final, fiquei com uma sensação um pouco mais positiva em relação ao
Java EE (ou devo dizer, menos negativa?). Enfim, parece que do seu
próprio modo a plataforma está evoluindo, e as APIs estão ficando bem
decentes. E <a href="http://jcp.org/en/jsr/detail?id=342">a próxima versão Java EE
7</a> parece que sairá em breve (<a href="http://jdevelopment.nl/open-source/java-ee-7-progress-page/">essa
página</a>
tenta registrar o progresso), com mais melhorias em todas as áreas.
Contudo, às vezes tenho a impressão que o meu sentimento positivo é mais
devido ao péssimo estado anterior das APIs do que aos recursos
verdadeiros das versões atuais.</p>
<p>Pessoalmente, das tecnologias para aplicações Web do “mundo Java”, tendo
a gostar mais de coisas como o <a href="http://grails.org/">Grails</a>, que oferece
várias facilidades semelhantes aos da plataforma Java EE, mas com
usabilidade bem melhorada para mim como programador. Sei que não é muito
justo comparar, já que Java EE é um conjunto de especificações (tem
muita gente que valoriza isso), mas em termos de recursos disponíveis
para um programador construir um app, pode fazer bastante sentido
compará-los.</p>
<p>Finalmente, tem algumas coisas que me importam bastante num <em>toolkit</em>, e
que Java EE ainda precisa melhorar:</p>
<ul>
<li>Facilidade de fazer bootstrap duma aplicação Web (IDEs e o Maven
ajudam, mas ainda estão longe de <em>grails create-app NOME_DO_APP</em>)</li>
<li>Facilidade de instalar/publicar uma aplicação -- em especial,
minimizando a quantidade de configuração a ser feita para os
recursos que ela vai usar.<ul>
<li>Envolve colocar o máximo de configuração possível embutido na
aplicação. Isso meio que bate de frente com a idéia prevalente
do Java EE de que as configurações devem ser feitas no servidor
de aplicação.</li>
</ul>
</li>
<li>Suporte de primeira-classe a uma linguagem dinâmica nas partes em
que faz mais sentido. (Groovy, Python, Ruby ou JavaScript já
resolveriam pra mim, mas outras também serviriam).</li>
<li>Independência de IDE -- quero poder acionar facilmente a execução
dos testes e geração de builds pela linha de comando. (Aqui usar uma
ferramenta como o Maven ajuda bastante, mas ainda depende de muita
configuração <em>boilerplate</em> -- e frequentemente, bastante esforço).</li>
</ul>
<p>Concluindo, acho que é bem interessante conhecer o que o Java EE tem a
oferecer. Mas é bom não parar por aí: ainda tem
<a href="http://www.playframework.org/">bastante</a> <a href="http://torquebox.org/">coisa</a>
<a href="http://grails.org/">interessante</a> <a href="http://www.joodoweb.com/">por</a>
<a href="http://www.webnoir.org/">aí</a> <a href="http://griffon.codehaus.org/">pra</a>
<a href="http://appfuse.org/">investigar</a>.</p>Fatos e Falácias da Engenharia de Software - notas do livro2012-12-03T13:23:00+01:002012-12-03T13:23:00+01:00Elias Dornelestag:eliasdorneles.com,2012-12-03:/2012/12/03/fatos-e-falacias-da-engenharia-de-software---notas-do-livro.html<p><a href="https://www.amazon.com/Facts-Fallacies-Software-Engineering-Robert/dp/0321117425"><img alt="Book cover" src="https://codinghorror.typepad.com/.a/6a0120a85dcdae970b012877703e5c970c-pi"></a>Acabo
de terminar a leitura de um livro simplesmente excelente, <em>Facts and
Fallacies of Software Engineering</em> (Fatos e Falácias da Engenharia de
Software), do programador/pesquisador/escritor <a href="https://en.wikipedia.org/wiki/Robert_L._Glass">Robert L.
Glass</a>. Bob Glass não é
um acadêmico que fica falando abobrinha sobre como deve ser feito
software mas que nunca quer …</p><p><a href="https://www.amazon.com/Facts-Fallacies-Software-Engineering-Robert/dp/0321117425"><img alt="Book cover" src="https://codinghorror.typepad.com/.a/6a0120a85dcdae970b012877703e5c970c-pi"></a>Acabo
de terminar a leitura de um livro simplesmente excelente, <em>Facts and
Fallacies of Software Engineering</em> (Fatos e Falácias da Engenharia de
Software), do programador/pesquisador/escritor <a href="https://en.wikipedia.org/wiki/Robert_L._Glass">Robert L.
Glass</a>. Bob Glass não é
um acadêmico que fica falando abobrinha sobre como deve ser feito
software mas que nunca quer botar a mão na massa. Ele se descreve como
um pesquisador e <span
style="text-decoration: underline;">praticante</span> de engenharia de
software (com 45 anos na área), e ele tem mesmo muita coisa interessante
pra dizer.</p>
<p>O livro -- dedicado aos pesquisadores que acenderam o fogo da ES e aos
praticantes que mantêm-no aceso -- consiste em 55 fatos apresentados num
formato fácil de ler (fato, discussão, controvérsia, fontes &
referências) e mais 10 falácias que ele resolveu adicionar depois que
começou a escrever o livro. Antes de ser cortado pelos editores o título
era “55 fatos fundamentais e frequentemente esquecidos (e algumas
falácias)”, o que é uma descrição do conteúdo bem apropriada na visão do
autor: uma grande porção dos fatos é coisa que todo mundo envolvido em
engenharia de software deveria saber e não sabe, e quem já sabe acaba
esquecendo e não faz nada a respeito.</p>
<p>Lendo esse livrinho (é pequeno, não chega às 200 páginas), fiquei
surpreso encontrando respostas relevantes para perguntas que
aparentemente ninguém estaria prestando atenção, mas que estão
disponíveis de fato há algumas décadas! A leitura foi fascinante, mas
lendo me senti muito ignorante por ainda não ter lido um material
articulando essas coisas.</p>
<p>Espie só:</p>
<ul>
<li>Propagandas exageradas (aka <em>hype</em>) são a praga da engenharia de
software. A maioria dos melhoramentos envolvendo ferramentas e
técnicas ajudam a aumentar entre 5% a 35% em produtividade e
qualidade. Não obstante, esses melhoramentos são propagandeados como
tendo benefícios de “uma ordem de magnitude”.<strong>Adotar uma nova
ferramenta ou técnica na verdade diminui a produtividade e qualidade
do trabalho, inicialmente.</strong> O benefício só é atingido depois da
curva inicial de aprendizado, e portanto só vale a pena caso seu
valor seja visto de forma realista e se tenha paciência ao medir os
benefícios.</li>
<li><strong>O fator mais importante no trabalho com software não são as
técnicas ou ferramentas usadas pelos desenvolvedores, e sim a
qualidade dos próprios desenvolvedores.</strong> Esse fato é sabido,
evidenciado e documentado desde os anos 70. Apesar disso, muita
gente decide "cortar custos" na hora de contratar desenvolvedores e
depois tenta instigar qualidade com metodologias, processos e
ferramentas. Seguidamente aparecem abordagens mesmo anti-pessoas,
que tentam transformá-las em engrenagens numa linha de montagem, e
serem facilmente substituíveis. Um exemplo famoso é o <a href="https://en.wikipedia.org/wiki/Capability_Maturity_Model">CMM -
Capability Maturity
Model</a> do
<a href="https://en.wikipedia.org/wiki/Software_Engineering_Institute">Software Engineering Institute
(SEI)</a>,
que se alastrou nas empresas públicas americanas (e vem fazendo o
mesmo nas brasileiras...), que é baseado na percepção errônea de que
o caminho para bom software é um bom processo. <em>Not so!</em> Mas veja o
site do CMMI... O hype lá cativa qualquer gerente! :P</li>
<li>As duas maiores causas de projetos saírem do controle são
<small>(a)</small> péssimas estimativas e <small>(b)</small>
requisitos instáveis. Estimativas são frequentemente feitas pelas
pessoas erradas (que não têm conhecimento o suficiente sobre como
software é construído), no momento errado (no início do projeto,
antes de qualquer trabalho pra descobrir exatamente o que será
feito), nunca são ajustadas ao longo do projeto, e apesar disso tudo
ainda são levadas a sério por todo mundo -- isso acaba gerando
expectativas inalcançáveis desde o início, estresse desnecessário e
moral-baixa das equipes. Já requisitos instáveis é um problema mais
complicado, e a engenharia de software vem tentando abordagens
diferentes em busca de soluções (depois de falhar miseravelmente
tentando achar um jeito de obter um conjunto fechado de requisitos
no início do projeto). Hoje, já é aceito como natural os requisitos
sofrerem alterações ao longo do projeto, e a controvérsia está mais
em como lidar nessas circunstâncias.</li>
<li>Reuso em pequena escala (<em>reuse-in-the-small</em>) existe há muito tempo
(muito antes de OO, viu?), e é um problema resolvido desde os anos<ol>
<li>Reuso em grande escala (componentização de soluções de problemas
genéricos) é um problema muito difícil, não-resolvido, mas que tem
maior chance de funcionar para uma família de sistemas de um domínio
específico. Linguagens de domínio específico (aka DSLs) são uma boa
idéia, façamos mais coisas desse tipo!</li>
</ol>
</li>
<li><strong>Para cada 25% de aumento na complexidade do problema, há um
aumento de 100% na complexidade de sua solução.</strong> Isso não é uma
coisa a ser mudada, é só uma constatação de como as coisas são. Esse
fato é muito bom saber porque, apesar de pouco conhecido, explica
grande parte dos outros. Veja:<ol>
<li><em>Por que pessoas são tão importantes?</em> Porque é necessário
habilidade e inteligência para superar complexidade.</li>
<li><em>Por que estimar é tão difícil?</em> Porque as soluções são bem mais
complicadas do que os problemas aparentam.</li>
<li><em>Por que reuso em larga escala é tão difícil?</em> Porque grande
complexidade significa grande diversidade de soluções.</li>
<li><em>Por que existem tantas maneiras diferentes de abordar uma
solução pra um problema?</em> Porque o espaço de soluções é bastante
complexo.</li>
<li><em>Por que conhecer uma solução existente é a tarefa mais difícil
de manutenção de software?</em> Porque há muitas soluções possíveis
para qualquer problema.</li>
<li><em>Por que os softwares têm tantos erros?</em> Porque é difícil de
fazer direito na primeira vez.</li>
<li><em>Por que alguns pesquisadores de software recorrem a defesa de
idéias não verificadas em vez de fazer pesquisas avaliativas que
verifiquem suas declarações?</em> Talvez porque, no mundo de
software complexo, é muito difícil fazer as pesquisas
avaliativas tão necessárias e que deveriam anteceder as defesas
de idéias.</li>
</ol>
</li>
</ul>
<p>Eu ainda não tinha visto tantas coisas relevantes -- e que muito
presenciei serem negligenciadas, às vezes por mim mesmo, sem saber como
agir -- compactadas em tão poucas páginas, e com dados reais, obtidos
usando medidas reais e úteis. Isso que a maioria das fontes do livro são
pré-2000 (o livro é de 2003), e tem bastante coisa interessante que é
pré-1980! Fenomenal... Me senti besta por ainda não ter ido atrás de
material como esse.</p>
<p>Comecei a montar a lista acima para funcionar como um "<em>sneak-peak"</em> do
material do livro, mas agora tô achando que o formato funciona legal
para apresentar um resumão dos pontos importantes do livro (e eu posso
ser mais preguiçoso, também :). Por isso, sigo com a lista de fatos:</p>
<ul>
<li>Erros em requisitos são os mais caros de consertar quando o software
já está em produção (e os mais baratos de consertar cedo no
desenvolvimento), sendo os casos de “requisitos ausentes” os mais
difíceis de todos.</li>
<li>Ocorre uma explosão de <em>requisitos derivados</em> (os requisitos para
uma solução em particular) causada pela complexidade do processo de
solução, que pode assumir proporções 50 vezes maior que os
requisitos originais. Isso faz com que seja impossível de se obter o
Santo Graal da rastreabilidade na prática.</li>
<li>Desenvolvedores alternam entre "modos" de análise e implementação
quando o programa está sendo decomposto num nível de <em>primitivas</em>
(unidades fundamentais conhecidas e facilmente codificadas) que o
responsável pela análise domina. Se o implementador não é a mesma
pessoa que fez a análise, as primitivas de cada um serão diferentes,
e esse confronto gera uma série de problemas, tanto no caso do
projetista ou no do implementador ser o profissional mais
experiente. Por isso, é melhor que a pessoa que faça a análise seja
a mesma que o implemente. Repetidamente se tenta praticar uma
divisão de trabalho de análise e implementação, e repetidamente isso
só causa mais problemas.</li>
<li>Remoção de erros é o que mais consome tempo do ciclo de vida do
desenvolvimento de um software. <strong>Inspeção rigorosa do código é a
maneira mais efetiva de remoção de erros</strong>, mas esse fato não é
muito propagandeado porque inspeções exigem trabalho mental intenso,
não existem fabricantes fazendo dinheiro com isso e ainda, da mesma
forma que testes, às vezes são vistas como não essenciais. (Note que
apesar dos grandes benefícios para remoção de erros, inspeções
rigorosas não substituem os testes.)</li>
<li>Software que um programador típico acredita ter sido testado a
fundo, teve apenas de 55% a 60% dos seus fluxos de lógica
executados. Analisadores de cobertura ajudam a aumentar isso para
entre 85 a 90%, mas é praticamente impossível atingir os 100%. Mesmo
se fosse possível atingir os 100%, isso ainda não seria um critério
suficiente para os testes. Em torno de 35% dos defeitos em software
surgem de fluxos não-existentes e outros 40% resultam de uma
combinação única de caminhos de lógica, portanto não seriam
descobertos por uma cobertura de 100%.</li>
<li>Revisões têm aspectos tanto técnicos como sociológicos. Prestar
atenção numa parte e não na outra é receita para o desastre. Por
mais que se clame pela <em>“egoless programming”</em>, todos nós temos um
investimento emocional e intelectual no resultado do nosso trabalho
e estamos vulneráveis quando outros o estão revisando. E quando o
resultado de um revisor é considerado pelos demais participantes
duma revisão, o ego desse revisor também está na reta. Cabem algumas
sugestões:<ol>
<li>Não permita gerentes participar de revisões, eles tendem a
revisar o produtor em vez do produto.</li>
<li>Não permita pessoas despreparadas participar, elas atrapalham os
que estão preparados e causam digressões nos tópicos.</li>
<li>Separe o papel do líder da revisão do papel do produtor, para
diminuir o envolvimento do ego do produtor.</li>
</ol>
</li>
<li>Manutenção é uma solução, e não um problema. É a solução ao problema
de não saber exatamente o que se quer construir na primeira vez, e
por isso é um <em>big deal, dude, very important!</em> Ela consiste
tipicamente de 40 a 80% de custos de software (média 60%), sendo por
isso a fase mais importante. E 60% da manutenção consiste em
melhorias, 17% apenas para correção de erros, 18% manutenção
adaptiva (manter funcionando os recursos existentes em um ambiente
novo), e os restantes 5% é o popular “outros” (manutenções
preventivas -- refatorações -- estariam nesses 5%). Essa relação 60%
do custo de construção de software é manutenção, e 60% da manutenção
é adição de melhorias é chamada <a href="http://programmer.97things.oreilly.com/wiki/index.php/The_60/60_Rule">regra
60/60</a>.
Por fim, como manutenção é tão importante, talvez devesse ser
ensinada antes de ensinar a produzir software (ensinar a ler antes
de ensinar a escrever).</li>
<li><strong>Qualidade de software é uma coleção de atributos:</strong><ol>
<li><span style="text-decoration: underline;">Portabilidade</span> é
sobre criar um produto de software facilmente movido para outra
plataforma.</li>
<li><span style="text-decoration: underline;">Confiabilidade</span>
é sobre um software que faz o que devia fazer de forma
confiável.</li>
<li><span style="text-decoration: underline;">Eficiência</span> é
sobre um software que economiza em tempo de execução e consumo
de espaço.</li>
<li><span style="text-decoration: underline;">Engenharia humana (ou
usabilidade)</span> é sobre um software que é fácil e
confortável de usar.</li>
<li><span style="text-decoration: underline;">Testabilidade</span> é
sobre um software que é fácil de testar.</li>
<li><span
style="text-decoration: underline;">Compreensibilidade</span> é
sobre um software que é fácil para o mantenedor compreender.</li>
<li><span
style="text-decoration: underline;">Modificabilidade</span> é
sobre um software que é fácil para o mantenedor modificá-lo.</li>
</ol>
</li>
<li>Não existe uma ordem universal correta desses atributos que deve ser
atingida, mas é importante que cada projeto tenha a sua lista
priorizada.</li>
</ul>
<p>Se você é como eu, os fatos acima devem ter ressonados fortemente com
sua experiência. Em vários pontos do livro, experimentei uma sensação de
alívio, constantando várias comichões minhas sendo coçadas, e numa forma
tão coerente, sensata, comedida, auto-avaliativa, madura... —
<small>nuóssa, agora me apavorei comigo mesmo e a minha sacolinha de
adjetivos! :)</small></p>
<p>Pois não se trata de um time de "desenvolvedores chorões e teimosos que
só querem bater contra a gerência", mas sim de evidência científica,
informações coletadas e analisadas de forma estudada e organizada,
enfim, fatos! Esquecidos frequentemente, sim, mas sempre serão fatos, e
não vão deixar de ser verdade mesmo que muitos na indústria e na
academia estejam em negação.</p>
<p>Bem, o livro tem bem mais coisas (tô pulando toda a parte específica de
codificação), pra quem quiser saber mais pode visitar os links no fim do
artigo ou então arranjar uma cópia do livro mesmo, que vale a pena. Só
quero ainda falar sobre algumas das falácias apresentadas no fim do
livro:</p>
<p>Falácia: <em>Você não pode gerenciar o que não pode medir.</em><br>
<strong>Errado!</strong> Na verdade, fazemos isso o tempo todo. Gerenciamos um monte
de tipo de coisas que não temos como medir. Na vida diária mesmo,
inclusive, desde relações sociais até os hábitos de alimentação.
Gerenciamos até a pesquisa do câncer. Gerenciamos análise e projeto de
software, que é uma tarefa essencialmente criativa. Gerenciamos muitas
coisas que são intelectuais ou mesmo criativas, sem nenhuma idéia que
números deveríamos ter pra nos guiar. Gerentes que trabalham com bom
conhecimento tendem a gerenciar qualitativamente, e não
quantitativamente.<br>
Todavia, não é porque esse dito é uma falácia que devemos rejeitar a
mensagem que ele traz. Afinal, gerenciar tendo em mãos alguns dados
úteis é mais fácil que na ausência deles, e por isso é muito importante
para o gerenciamento de software medir as coisas úteis.<br>
Boa capacidade de julgamento é vital.</p>
<p>Falácia: <em>Você consegue "gerenciar qualidade” para um produto de
software (manage quality into a software product)</em><br>
<strong>Errado também!</strong> Aqui é basicamente uma reprise da afirmação anterior
sobre qualidade ser composta de alguns atributos: portabilidade,
confiabilidade, usabilidade, eficiência, testabilidade,
compreensibilidade e modificabilidade. <strong>Todos esses atributos da
qualidade de software têm aspectos profundamente técnicos, e portanto
<span style="text-decoration: underline;">qualidade é uma realização
técnica</span>.</strong> Não funciona marketar qualidade, ou “metodologizar”
qualidade -- as abordagens dos gerentes para atingir qualidade, que
tendem a ser um tiro no pé, alienando os profissionais técnicos. E não
ajuda que o inimigo número um de qualidade na maioria dos projetos é a
pressão do cronograma. A gerência fica querendo enfiar “qualidade” com
uma mão e tirar com a outra!
<a href="https://eljunior.files.wordpress.com/2012/12/tqm-wont_work.jpg"><img alt="TQM-wont_work" src="https://eljunior.files.wordpress.com/2012/12/tqm-wont_work.jpg?w=300"></a><br>
Note que a falácia aqui é que qualidade seja um trabalho da gerência. A
gerência tem um papel muito importante em atingir qualidade: estabelecer
a cultura de prioridade em primeiro lugar, remover barreiras que impedem
os técnicos de instituir qualidade, contratar pessoas de qualidade (a
<em>ultimate</em> melhor maneira de atingir qualidade no produto), e sair do
caminho dessas pessoas de qualidade, permitindo-as que façam o que
queriam fazer o tempo todo: construir algo que eles possam se orgulhar.</p>
<p><strong>Ler mais:</strong></p>
<ul>
<li>Post do Jeff Atwood com a lista completa de fatos e falácias (em
inglês) -- <small>o texto que me instigou a comprar o livro:</small>
<a href="https://www.codinghorror.com/blog/2008/03/revisiting-the-facts-and-fallacies-of-software-engineering.html">https://www.codinghorror.com/blog/2008/03/revisiting-the-facts-and-fallacies-of-software-engineering.html</a></li>
<li><em>"You can indeed manage what you can’t measure"</em>:<ul>
<li><a href="http://www.galorath.com/wp/you-can-manage-what-you-cant-measure.php">http://www.galorath.com/wp/you-can-manage-what-you-cant-measure.php</a></li>
<li><a href="http://blogs.hbr.org/davenport/2010/10/what_cant_be_measured.html">http://blogs.hbr.org/davenport/2010/10/what_cant_be_measured.html</a></li>
<li><a href="http://corporatedeathspiral.blogspot.com.br/2009/11/managing-what-you-cant-measure.html">http://corporatedeathspiral.blogspot.com.br/2009/11/managing-what-you-cant-measure.html</a></li>
</ul>
</li>
<li>Série de posts em português discutindo os fatos e falácias do livro:<ul>
<li><a href="http://mr-bin.blogspot.com.br/2011/03/fatos-e-falacias-de-engenharia-de.html">http://mr-bin.blogspot.com.br/2011/03/fatos-e-falacias-de-engenharia-de.html</a></li>
<li><a href="http://mr-bin.blogspot.com.br/2011/03/fatos-e-falacias-de-engenharia-de_18.html">http://mr-bin.blogspot.com.br/2011/03/fatos-e-falacias-de-engenharia-de_18.html</a></li>
<li><a href="http://mr-bin.blogspot.com.br/2011/04/fatos-e-falacias-de-engenharia-de.html">http://mr-bin.blogspot.com.br/2011/04/fatos-e-falacias-de-engenharia-de.html</a></li>
<li><a href="http://mr-bin.blogspot.com.br/2011/09/fatos-e-falacias-de-engenharia-de.html">http://mr-bin.blogspot.com.br/2011/09/fatos-e-falacias-de-engenharia-de.html</a></li>
<li><a href="http://mr-bin.blogspot.com.br/2011/11/fatos-e-falacias-de-engenharia-de.html">http://mr-bin.blogspot.com.br/2011/11/fatos-e-falacias-de-engenharia-de.html</a></li>
</ul>
</li>
</ul>Sobre construir excelente experiência de usuário - livro EffectiveUI2012-11-25T18:48:00+01:002012-11-25T18:48:00+01:00Elias Dornelestag:eliasdorneles.com,2012-11-25:/2012/11/25/sobre-construir-excelente-experiencia-de-usuario---livro-effectiveui.html<blockquote>
<p>Este é o primeiro post na idéia de escrever sobre os livros que leio,
na tentativa de fixar melhor o que tô aprendendo. Rezemos pra que não
seja o último! :)</p>
</blockquote>
<p>O livro é <a href="https://www.amazon.com/Effective-UI-Building-Experience-Software/dp/059615478X" title="Effective UI na Amazon">Effective UI: The Art of Building Great User Experience in
Software,</a>
os autores são os fundadores e …</p><blockquote>
<p>Este é o primeiro post na idéia de escrever sobre os livros que leio,
na tentativa de fixar melhor o que tô aprendendo. Rezemos pra que não
seja o último! :)</p>
</blockquote>
<p>O livro é <a href="https://www.amazon.com/Effective-UI-Building-Experience-Software/dp/059615478X" title="Effective UI na Amazon">Effective UI: The Art of Building Great User Experience in
Software,</a>
os autores são os fundadores e os empregados da empresa
<a href="http://www.effectiveui.com/">EffectiveUI</a>, no site deles tem uma
<a href="http://www.effectiveui.com/book-resources/" title="Effective UI - book resources">página do
livro</a>.
Pelo que entendi, a empresa trabalha principalmente com consultoria de
UX, e o livro é baseado principalmente na experiência deles. Nunca tinha
ouvido falar da empresa antes, mas se a
<a href="http://oreilly.com/" title="oreilly.com">O'Reilly</a> pediu pra eles escreverem
o livro, imagino que eles devem saber do que estão falando. :) </p>
<p><center>
<a href="http://shop.oreilly.com/product/9780596154790.do"><img alt="Effective UI book cover" src="https://akamaicovers.oreilly.com/images/9780596154790/cat.gif" title="EffectiveUI - livro"></a>
</center></p>
<p>Ele trata do assunto: <em>"como fazer um projeto de software de qualidade,
considerando a experiência do usuário -- UX (User eXperience)"</em>. Quando
me recomendaram esse livro, pensei que trataria de alguns princípios
básicos de interface e que talvez tivesse algumas receitas de bolo para
serem aplicadas no desenho de interfaces na prática. Todavia, um projeto
de experiência do usuário [1] envolve muito mais do que questões de
leiaute, tamanhos e tipografia. De acordo com os autores, para fazer
softwares que estimulem o envolvimento do usuário e ajudem-no a fazer
suas tarefas, é necessário construir um certo clima desde o começo do
projeto, que possibilite a equipe ser eficiente, e manter esse clima
durante o projeto até o fim. Por isso, acho que posso dizer que esse
livro também é sobre como escapar das armadilhas que causam a maioria
dos softwares serem muito ruins de usar, e que fazem projetos
fracassarem antes de você ouvir falar deles.</p>
<blockquote>
<p>[1]: minha tradução para <a href="https://en.wikipedia.org/wiki/User_experience_design">User experience design</a>, não sei se existe termo melhor.</p>
</blockquote>
<p>Boa parte dos conselhos do livro são diretamente aplicáveis para pessoas
envolvidas com liderança de projetos, mas o conteúdo interessa qualquer
pessoa que esteja envolvido em algum esforço pra produzir software de
qualidade.</p>
<p>O engraçado é que, se eu soubesse de antemão exatamente do que o livro
tratava, acho que eu não teria me interessado. Mas como me recomendaram
como sendo um livro muito bom, resolvi ler e ver o que conseguiria
aprender, e no fim das contas valeu muito a pena! O livro é bem
abrangente, e fala de muita coisa que como desenvolvedor, é muito útil
eu me dar conta. Ainda assim, tenho a impressão que algumas lições ainda
vão demorar pra amadurecer na minha cabeça.</p>
<p>Alguns pontos importantes do livro:</p>
<ul>
<li>Melhorias na experiência do usuário (UX) de um produto podem render
facilmente retorno sobre investimento, pois criam valor ajudando os
usuários a atingir seus objetivos.</li>
<li>A responsabilidade pela experiência do usuário é de todo mundo, e
não funciona sendo delegada a alguns departamentos isolados -- basta
lembrar de como é "divertido" ligar para o call-center da sua
prestadora de telefonia...</li>
<li>Na hora de vender a idéia de melhorar a UX para as partes
interessadas
(<em><a href="https://pt.wikipedia.org/wiki/Stakeholder" title="Stakeholder na Wikipedia">stakeholders</a></em>),
exponha-as ao feedback dos usuários. Os autores inclusive contam uma
história de como os <em>stakeholders</em> de um projeto finalmente
decidiram priorizar a melhoria da usabilidade de um produto, depois
de assistirem o vídeo de um usuário muito irritado com o software a
ponto de esmurrar o teclado.</li>
<li>Você nunca tem todas as respostas antes do produto ser
desenvolvido. Especificações e requerimentos funcionais feitos antes
de começar o desenvolvimento são instantaneamente deficientes por
terem sido feitos da perspectiva menos informada. Em vez de perder
tempo definindo especificações, descubra os objetivos e as
prioridades dos usuários e do negócio. Atingir os objetivos do
negócio por meio de habilitar os usuários a atingir seus objetivos
== sucesso.</li>
<li>Intolerância a incertezas é intolerável. Durante a maior parte do
projeto, sempre haverá incerteza e desconhecidos, aprender a lidar
com isso é fundamental. Planejamento detalhado demais está fadado ao
fracasso porque muito do desconhecido ainda não foi descoberto.
Evite os problemas do <a href="https://en.wikipedia.org/wiki/Big_Design_Up_Front">Big Design Up
Front</a> e comece o
desenvolvimento o mais rápido possível. Quanto mais adiante no
projeto você estiver, mais sábio você será. Por isso, descubra os
objetivos cedo e postergue as decisões sobre os detalhes.</li>
<li>A coisa mais importante que pode ser feita para o sucesso de um
projeto é montar a melhor equipe. A equipe deve reconhecer a
importância das necessidades dos usuários para o produto. Sem
empatia com os usuários, os desenvolvedores podem acabar
sacrificando UX pelo que é mais fácil de fazer (ou por um “desejo de
elegância” para o modelo), os designers podem focar demais em deixar
bonito em vez de funcional, e outros colaboradores podem dar
importância demais às suas suposições sobre como o produto deve ser
e deixar de lado a pesquisa de usuário: tudo isso sacrifica a
qualidade do produto e diminui as chances dum bom retorno sobre o
investimento.</li>
</ul>
<p>Além da parte inicial que apresenta alguns conceitos de UX, explica sua
importância e por que você deveria se importar, o livro tem um capítulo
muito interessante sobre como capturar a perspectiva do negócio. Nele
são descritos alguns exercícios úteis para ajudar a descobrir as
expectativas das partes interessadas, encontrar as reais necessidades
por trás das idéias formuladas (por exemplo, alguém pode dizer que deve
haver um mecanismo para os usuários trocarem emails, em vez de expor a
necessidade de compartilhamento de recursos e facilidades de
colaboração), estabelecer o público-alvo do produto e as características
de alguns usuários desse público, e ainda, priorizar quais são as partes
importantes disso tudo. Basicamente, uma sucessão de negociações e de
aplicações do <a href="https://pt.wikipedia.org/wiki/Princ%C3%ADpio_de_Pareto" title="Princípio de Pareto">princípio de
Pareto</a>
para descobrir o que é realmente necessário.</p>
<p>Mas o trecho que mais me chamou a atenção foi o capítulo intitulado
Arquitetura Inicial do Produto (<em>Initial Product Architecture</em>), que
discorre sobre as decisões iniciais do desenvolvimento, sobre coisas que
serão difíceis de mudar depois. A hora em que são respondida perguntas
tipo: "Que tamanho é esse troço que vamos fazer?" "Que outros produtos
teremos que integrar?" "Quais linguagens/plataformas vamos utilizar?"
"Como os componentes serão conectados?” “Como as pessoas vão usar as
coisas que vamos criar?” “Que ‘cara’ o produto vai ter?”, e várias
outras. Segundo os autores, são dois tipos de “arquitetos” que trabalham
nessa parte: os "arquitetos de UX" e os "arquitetos técnicos".</p>
<p>Os arquitetos de UX usariam seus conhecimentos (que envolvem usualmente
usabilidade, design gráfico, práticas de engenharia de software, etc,
até psicologia) para produzir um refinamento das soluções a serem
desenvolvidas através de descrições de cenários contextuais, guias de
estilos, mapeamento de fluxos da interface, elaboração de nomenclatura,
e outras coisas mais. O livro detalha algumas técnicas usadas, e eu
curti em especial a parada sobre o uso de cenários (<a href="http://uxsuccess.com/2009/12/01/agile-personas-and-context-scenario/" title="Agile Personas and Context Scenario">exemplos
aqui</a>
- em inglês), porque esses tempos comecei a fazer algo parecido num
projeto sem saber, e me pareceu que funcionava legal. A sacada desses
cenários é que você descreve os passos que o usuário precisa para fazer
uma tarefa, mas não precisa especificar cada detalhezinho que você não
precisa definir. Dessa forma, os cenários representam as características
tradicionais de um <em>framework</em>: deixam fixo e estável o que já se sabe,
flexível e maleável o que ainda precisa ser descoberto.</p>
<p>Ainda nesse mesmo estágio de arquitetura inicial, os arquitetos técnicos
resolveriam os aspectos técnicos chave do produto que devem ser
definidos de antemão, tendo em vista as necessidades e restrições
existentes. As tarefas geralmente envolvem coisas como descobrir quais
recursos existentes serão aproveitados, quais linguagens/plataformas
devem ser usadas, que elementos de infraestrutura serão necessários, e
por último mas não menos importante, começar a identificar a lógica de
negócio (que usualmente está espalhada em outros softwares, planilhas
Excel e às vezes apenas na cabeça de algumas pessoas).</p>
<p>Por fim, os últimos dois capítulos tratam sobre o restante do projeto
(onde é gasto a maior parte do tempo), ressaltando a importância de
feedback e de comunicação durante todas as etapas do projeto. O primeiro
deles discorre especificamente sobre a importância do processo de
desenvolvimento ser
<a href="https://pt.wikipedia.org/wiki/Desenvolvimento_iterativo_e_incremental" title="Desenvolvimento iterativo e incremental - Wikipedia">iterativo</a>,
para agilizar a obtenção de <em>feedback</em> e a reavaliação das decisões,
restrições e objetivos levando em conta o <em>feedback</em>obtido. Esse
capítulo dá algumas idéias interessantes sobre minimizar as desvantagens
de um processo de desenvolvimento problemático que você pode estar sendo
forçado a trabalhar (como um
<a href="https://pt.wikipedia.org/wiki/Modelo_em_cascata">cascata</a> ou um
<a href="https://en.wikipedia.org/wiki/Big_Design_Up_Front" title="Big Design Up Front">BDUF</a>):</p>
<ul>
<li>permitir mais liberdade nas etapas posteriores de desenvolvimento;
às vezes isso pode ser feito simplesmente renomeando os documentos
“requisitos” e “especificações” produzidos para “diretrizes” e
“recomendações”. :)</li>
<li>envolver profissionais de outras disciplinas nas diferentes etapas:
colocar alguns profissionais de UX e desenvolvedores também para
trabalhar na definição dos requisitos de negócio, envolver também
pelo menos um especialista de UX e de negócio na etapa de
desenvolvimento.</li>
<li>apressar as primeiras etapas para chegar logo na etapa de
desenvolvimento, que será melhor de responder as perguntas. Qualquer
especificação feita antes será cheia de erros e omissões e muitas
vezes são criadas apenas por necessidades burocráticas, então é
melhor não gastar muito tempo nisso e ir logo para a etapa em que as
respostas serão realmente obtidas.</li>
</ul>
<p>E o último é sobre as ações relacionadas aos <em>releases</em>, que devem ter
como objetivo obter feedback (versão <em>alpha</em> para feedback de usuários
internos, versão <em>beta</em> para feedback de uma amostra de usuários mais
perto do real), e também das tarefas necessárias após o <em>release</em>:
marquetar o produto (muito necessário, mesmo que seja para uso interno
da organização), montar a documentação para os usuários (de preferência
embutida no próprio produto, disponível no contexto), e recapitular as
lições aprendidas. É importante verificar se os objetivos do negócio
originais estão sendo alcançados, e os objetivos do usuário também: o
resultado pode virar material para o próximo projeto. Pode ser útil
embutir no produto mecanismos para rastrear as ações dos usuários, para
verificar quais áreas requeiram atenção.</p>
<p>Enfim, talvez esse texto tenha ficado comprido demais, mas pode também
ser um bom sinal: o livro é bom e até que aprendi bastante coisa.
Recomendo!</p>
<p><small>Valeu, Filipi
(<a href="http://www.nextt.com.br/" title="www.nextt.com.br">NEXTT</a>), pela
recomendação do livro. :)</small></p>Algoritmos deviam ser ensinados breadth-first, e não depth-first2012-11-07T16:58:00+01:002012-11-07T16:58:00+01:00Elias Dornelestag:eliasdorneles.com,2012-11-07:/2012/11/07/algoritmos-deviam-ser-ensinados-breadth-first-e-nao-depth-first.html<p>Algoritmos deviam ser ensinados
<a href="https://pt.wikipedia.org/wiki/Busca_em_largura" title="Busca em largura (Breadth-first search), na Wikipedia"><em>breadth-first</em></a>,
e não
<a href="https://pt.wikipedia.org/wiki/Busca_em_profundidade" title="Busca em profundidade (Depth-first search) na Wikipedia"><em>depth-first</em></a>! </p>
<blockquote>
<p>Note que não me refiro ao aprendizado de programação, mas ao estudo sistemático de algoritmos (envolvendo projeto e análise).</p>
</blockquote>
<p><a href="https://pt.wikipedia.org/wiki/Busca_em_profundidade" title="Busca em profundidade (Depth-first search) na Wikipedia">Depth-first</a> é demasiado frustrante,
especialmente para quem já trabalha na indústria e sabe que existem muitas
outras coisas tão ou mais importantes quanto …</p><p>Algoritmos deviam ser ensinados
<a href="https://pt.wikipedia.org/wiki/Busca_em_largura" title="Busca em largura (Breadth-first search), na Wikipedia"><em>breadth-first</em></a>,
e não
<a href="https://pt.wikipedia.org/wiki/Busca_em_profundidade" title="Busca em profundidade (Depth-first search) na Wikipedia"><em>depth-first</em></a>! </p>
<blockquote>
<p>Note que não me refiro ao aprendizado de programação, mas ao estudo sistemático de algoritmos (envolvendo projeto e análise).</p>
</blockquote>
<p><a href="https://pt.wikipedia.org/wiki/Busca_em_profundidade" title="Busca em profundidade (Depth-first search) na Wikipedia">Depth-first</a> é demasiado frustrante,
especialmente para quem já trabalha na indústria e sabe que existem muitas
outras coisas tão ou mais importantes quanto performance (legibilidade,
usabilidade, simplicidade, extensibilidade, e lá vai...). Embora eu consiga
visualizar a utilidade de poder provar a complexidade assintótica e a
otimização de uma determinada solução na teoria, não percebo as vantagens de
aprender a fazê-lo para cada tipo de algoritmo <strong>na prática</strong>.</p>
<p>Seria muito melhor uma abordagem
<a href="https://pt.wikipedia.org/wiki/Busca_em_largura" title="Busca em largura (Breadth-first search), na Wikipedia">breadth-first,</a> em que você ficasse sabendo das
técnicas existentes de projeto de algoritmos, um apanhado das soluções
existentes para os problemas clássicos envolvendo as estruturas de dados
clássicas e as construções mais elaboradas em cima delas, e ir tentando
resolver problemas parecidos com os que já foram vistos. Dessa forma, o
estudante desenvolveria a habilidade de identificar e classificar os problemas
que aparecessem, e poderia estudá-lo a fundo (aí sim, <em>in depth</em>) quando fosse
necessário.</p>
<p>Mais importante do que compreender todos os detalhes duma instância específica
de um problema e saber articular essa compreensão, é conhecer as técnicas
utilizadas para obter a solução dessa classe de problemas e saber como
identificá-los.</p>
<p>Alguém conserte isso, por favor!</p>Primeiras escolhas importam2012-10-18T16:23:00+02:002012-10-18T16:23:00+02:00Elias Dornelestag:eliasdorneles.com,2012-10-18:/2012/10/18/primeiras-escolhas-importam.html<p>Nossas primeiras experiências influenciam as seguintes muito mais do que
a gente percebe.</p>
<p>Algumas coisas você não escolhe: sua língua materna, sua primeira
escola, sua primeira professora de matemática. Mas tudo isso vai
deixando umas estampas na sua vida inteira, influenciando o jeito que
você pensa, sua habilidade de perceber …</p><p>Nossas primeiras experiências influenciam as seguintes muito mais do que
a gente percebe.</p>
<p>Algumas coisas você não escolhe: sua língua materna, sua primeira
escola, sua primeira professora de matemática. Mas tudo isso vai
deixando umas estampas na sua vida inteira, influenciando o jeito que
você pensa, sua habilidade de perceber as próprias emoções, sua
capacidade de entender o mundo e as outras pessoas. Com essas coisas a
gente eventualmente aprende a aceitar o que não foi bom, tenta ver o
lado positivo da coisa toda. Não tivemos escolha mesmo, não adianta
querer mudar o que não tem como.</p>
<p>Agora, sobre as coisas que a gente tem, sim, escolha (o que comer, o que
vestir, o que escutar, o que rejeitar), aí acontecem umas coisas
estranhas. Muitas vezes, a gente acha que tá escolhendo, mas na verdade
não está. O fato é que tem um <em>bug</em> chato no seu cérebro, que faz ele
querer que tudo seja meio parecido com o que ele já viu.</p>
<p>O primeiro sabor de sorvete que você escolher, você provavelmente irá
repeti-lo muitas vezes, talvez sem nem experimentar muito outros, e irá
comparar sempre os outros que experimentar com aquele. Por ter sido a
primeira escolha, virou a referência. E às vezes você provou 2 ou 3
diferentes, e já escolhe um favorito... Quero dizer, quantos sabores de
sorvete existem?</p>
<p>O primeiro programa de edição de texto que você usou na vida, vem
influenciando toda a sua vida de usuário de computador. O tipo de coisas
a aparecer na tela, a ação esperada para cada tecla, as respostas aos
cliques do mouse, tudo já criou uma primeira impressão que afetarão
todas as próximas aplicações que você usa.</p>
<p>Nossas primeiras escolhas, muitas vezes tomadas no automático sem pensar
muito, tendem a se repetir e influenciar todas as próximas. Elas definem
o espaço em que todas as outras seguintes serão escolhidas e avaliadas.</p>
<p>Pense na primeira vez que você resolveu comer um doce depois do almoço,
e quantas próximas vezes você decidiu fazer a mesma coisa sem
pestanejar. Ou quando você resolveu que assistir um vídeozinho do
YouTube rapidinho no horário de trabalho não dá nada, que até tem a ver
um pouco com assuntos do trabalho, e quantos próximos vídeozinhos
houveram, alguns nada a ver com o trabalho...</p>
<p>Se você é um programador, a primeira linguagem que você aprendeu
influenciará todas as próximas que você aprender. Alguns programadores
chegam ao extremo de achar que a sua primeira linguagem é realmente a
melhor, tudo que ele precisa, e não vai mudar mais nunca.</p>
<p><a href="https://www.youtube.com/watch?v=iKQ3DIP8mzU">Primeiras escolhas
importam!</a><br>
Elas afetam você e as decisões que vai tomar depois, mais do que você
consegue se dar conta.</p>
<p>Num mundo em que somos continuamente rodeados de avalanches de
informações, fazer boas escolhas iniciais faz muita diferença.</p>
<p>Vamos prestar atenção nas próximas, então. :)</p>O que fazer quando o Ubuntu trava2012-06-30T21:11:00+02:002012-06-30T21:11:00+02:00Elias Dornelestag:eliasdorneles.com,2012-06-30:/2012/06/30/o-que-fazer-quando-o-ubuntu-trava.html<p>Um amigo meu costumava dizer que tudo no Linux é com malabarismos no
teclado, porque certa vez ele conseguiu rebootar um sistema que estava
travado, apertando várias teclas aleatórias ao mesmo tempo
("Alt+Shift+Ctrl+Del+K+Enter", narrava). Tempos depois, ele acabou
adotando o <a href="http://www.ubuntu.com">Linux Ubuntu</a> no desktop, e …</p><p>Um amigo meu costumava dizer que tudo no Linux é com malabarismos no
teclado, porque certa vez ele conseguiu rebootar um sistema que estava
travado, apertando várias teclas aleatórias ao mesmo tempo
("Alt+Shift+Ctrl+Del+K+Enter", narrava). Tempos depois, ele acabou
adotando o <a href="http://www.ubuntu.com">Linux Ubuntu</a> no desktop, e embora
ainda tenha problemas de vez em quando, tenho a impressão que ele já se
adaptou bem... Este post é uma homenagem a ele, uma versão em Português
duma <a href="http://askubuntu.com/questions/4408/what-should-i-do-when-ubuntu-freezes" title="AskUbuntu - What should I do when Ubuntu freezes">resposta no AskUbuntu à pergunta do que fazer quando o Ubuntu
trava</a>!
:)</p>
<h2>Quando um programa pára de funcionar:</h2>
<p>Quando a janela dum programa pára de responder, você geralmente consegue
parar o programa no botão Fechar (aquele com o X), no canto superior
direito (ou esquerdo, nas versões mais novas do Unity). Geralmente isso
vai resultar numa mensagem avisando que o programa não está respondendo,
e lhe mostrar a opção para matar o programa ou continuar esperando até
ele voltar a responder.</p>
<p>Às vezes isso não funciona como esperado. Se você não consegue fechar
uma janela do jeito normal, você pode abrir um terminal (ou apertar
<kbd>Alt</kbd> + <kbd>F2</kbd>) e executar o comando <code>xkill</code>. Feito
isso, o cursor do mouse se transformará em um X, e você pode clicar na
janela com problema para matar o processo, ou clicar com o direito em
qualquer lugar para voltar o mouse ao normal.</p>
<p>Quando comandos rodando num terminal param de responder, geralmente eles
podem ser parados com as combinações <kbd>Ctrl</kbd> + <kbd>C</kbd> ou
<kbd>Ctrl</kbd> + <kbd>/</kbd>. Se nenhum funcionar, você pode abrir
outro terminal (ou tentar recuperar o controle do mesmo com
<kbd>Ctrl</kbd> + <kbd>Z</kbd>), e tentar descobrir o número do processo
para matar "na mão", usando <code>ps ax | grep COMANDO</code> onde COMANDO é o nome
do programa que não está respondendo. Isso deve resultar numa saída
parecida com essa: </p>
<div class="highlight"><pre><span></span><code>$<span class="w"> </span>ps<span class="w"> </span>ax<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>firefox
<span class="m">2110</span><span class="w"> </span>?<span class="w"> </span>Sl<span class="w"> </span><span class="m">30</span>:32<span class="w"> </span>/usr/lib/firefox/firefox
<span class="m">2192</span><span class="w"> </span>?<span class="w"> </span>Sl<span class="w"> </span><span class="m">21</span>:19<span class="w"> </span>/usr/lib/firefox/plugin-container<span class="w"> </span>/usr/lib/flashplugin-installer/libflashplayer.so<span class="w"> </span>-greomni<span class="w"> </span>/usr/lib/firefox/omni.ja
<span class="m">2110</span><span class="w"> </span><span class="nb">true</span><span class="w"> </span>plugin<span class="w"> </span><span class="m">4584</span><span class="w"> </span>pts/0<span class="w"> </span>S+<span class="w"> </span><span class="m">0</span>:00<span class="w"> </span>grep<span class="w"> </span>--color<span class="o">=</span>auto<span class="w"> </span>firefox
</code></pre></div>
<p>O primeiro campo de cada linha é o número do processo (PID, de <em>Process
ID</em>) dos programas que o <code>grep</code> encontrou na busca (você pode ignorar o
último, que representa o próprio <code>grep</code>). Para matar o processo, use o
comando: <code>kill -9 PID_DO_PROCESSO</code>, usando o número correspondente ao
programa problemático no lugar de <em>PID_DO_PROCESSO</em>. Você pode ter que
fuçar um pouco mais pra descobrir qual o processo certo da lista,
refinando a busca do <code>grep</code> ou então usar o programa <code>top</code> no lugar.</p>
<p>Se você estiver usando o <a href="http://www.gnome.org">GNOME</a>, você não precisa
ter que lidar com essas elocubrações na linha de comando pra fazer isso,
simplesmente abra o <em>Monitor do Sistema</em> (vá em <code>Sistema</code> →
<code>Administração</code> → <code>Monitor do Sistema</code>), vá para a aba <em>Processos</em>,
escolha o processo que você precisa matar (talvez o que está usando 90%
da CPU?), clique com o direito nele e escolha a opção
<code>Finalizar Processo</code> ou <code>Matar Processo</code>:</p>
<p><a href="https://eljunior.files.wordpress.com/2012/06/matar_processo.png"><img alt="Terminando um processo usando o Monitor do Sistema do
GNOME" src="https://eljunior.files.wordpress.com/2012/06/matar_processo.png" title="GNOME - Monitor do Sistema"></a></p>
<h2>Quando o mouse pára de funcionar:</h2>
<p>Se o teclado ainda funciona, você pode tentar reiniciar o ambiente
gráfico com a combinação <kbd>Alt</kbd> + <kbd>SysReq (Print
Screen)</kbd> + <kbd>K</kbd>. Isso vai fechar todos os programas rodando
no ambiente gráfico e voltar você à tela de login. Opcionalmente, você
pode tentar abrir o <code>gnome-terminal</code> com <kbd>Alt</kbd> + <kbd>F2</kbd>
e tentar descobrir o que está acontecendo (quem sabe matar o programa
que avacalhou o mouse?).</p>
<h2>Quando tudo, teclas e mouse, param de funcionar:</h2>
<p>Tente fazer um reboot seguro usando as <a href="http://jvflima.wordpress.com/2007/01/09/magicas-do-sysreq/" title="Mágicas do SysReq">Mágicas do
SysReq</a>.
Isso vai envolver um certo malabarismo tecladístico que faz jus aos
comentários do meu amigo: enquanto mantém pressionadas as teclas
<kbd>Alt</kbd> e <kbd>SysReq (Print Screen)</kbd>, digite a sequência
<kbd>R</kbd> <kbd>E</kbd> <kbd>I</kbd> <kbd>S</kbd> <kbd>U</kbd>
<kbd>B</kbd>. Esses comandos são reconhecidos pelo kernel Linux, que
executam as operações:</p>
<ul>
<li>un<strong>R</strong>aw: recupera o controle do teclado,</li>
<li>t<strong>E</strong>rminate: envia o sinal SIGTERM a todos os processos, permitindo que terminem graciosamente,</li>
<li>k<strong>I</strong>ll: envia o sinal SIGKILL para todos os processos, forçando-os a terminar imediatamente,</li>
<li><strong>S</strong>ync: sincroniza dados do sistema de arquivos com o disco,</li>
<li><strong>U</strong>nmount: remonta todos os arquivos em modo somente leitura,</li>
<li>re<strong>B</strong>oot: reinicia o sistema</li>
</ul>
<blockquote>
<p><strong>Nota:</strong> Na época que aprendi essa sequência de comandos, lembro que me ajudou a decorar como <em>BUSIER</em> ao contrário...</p>
</blockquote>
<p>Se isso não funcionar, então está na hora de reiniciar o computador no dedão!</p>Entre profissionais2012-06-21T20:41:00+02:002012-06-21T20:41:00+02:00Elias Dornelestag:eliasdorneles.com,2012-06-21:/2012/06/21/entre-profissionais.html<p>Alguns dias atrás, tive a chance de fazer duas coisas muito importantes pra
mim: apresentar uma performance solo no meu estilo de violão instrumental
(acústico fingerstyle <em>in your face</em> :D) e subir no palco com músicos
profissionais: o estupendo guitarrista
<a href="https://pt.wikipedia.org/wiki/Manezinho" title="Manézinho - nativo de Floripa, SC">manézinho</a> <a href="http://www.lucianobilu.com.br/" title="Site do guitarrista Luciano Bilu">Luciano Bilu</a> e seu trio!</p>
<p>Há já um bom …</p><p>Alguns dias atrás, tive a chance de fazer duas coisas muito importantes pra
mim: apresentar uma performance solo no meu estilo de violão instrumental
(acústico fingerstyle <em>in your face</em> :D) e subir no palco com músicos
profissionais: o estupendo guitarrista
<a href="https://pt.wikipedia.org/wiki/Manezinho" title="Manézinho - nativo de Floripa, SC">manézinho</a> <a href="http://www.lucianobilu.com.br/" title="Site do guitarrista Luciano Bilu">Luciano Bilu</a> e seu trio!</p>
<p>Há já um bom tempo que tenho sido o <em>bedroom player</em>, curtindo o violão sem
muita preocupação, levando como hobby mesmo, pra se divertir. Poder acompanhar
profissionais nos ensaios e no palco foi uma experiência reveladora pra mim, em
diversos aspectos que de fato ainda estou refletindo...</p>
<p>É a situação ideal pra se aprender: estar no meio de gente que manja muito mais
do que a gente, prestando bastante atenção pra aprender o máximo! Tentei
prestar atenção e tomar nota de algumas coisas que me chamaram atenção,
relacionando com as características que também percebo nos profissionais de
excelência que já conheci na minha área.</p>
<p>Profissional não deixa detalhes pra trás. Quando alguma coisinha não está
funcionando, ela é identificada, isolada e trabalhada, até a música ficar
completa. Cada música tem o jeito certo para terminar, o lugar certo para o
improviso, etc. Se o leitor é músico profissional, imagino que esteja se
perguntando por que estou falando de coisas óbvias. Pois é... <a href="http://sivers.org/obvious" title="Obvious to you. Amazing to others.">Óbvio pra você.
Fantástico para outros!</a></p>
<p>Isso é coisa de quem se importa de verdade, e por isso está simplesmente fora
de cogitação sacrificar qualidade por preguiça ou inércia mesmo. (Coisas que o
hobbyista aqui faz o tempo todo... :-/) Tarefas que o iniciante deixa de fazer
por achar enfadonhas, o profissional passa por elas sem reclamar, sem ficar
buscando atalhos.</p>
<p>E finalmente, eles são muito gente boa! Sabem que você está começando, que um
dia estiveram onde você está, e estão prontos a perdoar os erros e as notas
podres. As críticas vêm em formato de encorajamento, pra você melhorar, jogar
pra cima mesmo. E isso às vezes é o que estava faltando você querer melhorar de
verdade...</p>
<p>Minha apresentação foi lotada de erros de principiante e, apesar de eu estar
nervoso à beça nela, a perninha tremeu de verdade quando eu toquei as músicas
com a banda! A função podia até ser um pouco menos elaborada, mas senti a
responsabilidade bem maior de dar o melhor de mim, pra fazer jus ao padrão
deles.</p>
<p>Enfim, foi muito massa, me dei conta de muuuuita coisa que eu tenho que
aprender, meu respeito pelos músicos profissionais triplicou e estou muito
feliz de ter tido essa oportunidade. Valeu, Bilu! Espero que um dia me convidem
de novo. :)</p>
<p>Você pode conferir as músicas do <a href="http://www.lucianobilu.com.br/" title="Site do guitarrista Luciano Bilu">Luciano Bilu</a> no <a href="http://lucianobilu.bandcamp.com/" title="Bandcamp do Luciano Bilu">Bandcamp
dele</a>, curtir a
<a href="http://www.facebook.com/luciano.bilu.9" title="Luciano Bilu no Facebook">página no Facebook</a> e acompanhar os vídeos da gravação do terceiro álbum no <a href="https://www.youtube.com/LucianoBilu" title="Luciano Bilu no Youtube">canal
LucianoBilu no Youtube</a>.</p>
<p>Pra acabar, um vídeozinho da minha apresentação:</p>
<p><a href="https://www.youtube.com/watch?v=SUJvAepO-rc">https://www.youtube.com/watch?v=SUJvAepO-rc</a></p>Idéias e execução2012-03-09T07:38:00+01:002012-03-09T07:38:00+01:00Elias Dornelestag:eliasdorneles.com,2012-03-09:/2012/03/09/ideias-e-execucao.html<p>Uma vez ou outra a gente topa com um cara que acha que ter uma idéia é
uma coisa tremendamente importante. Execução, isto é para noviços
(subentenda-se, <em>gente que só faz o que mandam</em>)! O jeito de ter sucesso é ter uma idéia
brilhante, e a sorte de ter tido …</p><p>Uma vez ou outra a gente topa com um cara que acha que ter uma idéia é
uma coisa tremendamente importante. Execução, isto é para noviços
(subentenda-se, <em>gente que só faz o que mandam</em>)! O jeito de ter sucesso é ter uma idéia
brilhante, e a sorte de ter tido essa idéia antes de todo mundo...<br>
De vez em quando, esse cara tem uma idéia empolgante o suficiente pra
iludir a si próprio que teria uma chance de criar uma coisa. E em vez de
botar a mão na massa e tentar implementar, aporrinha os outros sobre
como a sua idéia é super, e não se esforça pra pô-la em execução.</p>
<p>Se você não reconhece esse tipo de cara, tome cuidado: talvez você seja
ele! E esse tipo de pensamento é ruim pra você.</p>
<p>É ruim devido a vários fatores importantes, sendo o principal deles o
fato de que sua idéia é uma bosta. Bem, pode ser que não, mas é muito
provável! A probabilidade é de 87,81%, graças a estatística que elaborei
depois de escrever dois (ou três) números e escolher o mais bonito.</p>
<p>Se você não domina o ofício envolvido, você tem muito mais dificuldade
de enxergar os problemas das suas idéias.<br>
Se você não tem idéias muito frequentemente, e trata cada idéia sua como
algo especial que sequer compartilha com qualquer pessoa (ou ainda, está
aguardando o "momento certo"), as chances de sua idéia estar cheia de
furos são gigantes.<br>
Por fim, se você não experimenta nenhuma das idéias que tem, você tem
muito menos chances de sucesso do que alguém que está sempre testando um
monte de idéias ruins e aprendendo com os erros.</p>
<p>O dia que você tiver uma idéia empolgante o suficiente, você não vai ter
o necessário para executá-la. Você irá racionalizar que não pôde colocar
em prática sua grande idéia porque não tinha dinheiro para pagar alguém
pra fazer o trabalho braçal pra você, não teve apoio dos amigos, não
teve incentivo do governo, e o que mais inventar o poderoso gerador de
desculpas conhecido como cérebro humano. </p>
<p><center>
<a href="https://pt.wikipedia.org/wiki/Linus_Pauling"><img alt="Linus Pauling, cientista superprodutivo" src="https://upload.wikimedia.org/wikipedia/commons/5/58/L_Pauling.jpg" title="Linus Pauling"></a>
</center></p>
<blockquote>
<p>Se você quer ter boas idéias, você precisa ter muitas idéias. A
maioria delas estarão erradas. O que você precisa aprender é quais
jogar fora. - Linus Pauling, cientista superprodutivo</p>
</blockquote>
<p>Ward Cunningham, famoso pela <a href="https://en.wikipedia.org/wiki/Ward_Cunningham#Ideas_and_inventions">invenção do Wiki e de outras noções
importantes</a>
que acabaram dando forma à indústria de software, é conhecido por viver
<a href="http://www.nagarro.com/blog/ward-cunningham/">trocando idéias com os colegas</a>,
e implementando uma ou outra <a href="http://c2.com/ward/glory/">idéia bizarra</a> das
suas. Ele sabe que o jeito de ter boas idéias é ter muitas idéias, inclusive
ruins, e que o jeito de aprender quais jogar fora é discutindo-as e pondo-as em
teste.</p>
<p><a href="http://sivers.org/multiply">Idéias são apenas um multiplicador da execução</a>. A
execução não é uma “tarefa de pedreiro”, mas sim o fator que carrega maior peso
no impacto de um produto. Se idéia tá na escala 1, execução está na escala
1000000. Uma idéia brilhante precisa também de uma execução brilhante pra virar
sucesso.</p>
<p>É inútil ficar esperando ter uma grande idéia no momento certo, e é ridículo
achar que a idéia sozinha já é grande coisa.</p>
<p>Idéias são bonitas quando transmitidas, poderosas quando compreendidas, e
impactantes quando vividas. Execute a sua. (Ou as suas. :)</p>
<p>Suje as mãos! Escreva seu livro, filme seu vídeo, implemente seu app, monte sua
barraca de cachorro-quente. Você vai escrever muito lixo, filmar muita
tosquice, fazer muitos protótipos horrendos, e seus primeiros cachorros
provavelmente não serão aquela maravilha. E talvez você não ganhe dinheiro.
Mas ahh... você vai aprender muita coisa com cada um desses cachorros-quentes,
pode ter certeza!</p>Aprendendo Thumbpicking2011-12-11T23:12:00+01:002011-12-11T23:12:00+01:00Elias Dornelestag:eliasdorneles.com,2011-12-11:/2011/12/11/aprendendo-thumbpicking.html<p><center>
<a href="https://eljunior.files.wordpress.com/2011/12/ahogado.png"><img alt="Eu, tocando violão" src="https://eliasdorneles.com/images/ahogado.jpg" title="Eu, fominha, tocando violão em Punta del Este"></a>
</center></p>
<blockquote>
<p><strong>UPDATE:</strong> atualizei os links pra download dos MP3, porque estouraram
os limites do SoundCloud.</p>
</blockquote>
<p>Já faz uns 3 anos que comecei a tocar no violão o estilo conhecido como
<em>thumbpicking</em> (alguns também chamam de <em>fingerpicking</em>, embora <a href="https://en.wikipedia.org/wiki/Fingerstyle_guitar" title="Página da Wikipedia em inglês sobre violão fingerstyle">esse termo
parece ser mais genérico</a>).</p>
<p>Desde piá eu já tocava um pouco de …</p><p><center>
<a href="https://eljunior.files.wordpress.com/2011/12/ahogado.png"><img alt="Eu, tocando violão" src="https://eliasdorneles.com/images/ahogado.jpg" title="Eu, fominha, tocando violão em Punta del Este"></a>
</center></p>
<blockquote>
<p><strong>UPDATE:</strong> atualizei os links pra download dos MP3, porque estouraram
os limites do SoundCloud.</p>
</blockquote>
<p>Já faz uns 3 anos que comecei a tocar no violão o estilo conhecido como
<em>thumbpicking</em> (alguns também chamam de <em>fingerpicking</em>, embora <a href="https://en.wikipedia.org/wiki/Fingerstyle_guitar" title="Página da Wikipedia em inglês sobre violão fingerstyle">esse termo
parece ser mais genérico</a>).</p>
<p>Desde piá eu já tocava um pouco de violão e teclado, e sempre tive vontade de
tentar emular no violão o que conseguia no teclado: tocar a melodia ao mesmo
tempo que a base. A primeira vez que vi isso ser feito de verdade, sem deixar
nada sobrando, foi há mais ou menos uns 3 anos atrás, quando vi <a href="https://www.youtube.com/watch?v=AhR04kmcSXU" title="Tommy Emmanuel tocando Angelina">um
vídeo</a> do <a href="http://www.tommyemmanuel.com/" title="Tommy Emmanuel - Site Oficial">Tommy Emmanuel</a> no Youtube.</p>
<p><center>
<a href="http://www.flickr.com/photos/zanastardust/4224141072/"><img alt="Tommy Emmanuel" src="http://farm5.staticflickr.com/4012/4224141072_f706c5452f.jpg"></a></p>
<p><a href="http://www.flickr.com/photos/zanastardust/4224141072/">Tommy Emmanuel em algum show fenomenal por aí..!</a>
</center></p>
<p>Se você gosta de violão/guitarra, e ainda não conhece o nome Tommy
Emmanuel, pare de ler esse texto agora mesmo e vá catar alguns vídeos do
Tommy no Youtube! Aliás, vá mesmo que você nem curta muito o tal do
violão! O Tommy é muito mais do que um baita músico, a chance é que você
vai se abobar de qualquer forma. Pode começar com <a href="https://www.youtube.com/watch?v=JNZL7GkqeRI" title="Tommy Emmanuel tocando Guitar Boogie em St Louis">esse vídeo de Guitar
Boogie</a>,
ou com a <a href="https://www.youtube.com/watch?v=apXSU8F8zWs" title="Tommy Emmanuel tocando Purple Haze no quintal da casa dele">versão dele de Purple
Haze</a>.</p>
<p>Pois bem, o estilo que Tommy desenvolveu é em boa parte o <em>thumbpicking</em>
de <a href="https://en.wikipedia.org/wiki/Chet_Atkins" title="Chet Atkins na Wikipedia">Chet
Atkins</a>,
que desenvolveu o próprio estilo de tocar melodia em cima de baixos
alternados tentando reproduzir o que ouvia de <a href="https://en.wikipedia.org/wiki/Merle_Travis" title="Merle Travis na Wikipedia">Merle
Travis</a>.
Travis, por sua vez, desenvolveu o seu estilo a partir do <em>country
blues</em> que era tocado pelos negros americanos da sua região.</p>
<p>Enfim, a origem da coisa toda é muito interessante, mas eu obviamente só
fui descobrir essas coisas pesquisando bastante depois. Eu comecei nessa
parada mesmo, basicamente, a partir dessa <a href="https://www.youtube.com/watch?v=YoqG7PO-MHs" title="Tommy Emmanuel dando lição de violão">pequena lição do próprio
Tommy</a>:
<a href="https://www.youtube.com/watch?v=YoqG7PO-MHs">https://www.youtube.com/watch?v=YoqG7PO-MHs</a></p>
<p><center>
<a href="https://eljunior.files.wordpress.com/2011/12/dsc05668.jpg"><img alt="Tommy Emmanuel fazendo palhaçada pra gente" src="https://eljunior.files.wordpress.com/2011/12/dsc05668.jpg?w=300" title="Tommy Emmanuel fazendo palhaçada pra gente"></a></p>
<p>Tommy fazendo graça, e eu felizão assistindo...
</center></p>
<p>Nesse vídeo ele conta, entre outras coisas, de quando ele ouviu no rádio
pela primeira vez Chet Atkins tocando a melodia, o baixo e o ritmo, tudo
ao mesmo tempo. Ele prossegue explicando (entre uma piada e outra :D)
como treinou a independência do polegar dos outros dedos da mão direita,
ainda quando criança, para conseguir fazer a mesma coisa. E assim fui
iniciado, treinando os exercícios que ele ensinou nesse vídeo (deixando
os amigos doidos), tentando incorporar nas músicas que eu já tocava,
tentando em outras que aprendi depois, e tirando algumas músicas do
Tommy e Chet.</p>
<p>Meu objetivo é tentar passar essas mesmas idéias aqui, no nosso bom
português, pra quem também quer aprender esse jeito de tocar. Então,
vamos lá!</p>
<blockquote>
<p><strong>Nota:</strong> No fim do post, está uma lista com os links para todos os
exercícios propostos (áudios & tablaturas), assim você pode baixar e
estudar com calma. As tablaturas são meramente uma ajuda pra quem achar
mais fácil assim. Se você já toca "por ouvido" e não manja tablaturas,
nem esquente a cabeça e vá pelo áudio mesmo.</p>
</blockquote>
<p><strong>Baixo alternado</strong></p>
<p>A primeira coisa que você precisa começar a fazer pra desenvolver a
independência na mão direita, treinar o baixo alternado com o polegar
sozinho, o famoso dedão (em inglês, <em>thumb</em> - daí o nome
<em>thumbpicking</em>). Esse é o famoso <em>"boom-chick"</em>, o som característico do
estilo! Alguns exemplos de músicas: <a href="https://www.youtube.com/watch?v=DrDbaUKE4mM" title="Tommy Emmanuel tocando Locomotivation">Locomotivation - Tommy
Emmanuel</a>,
<a href="https://www.youtube.com/watch?v=5wTVLIZaxMk" title="I'll see you in my dreams - Chet Atkins & Mark Knopfler">I'll see you in My Dreams - Chet Atkins & Mark
Knopfler</a>,
<a href="https://www.youtube.com/watch?v=BORQTtjscTg" title="(Robbie's Bit) Thanks Chet - Robbie McIntosh">Thanks Chet - Robbie
McIntosh</a>.</p>
<p>O princípio é simples: você precisa abafar de leve as cordas mais graves
que você vai usar para o baixo alternado, para que ele não se sobressaia
e a melodia se destaque. Então, o primeiro exercício é exatamente isso:
tocar o baixo alternado com abafamento, usando apenas o dedão.</p>
<p>Faça com a mão esquerda a <a href="http://guitar.about.com/library/blchord_aminor.htm" title="posição de lá menor aberta simples">posição aberta simples de Lá
menor</a>,
e toque com o dedão nas 3 cordas graves alternando o baixo, tentando
imitar o som que você ouve no áudio a seguir. Use o lado da palma da mão
levemente encostado as 3 cordas de cima, para abafar um pouco o som.</p>
<p>
<audio controls="controls">
<source src="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/01-baixo_alternado.mp3" type="audio/mpeg">
</source>
<embed height="80px" width="100px">
</embed>
Your browser does not support this audio
</audio>
</p>
<p><a href="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/01-baixo_alternado.mp3" title="Baixar MP3 - Baixo Alternado">Baixar
MP3</a>
| <a href="https://eljunior.files.wordpress.com/2011/12/01-baixo_alternado.pdf">Baixar tablatura: Baixo
Alternado</a></p>
<div style="padding-left: 30px;">
Se você nunca fez esse tipo de coisa antes, você vai descobrir que o seu
dedão é um bicho muito teimoso! O danado do polegar não quer fazer o que
você manda ele fazer! Não se preocupe se o começo for difícil. Insista
um pouco, tenha paciência, e em algumas semanas ele vai estar que é um
leque! :)
</div>
<div style="padding-left: 30px;">
Uma coisa que você pode tentar, é deixar os outros quatro dedos
encostados no tampo do violão, assim você se força a usar somente o
polegar e deixar os outros dedos parados. Isso foi uma coisa que eu
precisei fazer no começo por um bom tempo.
</div>
<p>O detalhe desse exercício é tentar abafar apenas as 3 cordas graves que
você vai utilizar para o baixo, deixando as 3 cordas de baixo livres e
"desabafadas" pra você usar depois. Essa técnica de abafamento com o
lado da palma é também conhecida como <a href="https://en.wikipedia.org/wiki/Palm_mute" title="Palm mute">palm
mute</a>, e é muito
usada por guitarristas que usam palheta.</p>
<p>Aliás, se você tiver uma dedeira dando sopa, pode tentar usá-la, se
preferir. Eu comecei usando os dedos mesmo, e comecei a usar a dedeira
depois. Isso não deve importar muito nessa hora, agora o importante é
treinar a independência do dedão. Faça como for mais confortável pra
você. Treine o suficiente para conseguir manter o dedão tocando esse
exercício por um bom bocado de tempo, sempre com o lado da palma da mão
abafando as 3 cordas graves.</p>
<p><strong>Trazendo os outros dedos para a dança</strong></p>
<p>Quando você achar que tá na hora, experimente tentar colocar os outros
dedos na dança. Ainda mantendo a mão esquerda fazendo a posição aberta
de Lá menor, toque no tempo forte com os outros três dedos seguinte nas
outras três cordas, enquanto faz o baixo alternado com abafamento nas
três cordas de cima. Tente imitar o som do áudio:</p>
<p>
<audio controls="controls">
<source src="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/02-acordes_no_tempo_forte_com_baixo_alternado.mp3" type="audio/mpeg">
</source>
<embed height="80px" width="100px">
</embed>
Your browser does not support this audio
</audio>
</p>
<p><a href="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/02-acordes_no_tempo_forte_com_baixo_alternado.mp3" title="Baixar MP3 - Acordes no Tempo Forte + Baixo Alternado">Baixar
MP3</a>
| <a href="https://eljunior.files.wordpress.com/2011/12/02-acordes_no_tempo_forte_com_baixo_alternado.pdf">Baixar tablatura: Acordes no Tempo Torte +
Baixo_alternado</a></p>
<div style="padding-left: 30px;">
Novamente, se é a primeira vez que você faz algo parecido, você vai
perceber o dedão teimoso! Quando você coloca os outros dedos pra tocar o
acorde, o danado se rebela... Tente trabalhar nisso até achar que está
bom.
</div>
<div style="padding-left: 30px;">
Não esquente a cabeça em ficar perfeito logo de cara. Você está
treinando sua mão pra fazer um troço que ela não tá acostumada, vai
levar um bom tempo até o som sair estável. O negócio agora é o dedão
ficar independente dos outros dedos. O som você trabalha pelo resto da
vida depois... ;)
</div>
<p>A seguir, quando você achar que está pronto, adicione uma outra puxada
no acorde com os outros dedos, no contratempo, como no áudio a seguir:</p>
<p>
<audio controls="controls">
<source src="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/03-acordes_no_contratempo_com_baixo_alternado.mp3" type="audio/mpeg">
</source>
<embed height="80px" width="100px">
</embed>
Your browser does not support this audio
</audio>
</p>
<p><a href="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/03-acordes_no_contratempo_com_baixo_alternado.mp3" title="Baixar MP3 - Acordes no contratempo com baixo alternado">Baixar
MP3</a>
| <a href="https://eljunior.files.wordpress.com/2011/12/03-acordes_no_contratempo_com_baixo_alternado.pdf">Baixar tablatura: Acordes no contratempo +
Baixo_alternado</a></p>
<p>Dependendo de como você estiver, esses 3 exercícios podem levar dias,
semanas ou até meses. Pra mim, levou alguns meses até o som começar a
soar mais natural. Eu nunca fui realmente muito disciplinado com essas
práticas todas, mas o ideal é você manter a consistência. 15 minutos por
dia é mais importante que 6 horas só no final de semana.</p>
<p>Minha sugestão é que você faça no seu ritmo, sem estresse. Mas sempre
sabendo que se não está treinando, também não vai simplesmente conseguir
tocar de repente.</p>
<p><strong>Mudando os acordes e rascunhando melodia</strong></p>
<p>Até agora, nos exercícios você estava com a mão esquerda parada e
repetindo um padrão na mão direita várias vezes seguidas. Experimente
agora mudar de acorde, mantendo o baixo alternado com o dedão: comece em
Lá menor e vá para Mi maior, e depois volte, imitando o áudio.</p>
<p>
<audio controls="controls">
<source src="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/04-base-thumbpicking.mp3" type="audio/mpeg">
</source>
<embed height="80px" width="100px">
</embed>
Your browser does not support this audio
</audio>
</p>
<p><a href="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/04-base-thumbpicking.mp3" title="Baixar MP3 - Base Thumbpicking">Baixar
MP3</a>
| <a href="https://eljunior.files.wordpress.com/2011/12/04-base-thumbpicking.pdf">Baixar tablatura: Base thumbpicking - Trocando
acordes</a></p>
<p>Repare que quando muda o acorde, temos que recomeçar o padrão de
alternar baixos em outra corda para tocar a tônica (raiz) do acorde no
tempo forte. Quando em Lá menor, o baixo alternado deve começar em Lá
(5a corda), quando em Mi maior, o baixo alternado deve começar em Mi (6a
corda).</p>
<div style="padding-left: 30px;">
Esse é outro exercício que vai empoderar bastante seu dedão. Quando você
consegue tocar com as duas mãos acompanhando as mudanças, você pode
tocar qualquer música que encaixe nesse ritmo! Você pode criar seus
próprios exercícios usando outros acordes, cifras de músicas que você
conheça, cantigas de roda, enfim!
</div>
<p>A seguir, o próximo exercício é dar mais serviço para os outros dedos,
sempre mantendo o dedão no baixo alternado. Você vai colocar alguns
padrões de dedilhado, e o dedão não pode parar. Volte para os exercícios
anteriores se necessário, comece só com o dedão, e aos poucos comece a
usar os outros. O áudio:</p>
<p>
<audio controls="controls">
<source src="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/05-base_com_dedilhado-thumbpicking.mp3" type="audio/mpeg">
</source>
<embed height="80px" width="100px">
</embed>
Your browser does not support this audio
</audio>
</p>
<p><a href="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/05-base_com_dedilhado-thumbpicking.mp3" title="Baixar MP3 - Base thumbpicking com dedilhado">Baixar
MP3</a>
| <a href="https://eljunior.files.wordpress.com/2011/12/05-base_com_dedilhado-thumbpicking.pdf">Baixar tablatura: Base thumbpicking com dedilhado em
cima</a></p>
<p>Por fim, o último exercício é uma variação do anterior, em outro tom e
com um padrão um pouquinho mais complicado. Todavia, o princípio é o
mesmo: mudar de acorde, dedilhando com os dedos nas cordas de baixo, e o
dedão sempre fazendo o baixo alternado.</p>
<p>
<audio controls="controls">
<source src="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/06-outra_base_com_dedilhado-thumbpicking.mp3" type="audio/mpeg">
</source>
<embed height="80px" width="100px">
</embed>
Your browser does not support this audio
</audio>
</p>
<p><a href="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/06-outra_base_com_dedilhado-thumbpicking.mp3" title="Baixar MP3 - Base thumbpicking em dó, com dedilhado">Baixar
MP3</a>
| <a href="https://eljunior.files.wordpress.com/2011/12/06-outra_base_com_dedilhado-thumbpicking.pdf">Baixar tablatura: Base thumbpicking em Dó
maior</a></p>
<p><strong>Músicas simples de exemplo para estudar</strong></p>
<p>O resto agora é com você, meu nego! :)</p>
<p>Fazer o que a maioria dos outros violeiros/guitarristas têm preguiça:
aprender músicas novas!</p>
<p>Para o pontapé inicial, gravei essas versões de Aloha Oe e Windy and
Warm pra esta pequena lição de <em>thumbpicking</em>. Você pode começar
trabalhando nelas, ou achar outras no YouTube (<a href="https://www.youtube.com/watch?v=Z3RArufrbgw" title="Freight Train lesson no Youtube">Freight
Train</a>
é uma boa).</p>
<p><strong>Exemplo de Thumbpicking - Aloha Oe</strong></p>
<p>
<audio controls="controls">
<source src="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/07-exemplo-aloha_oe.mp3" type="audio/mpeg">
</source>
<embed height="80px" width="100px">
</embed>
Your browser does not support this audio
</audio>
</p>
<p><a href="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/07-exemplo-aloha_oe.mp3" title="Baixar MP3 de Aloha Oe">Baixar MP3 - Aloha
Oe</a></p>
<p><strong>Exemplo de Thumbpicking - Windy & Warm</strong></p>
<p>
<audio controls="controls">
<source src="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/08-exemplo-windy_and_warm.mp3" type="audio/mpeg">
</source>
<embed height="80px" width="100px">
</embed>
Your browser does not support this audio
</audio>
</p>
<p><a href="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/08-exemplo-windy_and_warm.mp3" title="Baixar MP3 - Windy and Warm">Baixar MP3 - Windy and
Warm</a></p>
<blockquote>
<p>Não deixe de conferir as versões de Windy & Warm de Tommy e Chet no
Youtube. Só do Tommy tem várias versões, uma melhor que a outra...</p>
</blockquote>
<p>E aprenda mais músicas. Dizem que músicas são os melhores professores.
Copie as versões dos outros, faça as suas versões.</p>
<p>Pra você não se frustrar, comece com músicas simples. Se as que você já
tentou estão fáceis, tente aprender algumas do Tommy Emmanuel ou do Chet
Atkins, olhando os vídeos no Youtube, ou
<a href="http://tommyemmanuel.wordpress.com/gitar-tabok/" title="blog compartilhando tablaturas do Tommy">catando</a>
<a href="http://tommyemmanuel.wordpress.com/chet-atkins/" title="blog compartilhando tablaturas do Chet">algumas</a>
tablaturas por aí. (Se todas estiverem fáceis, me avise, que vou querer
fazer aula com você. :)</p>
<p>Uma coisa que ajuda na hora de aprender uma música, é <a href="https://eljunior.wordpress.com/2011/07/28/tocar-video-ou-musica-em-outra-velocidade-mantendo-o-tom/" title="como tocar vídeo ou música em outra velocidade, mantendo o tom">reproduzir o
arquivo de áudio e/ou vídeo mais lento, mantendo o mesmo
tom</a>.
Existem programas que ajudam nisso, no Linux eu uso o <a href="http://29a.ch/playitslowly/" title="Play It Slowly">Play It
Slowly</a> e o
<a href="http://www.mplayerhq.hu/" title="site do mplayer">mplayer</a> (na linha de
comando). Para Windows, muita gente usa o
<a href="http://bestpractice.sourceforge.net/" title="página do BestPractice">BestPractice</a>
para áudio, mas não sei indicar um que faça o mesmo com vídeo.</p>
<p>No más, acho que era isso! Quaisquer dúvidas, sugestões ou correções,
deixe um comentário ou mande um email, que responderei assim que puder.</p>
<p><strong>Lista dos exercícios dessa lição:</strong></p>
<p>Os arquivos de áudio estão publicados <a href="http://soundcloud.com/eliasdorneles/sets/aprendendo-thumbpicking-1" title="Aprendendo Thumbpicking - Soundcloud - eliasdorneles">num
<em>set</em></a>
do <a href="http://soundcloud.com/" title="SoundCloud - Share Your Sounds">SoundCloud</a>. O
SoundCloud desativou os downloads para os MP3 porque estouraram os limites,
então movi os arquivos para <a href="https://googledrive.com/host/0B5Aeqmaq5y1MSTVNOXUtb0t0WnM/" title="Folder no Google Drive com todos os MP3">um folder no Google
Drive</a>.</p>
<p>E as tablaturas estão aqui:</p>
<ol>
<li><a href="https://eljunior.files.wordpress.com/2011/12/01-baixo_alternado.pdf">Baixo
Alternado</a></li>
<li><a href="https://eljunior.files.wordpress.com/2011/12/02-acordes_no_tempo_forte_com_baixo_alternado.pdf">Acordes no Tempo Torte +
Baixo_alternado</a></li>
<li><a href="https://eljunior.files.wordpress.com/2011/12/03-acordes_no_contratempo_com_baixo_alternado.pdf">Acordes no contratempo +
Baixo_alternado</a></li>
<li><a href="https://eljunior.files.wordpress.com/2011/12/04-base-thumbpicking.pdf">Base thumbpicking - Trocando
acordes</a></li>
<li><a href="https://eljunior.files.wordpress.com/2011/12/05-base_com_dedilhado-thumbpicking.pdf">Base thumbpicking +
dedilhado</a></li>
<li><a href="https://eljunior.files.wordpress.com/2011/12/06-outra_base_com_dedilhado-thumbpicking.pdf">Base thumbpicking em
Dó</a></li>
</ol>A maleta do milhão2011-10-17T23:40:00+02:002011-10-17T23:40:00+02:00Elias Dornelestag:eliasdorneles.com,2011-10-17:/2011/10/17/a-maleta-do-milhao.html<p><a href="https://www.flickr.com/photos/julianrod/432888092/"><img alt="maleta do
milhão" src="https://eljunior.files.wordpress.com/2011/10/432888092_8887774475_m.jpg" title="maleta cheia de dinheiro"></a></p>
<p>Anos atrás, eu estava numa sessão de conversação da escola de inglês
(que por sinal, paguei caro e não valeu o retorno), e a professora pediu
pra cada pessoa dizer o que faria se encontrasse uma maleta com um
milhão de reais. Desperta a imaginação do pessoal, surgiram rapidamente
novos …</p><p><a href="https://www.flickr.com/photos/julianrod/432888092/"><img alt="maleta do
milhão" src="https://eljunior.files.wordpress.com/2011/10/432888092_8887774475_m.jpg" title="maleta cheia de dinheiro"></a></p>
<p>Anos atrás, eu estava numa sessão de conversação da escola de inglês
(que por sinal, paguei caro e não valeu o retorno), e a professora pediu
pra cada pessoa dizer o que faria se encontrasse uma maleta com um
milhão de reais. Desperta a imaginação do pessoal, surgiram rapidamente
novos adjetivos, verbos e substantivos do idioma da rainha na fala da
galera, cumprindo a intenção da brincadeira (Ilustração roubada de:
<a href="https://www.flickr.com/photos/julianrod/432888092/" title="https://www.flickr.com/photos/julianrod/432888092/">julianrod</a>).</p>
<p>As respostas variaram entre os malandros que devolveriam a maleta
pedindo uma recompensa, a galera bon-vivant que beijaria a maleta e
torraria a grana viajando o mundo conhecendo gente nova e fazendo festa,
e o pessoal consciência social que doaria tudo pra os pobres (hmm,
talvez antes comprar um apartamento modesto. ahn, e mandar uma grana pra
os pais também..!). A minha resposta: "Eu faria de conta que não tinha
visto nada, deixava a maleta lá e ia-me embora! Dinheiro assim só traz
azar..." Ok, pode não ser a resposta mais imaginativa do mundo, e
certamente vem com uma carguinha de superstição (o que vem fácil, vai
fácil) de brinde.<br>
Todavia, acredito que seja uma superstição que é na verdade útil
(principalmente se a maleta pertence a um gângster com o dobro do meu
tamanho, ou a um golpista que me ludibriaria mais tarde), pois pensando
desse jeito eu tendo a não ser ambicioso demais.</p>
<p>Dinheiro fácil é um atrativo pra muita gente - a Internet está cheia de
tramóias que prometem ensinar como ganhar na Mega Sena (vender apostilas
de tramóias vem a ser possivelmente o jeito mais fácil de lucrar com a
Mega Sena), e tem muita gente que gasta considerável dinheiro e esforço
montando esquemas pra ajudar a aumentar as chances. As famosas fraudes
nigerianas fizeram a miséria de muita gente que caiu no conto de vigário
contado em emails pessimamente escritos (a propósito, quem lê inglês se
divertirá com <a href="http://web.archive.org/web/20070209072152/spl.haxial.net/nigerian-fraud/" title="O comedor saiu comido">a história do cara que sacaneou o spammer
nigeriano</a>).
E tudo isso, por acreditar na falsa premissa de que mais dinheiro é
igual a mais felicidade.</p>
<p>Bem, eu provavelmente não vivi o suficiente pra poder opinar com muita
propriedade sobre assuntos financeiros (ainda tenho muitas más decisões
a tomar pela frente :), mas o pouco que já vivi me é suficiente pra
corroborar o seguinte princípio: "Você DIFICILMENTE vai ser mais feliz
do que você é agora, com mais dinheiro do que você tem agora."</p>
<p>Aparentemente, todo mundo sabe disso, mais ou menos. Ao mesmo tempo,
todo mundo ainda quer ganhar um pouco mais, e acaba eventualmente
pensando que só fala esse tipo de coisa quem já tem uma vida
confortável, emprego razoável, etc e tal. Bem... talvez isso tenha sua
parcela de verdade. Ainda assim, é certo que quem não consegue se
satisfazer com um salário mirrado, dificilmente vai aprender a ser feliz
com um salário maior. Porque um salário maior pode até trazer um
pouquinho mais de conforto, mas não vai mudar muito o jeito que você
funciona.</p>
<p>O pensamento de que a gente seria mais feliz se tivesse mais dinheiro
está diretamente relacionado com um viés cognitivo conhecido como
ancoragem (a Wikipedia em inglês tem um <a href="https://en.wikipedia.org/wiki/Anchoring">ótimo artigo a
respeito</a>). Ancoragem se trata
da tendência humana de confiar demais em um determinado dado ou
informação (a "âncora"), na hora de tomar uma decisão. O exemplo da
Wikipedia é, na busca de um carro usado para comprar, focar
excessivamente no ano ou no registro do odômetro (ancorando o valor do
veículo à essa informação), em vez de nas condições de manutenção do
motor e da transmissão, e do veículo em geral.</p>
<p>Com o salário mensal é a mesma coisa: ancoramos trouxamente os números
no contracheque ao nosso bem estar em geral! Quando vem um aumento, o
efeito na felicidade vem e vai, e passa pouco antes ou depois de logo. O
satisfeito seguirá satisfeito e o descontente, descontente (às vezes um
pouco menos, às vezes um pouco mais).</p>
<p>E dinheiro fácil ganhado na loteria pode muito possivelmente ser a pior
coisa que acontece na vida de alguém. Existem inúmeros casos em que os
"sortudos" só se fodem com as consequências, ou porque não sabem
administrar a grana, ou porque perdem a paz porque a família discordou
do melhor jeito de gastar e se volta contra ele, ou porque tem um monte
de malandro querendo se aproveitar. Quantos quiçá prefeririam nunca ter
apostado...</p>
<p>Se o tempo e o dinheiro que as pessoas despendem nesses esquemas de
dinheiro fácil (bolão, tramóia pra Mega Sena, jogatinas online, etc)
fossem usados pra aprender alguma habilidade nova, ou estudar algum
assunto de interesse, provavelmente seria uma fonte maior de felicidade,
bem-estar e, por que não, talvez até de riqueza mesmo. Alguém pode
descobrir que gosta de pintar, bordar, contar histórias, tocar um
instrumento, fazer desenhos/vídeos engraçados, sei lá!, e acabar
arranjando um novo ofício enquanto se diverte!</p>
<p>É bem possível que eu esteja sendo tendencioso escrevendo sobre isso
tudo, porque neste momento estou em transição entre dois empregos, sendo
que o salário no meu emprego atual compreende mais ou menos a metade do
meu salário anterior (obtive um aumento de -50%, yay!). Por causa disso,
muita gente veio me dizer que estou fazendo besteira, arruinando minha
carreira, que não valia a pena, etc e tal. Aparentemente, são bem poucas
as pessoas que sabem que, na verdade, eu não estou sacrificando nada!<br>
Estou só tentando ser feliz.</p>
<p>E quer saber? Só de me dar conta que eu consegui sair de onde eu estava,
e estou indo pra onde estou indo, já me dá um contentamento do caráleo!
:D</p>Vivendo alienado2011-09-21T11:48:00+02:002011-09-21T11:48:00+02:00Elias Dornelestag:eliasdorneles.com,2011-09-21:/2011/09/21/vivendo-alienado.html<p>Não tem problema!</p>
<p>Se eu não reconheço as referências a livros ou filmes supostamente
clássicos ou nunca ouvi a banda que todo mundo conhece, não tem
problema. Se não conheço o último meme do Twitter, nunca assisti o
seriado da moda, nem uso a última versão do software/gadget que …</p><p>Não tem problema!</p>
<p>Se eu não reconheço as referências a livros ou filmes supostamente
clássicos ou nunca ouvi a banda que todo mundo conhece, não tem
problema. Se não conheço o último meme do Twitter, nunca assisti o
seriado da moda, nem uso a última versão do software/gadget que todo
mundo tá usando... tá tudo tranquilo!</p>
<p>Com o passar do tempo, vou percebendo que perdi algumas coisas, mas não
muito.</p>
<p>Eu costumava me importar com ficar boiando nas conversas, não entender
as piadas, e às vezes, não ter a mínima idéia do que os outros tavam
falando...</p>
<p>Todavia, a gente já convive com ruído demais. Temos música e literatura
de vários séculos, filmes de várias décadas, mais o que existe na
Internet, é devastador! Não temos muita opção senão confiar no nosso
filtro nativo.</p>
<p>Tentar se manter atualizado ou "desalienado" custa muito caro, e é um
custo que passa praticamente despercebido.</p>
<p>Os grandes artistas frequentemente usam as mesmas ferramentas a vida
inteira, mudando pouco ou nada, só quando realmente não têm outra opção.
Isso é porque conhecem o custo de um upgrade.</p>
<p>Se eu conseguir me concentrar no que é bom pra mim, tanto melhor.</p>
<p>Meu negócio é viver alienado e desatualizado, mesmo!</p>
<p><a href="http://www.flickr.com/photos/neofob/2462886262/" title="Will this lo-fi studio work? by neofob, on Flickr"><img alt="Will this lo-fi studio
work?" src="https://farm3.static.flickr.com/2104/2462886262_2b438e50c1.jpg"></a><br>
Imagem de: <a href="http://www.flickr.com/photos/neofob/2462886262/">neofob</a></p>Tocar vídeo ou música em outra velocidade mantendo o tom2011-07-28T10:53:00+02:002011-07-28T10:53:00+02:00Elias Dornelestag:eliasdorneles.com,2011-07-28:/2011/07/28/tocar-video-ou-musica-em-outra-velocidade-mantendo-o-tom.html<p>Alguns meses atrás descobri o <a href="http://29a.ch/playitslowly/" title="http://29a.ch/playitslowly/">Play it slowly</a>, um programa para tocar arquivos de áudio em
velocidades ou alturas diferentes, no Linux. Você pode usá-lo para, por
exemplo, ouvir uma música no mesmo tom da original mas com um ritmo bem mais
lento (útil para aprender as notas de um …</p><p>Alguns meses atrás descobri o <a href="http://29a.ch/playitslowly/" title="http://29a.ch/playitslowly/">Play it slowly</a>, um programa para tocar arquivos de áudio em
velocidades ou alturas diferentes, no Linux. Você pode usá-lo para, por
exemplo, ouvir uma música no mesmo tom da original mas com um ritmo bem mais
lento (útil para aprender as notas de um solo complicado), ou ainda ouvir um
<em>podcast</em> numa velocidade um pouco mais rápida sem transformar a voz do
palestrante na de um ratinho. (Tem um equivalente para Windows, <a href="http://bestpractice.sourceforge.net" title="http://bestpractice.sourceforge.net">Best
Practice</a>, grátis e livre assim como o Play it
slowly).</p>
<p>Frequentemente eu preciso fazer algo parecido, mas com um vídeo. A melhor
alternativa que encontrei, até agora, é utilizar o plugin
<a href="http://scaletempo.sourceforge.net" title="http://scaletempo.sourceforge.net">scaletempo</a> do <a href="http://www.mplayerhq.hu" title="http://www.mplayerhq.hu">mplayer</a> (nunca testei, mas acredito que também funcione no
Windows):</p>
<div class="highlight"><pre><span></span><code>mplayer -af scaletempo video.avi
</code></pre></div>
<p>Tendo iniciado o <em>mplayer</em> assim, basta usar os atalhos [ ou ] (abre e
fecha colchetes) para reduzir ou aumentar a velocidade, respectivamente!
Para o <em>mplayer</em> sempre carregar o plugin <em>scaletempo</em> para qualquer
arquivo, coloquei no meu <em>\~/.mplayer/config</em> a diretiva:</p>
<div class="highlight"><pre><span></span><code>af=scaletempo
</code></pre></div>
<p>Era isso! :)</p>Steve Yegge é meu herói!2011-07-28T08:23:00+02:002011-07-28T08:23:00+02:00Elias Dornelestag:eliasdorneles.com,2011-07-28:/2011/07/28/steve-yegge-e-meu-heroi.html<p><a href="https://steve-yegge.blogspot.com" title="https://steve-yegge.blogspot.com">Steve
Yegge</a>
é meu herói!</p>
<p>Já que ele voltou a escrever no blog (dois posts na mesma semana, yay!),
obrigo-me a escrever aqui também. A gente acaba criando uma relação
afetiva com certos feeds, que quando aparece um post novo o seu dia
melhora, nem que seja um pouquinho.</p>
<p>De …</p><p><a href="https://steve-yegge.blogspot.com" title="https://steve-yegge.blogspot.com">Steve
Yegge</a>
é meu herói!</p>
<p>Já que ele voltou a escrever no blog (dois posts na mesma semana, yay!),
obrigo-me a escrever aqui também. A gente acaba criando uma relação
afetiva com certos feeds, que quando aparece um post novo o seu dia
melhora, nem que seja um pouquinho.</p>
<p>De quando em vez, eu faço uma limpa nos meus feeds, e removo os que
estão com muito ruído, ou que eu não esteja mais interessado, ou ainda,
que dá pra arriscar ficar desinformado. Mas o feed do Mr. Yegge veio pra
ficar. Mesmo que ele poste somente uma vez por ano. <em>Take all the time
you want, Steve! No need to hurry, we'll be listening. We are glad
you're back, but you don't need to care. Just... thanks, man! :)<br>
</em></p>
<p>Por causa desse senhor Yegge, eu acabei aprendendo algumas coisas
imporantes. Eu certamente não sou importante, e talvez essas coisas
acabem não sendo tão importantes assim, mas é que, nos contextos que eu
estive, essas coisas foram importantes pra mim. O problema é que, o
tempo vai passando, e eu vou achando que já aprendi essas coisas
importantes, e aí vou esquecendo, devagaritcho. Quando percebo, oh boy,
tô fazendo tudo errado, de novo!</p>
<p>Talvez a mentalidade correta seria, eu ainda estou aprendendo. É isso!
Então, por causa do senhor Yegge, eu acabei não aprendendo coisas
importantes, mas acabei aprendendo que elas são importantes, e que eu
preciso seguir tentando aprender.</p>
<p>Por isso, que eu tô indo reler novamente os rants antigos do Steve, pra
aprender que <a href="https://steve-yegge.blogspot.com/2008/06/done-and-gets-things-smart.html" title="https://steve-yegge.blogspot.com/2008/06/done-and-gets-things-smart.html">sou um péssimo programador e preciso aprender com os
melhores que
eu</a>, <a href="https://steve-yegge.blogspot.com/2008/02/portrait-of-n00b.html" title="https://steve-yegge.blogspot.com/2008/02/portrait-of-n00b.html">não
devo ter medo de
código</a>,
<a href="https://steve-yegge.blogspot.com/2008/08/business-requirements-are-bullshit.html" title="https://steve-yegge.blogspot.com/2008/08/business-requirements-are-bullshit.html">o melhor jeito de escolher projetos é fazer pra mim
mesmo</a>,
<a href="https://steve-yegge.blogspot.com/2007/06/rich-programmer-food.html" title="https://steve-yegge.blogspot.com/2007/06/rich-programmer-food.html">compiladores importam e eu tenho que escrever
um</a>,
<a href="https://steve-yegge.blogspot.com/2009/04/have-you-ever-legalized-marijuana.html" title="https://steve-yegge.blogspot.com/2009/04/have-you-ever-legalized-marijuana.html">o tempo que leva é o tempo que
leva</a>,
e o resto que eu uh... esqueci já! Tá vendo? Eu preciso mesmo reler!</p>
<p>Espero que o Steve Yegge não se importe que eu descreva o blog dele
quase como um livro de auto-ajuda. Mas... pra mim funciona. Então,
licençinha, que os rants são compriditos!</p>Economia vs. Consumo2011-02-03T12:53:00+01:002011-02-03T12:53:00+01:00Elias Dornelestag:eliasdorneles.com,2011-02-03:/2011/02/03/economia-vs.-consumo.html<p>Dias atrás estava debatendo com alguns amigos, tentando demonstrar como não era
muito intuitivo o jeito que acostumamos a pensar sobre consumo de combustível,
para efeito de comparação. Perguntei a eles o que fariam se tivessem dois
carros, um sedã que fizesse 10km/L e uma camionete que fizesse 5km …</p><p>Dias atrás estava debatendo com alguns amigos, tentando demonstrar como não era
muito intuitivo o jeito que acostumamos a pensar sobre consumo de combustível,
para efeito de comparação. Perguntei a eles o que fariam se tivessem dois
carros, um sedã que fizesse 10km/L e uma camionete que fizesse 5km/L, e
tivessem que escolher entre o upgrade da camionete para uma que fizesse 10km/L
ou o upgrade do sedã para um que fizesse 35km/L. Todos me disseram que iriam
obviamente com a segunda opção.</p>
<p>Levou-me algum tempo para conseguir explicar que provavelmente seria uma má
decisão, pois se ambos os carros fossem usados para as mesmas viagens, a
primeira opção (upgrade da camionete) é a mais econômica. Veja nessa tabela os
valores do consumo de combustível para andar 100km com cada carro, calculado
para os dois upgrades:</p>
<div class="highlight"><pre><span></span><code><span class="c"> Consumo da camionete Consumo do sedã Consumo total</span>
<span class="nb">-----------</span><span class="c"> </span><span class="nb">----------------------</span><span class="c"> </span><span class="nb">-------------------------</span><span class="c"> </span><span class="nb">---------------</span>
<span class="c">Upgrade 1 100km / 10km/L = 10L 100km / 10km/L = 10L 20L</span>
<span class="c">Upgrade 2 100km / 5L = 20L 100km / 35km/L =\~ 2</span><span class="nt">,</span><span class="c">8L 22</span><span class="nt">,</span><span class="c">8L</span>
</code></pre></div>
<p>Como se pode ver, o upgrade da camionete é a solução ótima, pois utiliza menos
combustível para os dois carros percorrendo as mesmas distâncias.
Evidentemente, a coisa seria diferente se você pudesse usar mais o sedã e menos
a camionete para fazer o upgrade valer a pena. Contudo, esse não é o foco do
exercício (afinal, se você não precisasse da camionete, você sempre poderia
aposentá-la, usar apenas o sedã para tudo e obteria um resultado equivalente ao
Upgrade 1). O problema em foco aqui é que estamos mais acostumados a pensar na
medida de economia (tantos quilômetros com um litro), e por isso pensamos
automaticamente em “quantos quilômetros conseguiremos fazer com X litros?”.
Porém, se estivéssemos pensando em uma medida de consumo (litros necessários
para tantos quilômetros), a pergunta seria “se eu andar 10km por dia com os
dois carros, quantos litros de combustível vou gastar?”, que representa melhor
o problema apresentado.</p>
<p>A ideia é que para comparar automóveis em relação a consumo de combustível, é
melhor utilizar uma unidade de consumo que represente a quantidade de
combustível necessária para preencher determinada distância (L/100km ou GPM) em
vez da unidade de economia (km/L ou MPG), como já é feito em alguns países. O
centro da questão é que uma melhora modesta na economia de um veículo
ineficiente resulta em uma economia bem maior do que uma melhora na mesma
proporção em um veículo relativamente eficiente, e a unidade de medida de
consumo deixa isso bem mais aparente.</p>
<p>Alguém pode pensar que a diferença entre um carro que anda 5km/L e outro que
anda 6km/L seria equivalente à diferença entre um carro que anda 10km/L e outro
que anda 12km/L já que a diferença entre estes é na mesma proporção (aumento de
20% na economia). Contudo, observe a tabela a seguir, que relaciona essas
medidas de economia e suas equivalentes em consumo (litros necessários para
cada 100km):</p>
<div class="highlight"><pre><span></span><code>km/L 5 6 10 12 20 24
L/100km 20 16,6 10 8,3 5 4,16
</code></pre></div>
<p>Repare que apesar da proporção existente entre as diferenças de duas medidas
(aumento de economia de 20%), o valor do consumo varia de forma diferente: a
primeira diferença representa uma economia de 3,4 litros a cada 100km; a
segunda, economia de 1,17 litros a cada 100km; e a terceira, economia de menos
de 1 litro a cada 100km.</p>
<p>Concluindo, comparar o consumo de combustíveis para veículos diferentes merece
uma boa dose de atenção devido a esses detalhes, e embora decidir qual opção é
mais econômica seja discussão específica para cada caso, uma coisa fica clara:
a melhora da economia de um carro ineficiente é em geral, bem melhor que a
melhora para um carro mais eficiente. Ou ainda, um carro que faz 12km/L é
melhor que um carro que faz 10km/L, mas não tão melhor quanto um carro que faz
10km/L é melhor que um carro que faz 8km/L. :)</p>
<p>A Wikipedia em inglês tem uma seção sobre o assunto:
<a href="http://en.wikipedia.org/wiki/Fuel_economy_in_automobiles#Units_of_measure">http://en.wikipedia.org/wiki/Fuel_economy_in_automobiles#Units_of_measure</a></p>
<p><strong>Editado:</strong> correção dos números (grazie, Zé).</p>