tag:blogger.com,1999:blog-3960833820341744392024-03-12T16:39:17.500-07:00RodolfoCarvalho.netRodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.comBlogger169125tag:blogger.com,1999:blog-396083382034174439.post-5041277160632470432019-04-24T09:11:00.001-07:002019-04-24T09:11:11.344-07:00Moving to a new addressFuture posts will go to <a href="https://www.rodolfocarvalho.net/blog/">https://www.rodolfocarvalho.net/blog/</a>.Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-90978279701386107392019-02-18T10:44:00.001-08:002019-02-18T10:44:35.200-08:00Free Software for Web AnalyticsThis is a personal note. I've been looking for a Google Analytics replacement. These are alternatives to Google Analytics I came across today:<br />
<br />
<ul>
<li>Nothing. Yes, nothing. Simply do not track anything, that may be the best way to go as it respects visitors' privacy.</li>
<li><a href="https://www.awstats.org/" target="_blank">AWStats</a>: ugly for modern standards. Based on log files. I recall experimenting with this several years ago. It may be a fine solution to avoid adding JavaScript snippets to a site.</li>
<li>JavaScript-based and self-hosted:</li>
<ul>
<li><a href="https://matomo.org/" target="_blank">Matomo</a> (previously called Piwik): seems to be the best of its kind. Well maintained, full of features. Big focus on its commercial offering of hosted service. <a href="https://github.com/matomo-org/matomo" target="_blank">Matomo on GitHub</a>.</li>
<li><a href="http://www.openwebanalytics.com/" target="_blank">Open Web Analytics</a> (OWA): looks less fancy. Seems to be more community oriented, no business around. <a href="https://github.com/padams/Open-Web-Analytics" target="_blank">Open Web Analytics on GitHub</a>.</li>
<li><a href="https://usefathom.com/" target="_blank">Fathom</a>: maybe the newest kid in the neighborhood. Built with Go and Preact (a smaller React-compatible JS library, first time I hear of it). <a href="https://github.com/usefathom/fathom" target="_blank">Fathom on GitHub</a>.</li>
</ul>
</ul>
<div>
Other pieces of software might be worth a look. No software also deserves a lot of consideration.</div>
<div>
<br /></div>
See a <a href="https://en.wikipedia.org/wiki/List_of_web_analytics_software" target="_blank">list of web analytics software on Wikipedia</a> for more.Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-41290869010763984632019-01-24T13:24:00.000-08:002019-01-24T13:24:46.832-08:00Installing Flutter and Android Studio on Fedora 29Since neither Flutter nor Android Studio come as regular packaged applications, I am installing them under ~/opt/android. Android Studio installs the Android SDK at ~/Android/Sdk, and creates projects at ~/AndroidStudioProjects.<br />
<br />
Download <a href="https://flutter.io/docs/get-started/install/linux" target="_blank">Flutter</a> and <a href="https://developer.android.com/studio" target="_blank">Android Studio</a>.<br />
<br />
$ mkdir -p ~/opt/android<br />
<br />
<h3>
Android Studio installation</h3>
<span style="font-family: Courier New, Courier, monospace;">$ unzip ~/Downloads/android-studio-ide-182.5199772-linux.zip 'android-studio/*' -d ~/opt/android</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ cd ~/opt/android/android-studio/bin/</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ ./studio.sh</span><br />
<br />
Follow the wizard accepting defaults.<br />
<br />
Tools > Create Command-line Launcher, at <span style="font-family: Courier New, Courier, monospace;">~/bin/studio</span>.<br />
Tools > Create Desktop Entry<br />
<br />
I <b>did not</b> install the libraries that are said to be required (zlib.i686 ncurses-libs.i686 bzip2-libs.i686). So far they did not seem to be missed.<br />
<br />
<a href="https://flutter.io/docs/get-started/install/linux#set-up-the-android-emulator" target="_blank">Set up the Android emulator</a>. I added two virtual devices, both are Pixel 2 with API 28, Android 9.0 with Google Play. One is x86 and the other is x86_64. Not clear which one will give better performance.<br />
<br />
<h3>
Flutter installation</h3>
<span style="font-family: Courier New, Courier, monospace;">$ tar -C ~/opt/android -xf ~/Downloads/flutter_linux_v1.0.0-stable.tar.xz flutter</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ ln -s ~/opt/android/flutter/bin/flutter ~/bin/</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ flutter doctor</span><br />
<span style="font-family: Courier New, Courier, monospace;">$ sudo dnf install libstdc++.i686</span><br />
<br />I am a bit puzzled and hesitant to accept licenses that <span style="font-family: Courier New, Courier, monospace;">flutter doctor --android-licenses</span> says need to be accepted.<div>
<br /></div>
<div>
4 of 5 SDK package licenses not accepted</div>
<div>
<br /><div>
They are:</div>
<div>
<ul>
<li>1/4: License android-googletv-license</li>
<li>2/4: License android-sdk-preview-license</li>
<li>3/4: License google-gdk-license</li>
<li>4/4: License mips-android-sysimage-license</li>
</ul>
I guess I'll need to surrender :-(<br />
<br />
Now on Android Studio, install the Dart and Flutter plugins.<br />
<br />
<br />
Let the Android hacking begin!<br />
<br /></div>
</div>
Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-48145177659079329732019-01-23T11:29:00.000-08:002019-01-23T11:29:40.212-08:00Lenovo X1 Carbon 6th Gen - personal notesPersonal notes configuring my Lenovo X1 Carbon 6th Generation laptop.<br />
The computer was bought in July 2018, and at the time there were unfortunate power management issues on Linux, as described in the <a href="https://wiki.archlinux.org/index.php/Lenovo_ThinkPad_X1_Carbon_(Gen_6)" target="_blank">Arch Wiki</a>.<br />
<br />
This post is based on simple notes I took while setting things up.<br />
<br />
<h3>
BIOS configuration changes</h3>
<br />
<ul>
<li>Disable WoL and UEFI network stack</li>
<li>Disable Wake by Thunderbolt 3</li>
<li>Disable Card Reader and Fingerprint Reader</li>
<li>Disable Computrace module activation</li>
<li>Enable Intel TXT security feature</li>
<li>Disable AMT (ctrl-P)</li>
</ul>
<br />
<h3>
Install Fedora 28</h3>
Tune GRUB2 timeout for faster boots: edit /etc/default/grub, TIMEOUT=1<br />
<h4>
Power management</h4>
Trying to counter the suspend issue that caused the battery to drain very quick, IIRC in about one or two hours, with the laptop warm when the lid was closed., I went on to install some tools:<br />
<br />
dnf install powertop<br />
dnf install tlp tlp-rdw<br />
<br />
https://linrunner.de/en/tlp/docs/tlp-linux-advanced-power-management.html#fedora<br />
<br />
sudo dnf install akmod-tp_smapi akmod-acpi_call<br />
sudo dnf install smartmontools <br />
<br />
sudo vi /etc/defaults/tlp RESTORE_DEVICE_STATE_ON_STARTUP=1<br />
<br />
I believe these are not necessary with newer kernels and newer BIOS firmware (currently on 1.34).<br />
<br />
<h4>
Other configuration</h4>
Configure name, and background and lock screen<br />
<br />
$ hostnamectl --static set-hostname crater.local<br />
<br />
Install RPM Fusion repos<br />
Install Dropbox<br />
<br />
To get the Dropbox icon on the top bar, install (K)StatusNotifierItem/AppIndicator Support<br />
<br />
<h3>
After about 6 months of usage</h3>
<div>
The few notes in this post baked for a long time. Now, about 6 months since I unboxed the laptop here's what happened:</div>
<div>
<br /></div>
<div>
<ul>
<li>I have used the laptop very lightly while travelling</li>
<li>Was very frustrated for not being able to suspend</li>
<li>Suspend issue was fixed by BIOS 1.30, got the upgrade through Gnome Software Center and LVFS</li>
<li>There was a growing discontent with Thunderbolt 3, it seemed that enabling it caused boot times and wake from sleep extremely slow, taking 30+ seconds in both cases</li>
<li>I have upgraded to Fedora 29</li>
<li>At around 20:48 UTC on Jan 6, 2019 the laptop produced its last log line and would not boot anymore</li>
<li>On the following day, Monday, I contacted the Lenovo support to claim my warranty, and started a lengthy process until I got my machine back from their repair center on Jan 22</li>
<li>They had to replace the motherboard, dead. The note said "reset problem"</li>
<li>I upgraded the BIOS on the new motherboard (was 1.27) to 1.34 and the Intel ME firmware (was 11.8.50.3425) to 11.8.55.3510</li>
<li>Fine tuned BIOS settings, and thus far have not observed the slow boot/wake up like in the faulty motherboard:</li>
<ul>
<li>Disable Wake On LAN</li>
<li>Disable UEFI Networks Stacks</li>
<li>Power > Sleep State = Linux</li>
<li>Thunderbolt BIOS Assist Mode = Disabled (not changed from factory, until I determine if enabling is really needed with the current firmware/kernel combination)</li>
<li>Disable Wake by Thunderbolt</li>
<li>Disable Intel AMT by pressing ctrl-p when the Lenovo logo shows up, then set a MEBx password and disable AMT management features (I so much wish Intel ME and all other features were not there in the first place...)</li>
<li>Enable Virtualization features</li>
<li>Disable ports: Ethernet LAN, Wireless WAN, Memory Card Slot, Fingerprint Reader</li>
<li>Disable Computrace</li>
<li>Keep Secure Boot disabled</li>
<li>Disable Intel SGX</li>
<li>Boot only using UEFI, disable CSM</li>
</ul>
</ul>
<div>
<br /></div>
</div>
<div>
I hope the system will survive more usage.</div>
Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-60170797999469491862018-07-20T17:20:00.000-07:002018-07-20T17:20:08.872-07:00How Complex Systems FailHighlights from <a href="http://web.mit.edu/2.75/resources/random/How%20Complex%20Systems%20Fail.pdf" target="_blank">How Complex Systems Fail</a>:<br />
<br />
<br />
<ul>
<li>Title) How Failure is Attributed to Proximate Cause</li>
<li>1) It is the presence of these hazards
that drives the creation of defenses against hazard that characterize these systems</li>
<li>2) multiple layers of
defense</li>
<li>3) Catastrophe requires multiple failures</li>
<li>4) Eradication of all latent failures is limited
primarily by economic cost but also because it is difficult before the fact to see how such
failures might contribute to an accident</li>
<li>5) complex systems run as broken systems</li>
<li>5) The
system continues to function because it contains so many redundancies and because
people can make it function, despite the presence of many flaws</li>
<li>6) It is impossible to eliminate the potential for
such catastrophic failure</li>
<li>7) Post-accident attribution accident to a ‘root cause’ is fundamentally wrong</li>
<li>7) There are multiple contributors to accidents</li>
<li>7) social, cultural need to blame
specific, localized forces or events for outcomes</li>
<li>8) Knowledge of the outcome makes it seem that events leading to the outcome should have
appeared more salient to practitioners at the time than was actually the case</li>
<li>8) It seems that practitioners “should
have known”</li>
<li>9) dual roles</li>
<li>9) Outsiders rarely acknowledge the duality of this role</li>
<li>11) After an accident, practitioner
actions may be regarded as ‘errors’ or ‘violations’</li>
<li>11) biased by hindsight and ignore the other driving forces, especially production pressure</li>
<li>13) Human expertise in complex systems is constantly changing</li>
<li>13) need to replace experts who leave</li>
<li>14) Change introduces new forms of failure</li>
<li>14) overt: open and observable</li>
<li>14) use of new technology</li>
<li>14) decrease the number of low consequence but high frequency
failures</li>
<li>14) create opportunities for new, low frequency but
high consequence failures</li>
<li>14) Not uncommonly, these new, rare
catastrophes have even greater impact than those eliminated by the new technology</li>
<li>14) hard to see the contribution of technology to the failure</li>
<li>What to do? Freeze a system from all and any change?</li>
<li>15) post-accident remedies usually increase the coupling and complexity</li>
<li>16) Safety is a characteristic of systems and not of their components</li>
<li>18) Failure free operations require experience with failure</li>
<li>"Game day" and failure injection</li>
</ul>
<br />
<br />
<br />Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-14758218432524658762018-07-20T16:35:00.003-07:002018-07-20T16:36:17.198-07:00Learning vi: mental notesThough I use vi here and there for several years now, there's always some new trick to learn.<br />
Lately I've had on my desk the book Learning the vi editor by Linda Lamb, published by O'Reilly.<br />
<br />
Here I list, in no particular order, some notes as a way to reinforce what I've learned from the book. The focus is on things that called my attention, were new to me and/or that were not internalized yet in my day-to-day usage.<br />
<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">vi versus/and ex</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">ZZ = save and exit = :wq (ex command)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">:e! = reload from disk</span><span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">~ = toggle case</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">xp = transpose two characters</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">0 = go to beginning of line (same as ^)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">W = move to the beginning of the next word, ignoring punctuation</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">B = move to the beginning of the previous word, ignoring punctuation</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">e = move to the end of the next word</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">E = move to the end of the next word, ignoring punctuation</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">. = repeat last command</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Y = yy</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">P = put text before cursor</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">D = d$</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">C = c$</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">X = delete character before cursor</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">cc = change line = ddO = 0D</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">"3p = put contents of buffer number 3 (not the last buffer)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">U = undo all edits on a single line</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">A = append at the end of the line</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">I = insert at the beginning of the line</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">s = c+space = xi = substitute character</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">S = cc = substitute line</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">50i*<esc> = insert 50 times *</esc></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">ea = append to the end of a word</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">J = join consecutive lines</span>Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-51716843722762937622018-06-12T13:07:00.002-07:002018-06-12T13:07:54.500-07:00Quick and easy statistics with Python 3Today I discovered that Python 3 (starting with 3.4) includes a new module in the standard library: statistics!<br />
<br />
The full docs: <a href="https://docs.python.org/3/library/statistics.html">https://docs.python.org/3/library/statistics.html</a><br />
<br />
It is a useful library for quick explorations in the terminal. Fire an <a href="https://ipython.org/" target="_blank">iPython</a> shell, gather some data in a list, e.g. k, and then:<br />
<br />
<div class="p2">
<span class="s1">In [</span><span class="s2"><b>8</b></span><span class="s1">]: <b>import</b></span><span class="s3"> </span><span class="s4"><b>statistics</b></span></div>
<div class="p1">
<span class="s1"></span><br /></div>
<div class="p3">
<span class="s5">In [</span><span class="s2"><b>9</b></span><span class="s5">]: </span><span class="s1">statistics.mean(k)</span></div>
<div class="p3">
<span class="s6">Out[</span><span class="s7"><b>9</b></span><span class="s6">]: </span><span class="s1">354.2944444444444</span></div>
<div class="p1">
<span class="s1"></span><br /></div>
<div class="p3">
<span class="s5">In [</span><span class="s2"><b>10</b></span><span class="s5">]: </span><span class="s1">statistics.stdev(k)</span></div>
<div class="p3">
<span class="s6">Out[</span><span class="s7"><b>10</b></span><span class="s6">]: </span><span class="s1">29.47088274648779</span></div>
<br /><br />
<br />
Profit!<br />
<style type="text/css">
p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo; color: #000000; background-color: #ffffff; min-height: 21.0px}
p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo; color: #34a327; background-color: #ffffff}
p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo; color: #000000; background-color: #ffffff}
span.s1 {font-variant-ligatures: no-common-ligatures}
span.s2 {font-variant-ligatures: no-common-ligatures; color: #2ee721}
span.s3 {font-variant-ligatures: no-common-ligatures; color: #000000}
span.s4 {font-variant-ligatures: no-common-ligatures; color: #3c9ff2}
span.s5 {font-variant-ligatures: no-common-ligatures; color: #34a327}
span.s6 {font-variant-ligatures: no-common-ligatures; color: #b23622}
span.s7 {font-variant-ligatures: no-common-ligatures; color: #ff3b1e}
</style>Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-7151111016522776922018-04-30T23:28:00.001-07:002018-04-30T23:28:43.024-07:00Go Exceptions: An Introduction<div style="background: #E8AC41; border-radius: 0.25em; margin-bottom: 0.5em; padding: 0.8em;">
Estimated reading time: 12 seconds.
</div>
<div style="background: #f6f6f6; border-radius: 0.25em; padding: 0.8em;">
Table of Contents<br />
<ul>
<li> </li>
</ul>
</div>
<br />
<i>[this section intentionally left blank]</i><br />
<br />
<h4>
Summing Up</h4>
Unlike many other languages, there are no exceptions in the Go programming language.<br />
<br />
<hr />
<div style="color: #cccccc;">
This post was inspired by the much lengthier <a href="https://realpython.com/python-exceptions/" target="_blank">Python Exceptions: An Introduction</a>.</div>
Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-83401315508333233612017-11-10T16:20:00.001-08:002017-11-14T16:15:43.669-08:00zsh - the Z ShellAfter years using Bash, and doing more Bash scripting than I ever wanted in the last 2½ years, yesterday I switched to Zsh.<br />
<br />
Why? Just because. I got it as my default shell in one remote host, and then decided to install it locally and take the opportunity to learn something new.<br />
<br />
I'll be searching a lot for "how do I do X in zsh?"<br />
<br />
The interesting things I did today already:<br />
<ol>
<li>Setup <a href="https://github.com/sorin-ionescu/prezto">prezto</a>; what seems to be a (better?) alternative to the famous "<a href="http://ohmyz.sh/">oh-my-zsh</a>"</li>
<li>Answered an StackOverflow question about zsh! <a href="https://stackoverflow.com/a/47232956/4804690">How can I pause in zsh?</a></li>
<li>Figured out how to get the path to the directory containing the current script: <code><strike>${${(%):-%N}:h}</strike> ${${(%):-%x}:h:a}</code>
<br />Update Nov/14:<br /><ul>
<li>Using <code>%x</code> instead of <code>%N</code> makes it work within a function;</li>
<li><code>:a</code> makes the path absolute.</li>
</ul>
</li>
</ol>
<br />
As the last item shows, there is some <code>man zsh</code> going on instead of <code>man bash</code> now.Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-54261080435310724462017-09-12T05:33:00.000-07:002017-09-12T05:33:12.718-07:00Visualizing pull request merge cadenceThis summer I had the pleasure to mentor Martin Nečas, a talented student from <a href="http://www.sspbrno.cz/">Střední průmyslová škola Brno, Purkyňova</a> (a high school in Brno, CZ).<br />
Martin has so many interests and wishes to learn everything that he can, and delivers on doing so, what makes me appreciate his eagerness for knowledge.<br />
<br />
His summer internship project at <a href="https://www.redhat.com/">Red Hat</a> was to enable developers to visualize the time it takes to merge <i>Pull Requests</i> in GitHub repositories. In particular, we intended to use that to understand the healthiness of the merge processes in <a href="https://www.openshift.org/">OpenShift</a>-related repositories, and to serve as a guide to gauge the effects of changes to the said processes.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://imgur.com/a/JyoAv"><img height="300" src="http://i.imgur.com/Xi40gzw.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><a href="http://martin.codingkwoon.com/openshift/origin/">http://martin.codingkwoon.com/openshift/origin/</a></td></tr>
</tbody></table>
<br />
It all started back in early May, and in the first weeks Martin took the time to learn about OpenShift, containers, Linux and Python. He has been using <a href="https://getfedora.org/">Fedora</a> on his laptop since then, and I know he really enjoys it, specially when he discovers new ways of doing things in the command line.<br />
<br />
Due to my time constraints, it was only in June 1 when we started discussing his project in more detail. He was quick to grasp the idea and kept coming back with working prototypes. At first he was sold on learning Go, but then decided to stick with Python and Django and leverage his pre-existing skills.<br />
<br />
His open source project <a href="https://github.com/ocasek/GithubGraphs">GithubGraphs</a> can be seen live at <a href="http://martin.codingkwoon.com/">http://martin.codingkwoon.com</a>, it is a web application that communicates with GitHub through its GraphQL API to fetch data about PRs and stores it locally to generate interactive visualizations. It is worth noting Martin's ability to play with the GitHub v3 REST API, and then, once he realized the downsides of using it, learning about GraphQL and using it effectively to improve the performance of the project.<br />
<br />
This project also let Martin write much more JavaScript code than he has ever written before! And he did it well. Through several iterations, collecting feedback from different sources, he got to a good looking and functional design, well done!<br />
<br />
In August, Martin reached out to OpenShift developers to <a href="https://lists.openshift.redhat.com/openshift-archives/dev/2017-August/msg00065.html">announce his project publicly</a> and get feedback. The reception was positive. Now I wish the original goals of the project will be fulfilled.<br />
<br />
As we wrap up our collaboration, Martin is looking for new projects and more exciting times at Red Hat. Good luck!<br />
<br />
<br />
Martin's GitHub profile: <a href="https://github.com/ocasek">https://github.com/ocasek</a><br />
Martin's blog: <a href="http://mnecas.blogspot.cz/">http://mnecas.blogspot.cz/</a>Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-3752844031330158162017-04-06T01:52:00.003-07:002017-04-06T01:52:47.526-07:00Go types and assignabilityYesterday, during our weekly <a href="https://dojo-brno.github.io/">coding dojo</a>, we had a bit of a puzzling moment when we realized one of the <a href="https://golang.org/ref/spec#Assignability">rules of assignability in Go</a>.<br />
<br />
A coding dojo is a suitable place for these "aha" moments, because we have freedom to try things and take the time to understand details that we could possibly otherwise let go and simply never come across.<br />
<br />
<h3>
On the assignability of values with identical underlying types</h3>
<br />
When writing <a href="https://github.com/golang/go/wiki/TableDrivenTests">table tests in Go</a>, it is a common idiom to have a slice of structs to hold data for each test case. Our struct had a field of a custom type, a tic-tac-toe <code>Game</code>, and the underlying type was a slice of slice of ints (<code>[][]int</code>).<br />
<br />
We experimented with different ways of writing a <a href="https://golang.org/ref/spec#Composite_literals">composite literal</a> to create a value holding all test cases including the <span style="font-family: monospace;">Game</span> field.<br />
<br />
This was what we eventually committed after the dojo: <a href="https://github.com/dojo-brno/dojo-brno/blob/ec307ae56dc5d75364d0e91fe393956a8f0772b7/2017/2017-04-05/tictactoe/tictactoe_test.go#L6-L18">tictactoe_test.go#L6-L18</a>. However, a single Git commit does not capture all the alternatives we tried.<br />
<br />
<a href="https://play.golang.org/p/iVVPxxSC_4">This Go Playground snippet</a> shows how we can use <span style="font-family: monospace;">Game</span> and <span style="font-family: monospace;">[][]int</span> interchangeably in the context of an assignment, and why we can do it I highlight in this quote from <a href="https://golang.org/ref/spec#Assignability">The Go Programming Language Specification</a>:<br />
<blockquote class="tr_bq">
<blockquote class="tr_bq">
A value x is assignable to a variable of type T ("x is assignable to T") in any of these cases:</blockquote>
<blockquote class="tr_bq">
<ul>
<li>x's type is identical to T.</li>
<li><b>x's type V and T have identical underlying types and at least one of V or T is not a named type.</b></li>
<li>T is an interface type and x implements T.</li>
<li>x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a named type.</li>
<li>x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.</li>
<li>x is an untyped constant representable by a value of type T.</li>
</ul>
</blockquote>
</blockquote>
<span style="font-family: monospace;">Game</span> and <span style="font-family: monospace;">[][]int </span>have identical underlying types (<span style="font-family: monospace;">[][]int</span>), as follows from the <a href="https://golang.org/ref/spec#Types">definition of types</a>:<br />
<blockquote class="tr_bq">
Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its type declaration.</blockquote>
And <span style="font-family: monospace;">[][]int</span> is not a named type, thus satisfying the assignability rule.<br />
<b><br /></b>
<b>The rule applies recursively!</b><br />
<div>
<br /></div>
<div>
Yes, it also works if we have intermediate named types, for example if we would <a href="https://play.golang.org/p/gOlGffnEsX">define <span style="font-family: monospace;">Game</span> as a slice of <span style="font-family: monospace;">Row</span></a>.</div>
<div>
<br /></div>
<h3>
What does not work</h3>
<div>
<br /></div>
<div>
It is as well interesting to explore what is not allowed by the assignability rules.</div>
<br />
<b>Two named types with the same underlying type are NOT directly assignable</b><br />
<div>
<br /></div>
<div>
We need at least one of the types involved in an assignment to be unnamed, see how <a href="https://play.golang.org/p/5updqRIPBT">this snippet failed to compile</a>.</div>
<div>
<br /></div>
<div>
Note, however, that an explicit <a href="https://golang.org/ref/spec#Conversions">conversion</a> is <a href="https://play.golang.org/p/qrmoE9xqd8">possible</a>.</div>
<div>
<br /></div>
<div>
I think this is reasonable, because two named types can have completely different method sets, and we don't want implicit type conversions... well, the reason why I said assignability was "puzzling" at the very beginning is that it would be probably okay if a <span style="font-family: monospace;">[][]int </span>literal was not assignable to a <span style="font-family: monospace;">Game</span>. I suspect the reason that assignment is possible has to do with either convenience or some implication for the type system I have not thought of.</div>
<div>
<br /></div>
<div>
So that's the summary of one of the things we learned in the <a href="https://dojo-brno.github.io/">dojo</a> yesterday. Did you know about it? Was it useful?</div>
<div>
<br /></div>
Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-4770654338934267622017-03-20T09:34:00.000-07:002017-03-20T09:34:18.279-07:00Indentation styles<h2 style="background-color: white; border-bottom: 1px solid rgb(234, 236, 239); box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; line-height: 1.25; margin-bottom: 16px; margin-top: 0px !important; padding-bottom: 0.3em;">
pro-tip for indentation style</h2>
<h3 style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
Style 1: bad</h3>
<div class="highlight highlight-source-python" style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px; overflow: visible !important;">
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; font-stretch: normal; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"> docker_or_rpm_images.update(<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">self</span>.qualified_docker_images(<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">self</span>.image_from_base_name(image_base_name),
<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box;">"</span>v<span class="pl-pds" style="box-sizing: border-box;">"</span></span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">+</span> openshift_image_tag))</pre>
</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
Suppose during a refactor we rename <code style="background-color: rgba(27, 31, 35, 0.0470588); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">docker_or_rpm_images</code> -> <code style="background-color: rgba(27, 31, 35, 0.0470588); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">images</code>, result:</div>
<div class="highlight highlight-source-python" style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px; overflow: visible !important;">
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; font-stretch: normal; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"> images.update(<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">self</span>.qualified_docker_images(<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">self</span>.image_from_base_name(image_base_name),
<span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box;">"</span>v<span class="pl-pds" style="box-sizing: border-box;">"</span></span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">+</span> openshift_image_tag))</pre>
</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
Bad indentation... this style is painful to maintain.</div>
<h3 style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 1.25em; line-height: 1.25; margin-bottom: 16px; margin-top: 24px;">
Style 2: better</h3>
<div class="highlight highlight-source-python" style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px; overflow: visible !important;">
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; font-stretch: normal; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"> docker_or_rpm_images.update(
<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">self</span>.qualified_docker_images(<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">self</span>.image_from_base_name(image_base_name), <span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box;">"</span>v<span class="pl-pds" style="box-sizing: border-box;">"</span></span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">+</span> openshift_image_tag))</pre>
</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
Suppose during a refactor we rename <code style="background-color: rgba(27, 31, 35, 0.0470588); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">docker_or_rpm_images</code> -> <code style="background-color: rgba(27, 31, 35, 0.0470588); border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; margin: 0px; padding: 0.2em 0px;">images</code>, result:</div>
<div class="highlight highlight-source-python" style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px; overflow: visible !important;">
<pre style="background-color: #f6f8fa; border-radius: 3px; box-sizing: border-box; font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace; font-size: 11.9px; font-stretch: normal; line-height: 1.45; overflow: auto; padding: 16px; word-break: normal; word-wrap: normal;"> images.update(
<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">self</span>.qualified_docker_images(<span class="pl-c1" style="box-sizing: border-box; color: #0086b3;">self</span>.image_from_base_name(image_base_name), <span class="pl-s" style="box-sizing: border-box; color: #183691;"><span class="pl-pds" style="box-sizing: border-box;">"</span>v<span class="pl-pds" style="box-sizing: border-box;">"</span></span> <span class="pl-k" style="box-sizing: border-box; color: #a71d5d;">+</span> openshift_image_tag))</pre>
</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
We still have a long and apparently complicated line, but this time the indentation stays consistent, no need to update adjacent lines to the one that was automatically changed with the rename.</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px; margin-bottom: 16px;">
For more details:</div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px;">
<a href="https://youtu.be/ZsHMHukIlJY?t=17m7s" style="background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;">https://youtu.be/ZsHMHukIlJY?t=17m7s</a><br style="box-sizing: border-box;" /><a href="http://www.slideshare.net/Kevlin/seven-ineffective-coding-habits-of-many-programmers/27" style="background-color: transparent; box-sizing: border-box; color: #0366d6; text-decoration-line: none;">http://www.slideshare.net/Kevlin/seven-ineffective-coding-habits-of-many-programmers/27</a></div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px;">
<br /></div>
<div style="background-color: white; box-sizing: border-box; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; font-size: 14px;">
(post content extracted from a <a href="https://github.com/openshift/openshift-ansible/pull/3461#discussion_r106629152">PR I was reviewing recently</a>)</div>
Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-66605950172353224362017-01-30T08:38:00.001-08:002017-01-30T08:40:07.081-08:00Do not squash commits mindlessly!I've always wanted to write about my frustration with projects and code reviewers that insist on mindlessly squashing all commits of a pull request before merge, instead of accepting well factored commits.<br />
<br />
Because I've just come across a blog post from Matthew Garrett about the same topic, I'll cite him:<br />
<br />
<a href="http://mjg59.dreamwidth.org/42759.html">http://mjg59.dreamwidth.org/42759.html</a><br />
<br />
<blockquote class="tr_bq">
<span style="background-color: white; color: #3e3e3e; font-family: "trebuchet ms" , "arial" , sans-serif; font-size: 16px;">(...) When you're crafting commits for merge, think about your commit history as a textbook. Start with the building blocks of your feature and make them one commit. Build your functionality on top of them in another. Tie that functionality into the core project and make another commit. Add client support. Add docs. Include your tests. Allow someone to follow the growth of your feature over time, with each commit being a chapter of that story. (...)</span> </blockquote>
<br />
It's terrible when we go see the history of a certain line of code just to discover it was changed last together with other 20,000 lines, in a commit with a poor message, in a pull request with empty description...Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-58165742690329417712017-01-30T03:02:00.000-08:002017-01-30T03:13:31.472-08:00Does TDD work?! Baby steps?!<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
I believe one good quality of thinkers, engineers, programmers, you name it, is skepticism.</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
Not taking things for granted allows one to dig deeper, try to understand pros and cons, dive into a detailed level of understanding.</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
TDD is old enough that you can find online (and physical books even) a myriad of related material, both favoring it and bashing it. I'd say that questioning it is great, whether you are in favor, against or indifferent towards it.</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
I'd like to share some links I've (re)visited recently:</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<ul>
<li><a href="http://softwareengineering.stackexchange.com/questions/41409/why-does-tdd-work" style="color: #1155cc;">http://softwareengineering.stackexchange.com/questions/41409/why-does-tdd-work</a></li>
<li><a href="http://thecleancoder.blogspot.com/2010/10/craftsman-62-dark-path.html">http://thecleancoder.blogspot.com/2010/10/craftsman-62-dark-path.html</a></li>
<li><a href="http://softwareengineering.stackexchange.com/questions/109990/how-baby-are-your-baby-steps-in-tdd/109997#109997" style="color: #1155cc;">http://softwareengineering.stackexchange.com/questions/109990/how-baby-are-your-baby-steps-in-tdd/109997#109997</a></li>
</ul>
</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br />
<h3>
TDD</h3>
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
The first one is a question, "<a href="http://softwareengineering.stackexchange.com/questions/41409/why-does-tdd-work" target="_blank">why does TDD work?</a>", or perhaps it should've been "does TDD work?!?"</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
I sympathize with <a href="http://softwareengineering.stackexchange.com/questions/41409/why-does-tdd-work#comment73329_41421" style="color: #1155cc;">this comment</a> (emphasis mine):</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); color: #222222; font-family: arial, sans-serif; font-size: small; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
<span style="color: #242729; font-family: "arial" , "helvetica neue" , "helvetica" , sans-serif; font-size: 13px;">TDD is, in my opinion, mainly about ways to make sure you can check parts rather than a big 'all or nothing' at the end. </span><span style="color: #242729; font-family: "arial" , "helvetica neue" , "helvetica" , sans-serif; font-size: 13px;">But the adagium of TDD, 'build a test first' is<b> not meant to be 'make a test before you think about what you want to accomplish'</b>. Because <b>thinking of a test IS part of designing</b>. Specifying what you want that exact part to do, is designing. Before you ever start to type, you have already done some designing. (In that way I think the term 'test driven design' is misleadingly implying a oneway path, where it is really a <b>feedback loop</b>).</span></blockquote>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<div>
Good design can come either through picking tests intelligently, or by any other technique... how do you learn and discover good designs? You either learn from existing designs, or you try things out.</div>
<div>
I think the former is more effective, and immensely prepares you for the latter.</div>
</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
To a mathematician's mind, I'm speaking to you now, though I see programming are much more than maths, as programming projects are also related to arts, social science, communication, and more...<br />
The way how I learned many topics in maths (and physics, etc): I was taught some theory, and then I did hundreds, perhaps thousands, of exercises. Often an exercise builds up on ideas you've learned in previous challenges. Often a problem is hard enough that you need to be presented with a solution... then you understand it, it makes the problem seem much easier than it originally was. And them you feel empowered to solve similarly tough exercises, and to innovate when faced with the unseen.</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br />
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
What if <a href="http://softwareengineering.stackexchange.com/a/41703" target="_blank">TDD doesn't work</a> as in this quote from Peter Norvig:</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); color: #222222; font-family: arial, sans-serif; font-size: small; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
“Well, the first thing you do is write a test that says I get the right answer at the end,” and then you run it and see that it fails, and then you say, “What do I need next?”—that doesn’t seem like the right way to design something to me. It seems like only if it was so simple that the solution was preordained would that make sense. I think you have to think about it first. You have to say, “What are the pieces? How can I write tests for pieces until I know what some of them are?” And then, once you’ve done that, then it is good discipline to have tests for each of those pieces and to understand well how they interact with each other and the boundary cases and so on. Those should all have tests. But I don’t think you drive the whole design by saying, “This test has failed.”</blockquote>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
Indeed. Writing arbitrary tests and making them pass don't take you anywhere.<br />
<br />
The second link I share is a good commented example of how it goes when <a href="http://thecleancoder.blogspot.com/2010/10/craftsman-62-dark-path.html">the order of tests in unfavorable and we get stuck</a>. One needs to think. You need to build a baggage, a toolbox, and it takes time ;-)</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
At all times, let's keep in mind that <a href="http://softwareengineering.stackexchange.com/a/115478" style="color: #1155cc;">who drives the show</a> is YOU (by writing tests or anything else).</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
Like other techniques, TDD doesn't always work, for it depend on individual and collective "talent" to get things done at a certain quality level.</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); color: #222222; font-family: arial, sans-serif; font-size: small; margin: 0px 0px 0px 0.8ex; padding-left: 1ex;">
(...) how come it does not always work?<br />
<br />
Because testing requires a VERY different mindset than building does. Not every one is able to switch back and from, in fact some people will not be able to build proper tests simply because they cannot set their mind to destroy their creation. This will yield projects with too few tests or tests just enough to reach a target metrics (code coverage comes to mind). They will happy path tests and exception tests but will forget about the corner cases and boundary conditions.<br />
<br />
Others will just rely on tests forgoing design partly or altogether. (...)</blockquote>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
One positive thing about practicing collectively in a <a href="https://dojo-brno.github.io/" target="_blank">coding dojo</a> is the ability to criticize design decisions, and to share that "baggage" on things that work, and things that doesn't, most often being able to show why it does or doesn't. And, looking from a different perspective, there's space to learn things one would not otherwise think in isolation.</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br />
<h3>
Baby steps</h3>
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
This is notably quite long already... but closing with the third link, here goes something about <a href="http://softwareengineering.stackexchange.com/a/109997" style="color: #1155cc;">the "size" of baby steps</a>, something that people being introduced to TDD and baby steps are often asking, when they start to think that one ought to write senseless code when you know an obvious implementation. No, you do not need to write mindless code nor are you supposed to do that.</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
If you know how to do something, if it is obvious for you and you are comfortable, go ahead and do it. Stay in the flow. Now, when your instincts fail, there is the "fake until you make it" technique to keep you up in the game. Faking endlessly and thoughtlessly will not magically solve the problem for you, but gives you time to observe.</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
When overconfidence fails you, you can learn to know when to step back.</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
A whiteboard or a piece a paper, or an interactive interpreter, all might be equally good tools for fostering thinking.</div>
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
<hr style="color: #222222; font-family: arial, sans-serif; font-size: small;" />
<div style="color: #222222; font-family: arial, sans-serif; font-size: small;">
<br /></div>
We practice TDD and Baby Steps in coding dojos, though those are not magical techniques that solve all problems. The breath of domains we write programs for is so vast that no single technique could possibly be a silver bullet. Those two are certainly not sufficient in the toolbox of one aspiring to be a good programmer.<br /><br />What are other useful techniques for you?</div>
</div>
Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-61112910244427248722017-01-25T05:47:00.000-08:002017-01-25T08:26:06.399-08:00Go workshop<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0tjnAokeffUktWYowp2MznTVZhGR7wmUQixQMXTI1divI2MsHkGXF2RfdEra8SBddliKS4y7HDnR_DpOTl7AEASxuXzwfVty_gdeKN4s2a-jQyODihHWch0p4jX3HgqKDxg9v7vbKG1lZ/s1600/2017-01-24+17.19.33.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0tjnAokeffUktWYowp2MznTVZhGR7wmUQixQMXTI1divI2MsHkGXF2RfdEra8SBddliKS4y7HDnR_DpOTl7AEASxuXzwfVty_gdeKN4s2a-jQyODihHWch0p4jX3HgqKDxg9v7vbKG1lZ/s320/2017-01-24+17.19.33.jpg" width="320" /></a></div>
<br />
<br />
Yesterday, I've facilitated an <a href="https://www.meetup.com/Golang-Brno/events/236846434/" target="_blank">introductory workshop about the Go programming language</a>. So far the feedback has been positive, both during our retrospective at the end of the workshop, the corridor conversations later, and comments on the event page.<br />
<br />
There were 9 participants, some from Red Hat, some from Solar Winds, some students, some unemployed, and some from other companies which I do not recall. It was a very good team, and I attribute the success of the workshop to them.<br />
<div>
<br /></div>
They were familiar with C, Java, C#, Python and perhaps other languages. It was either their very first contact with Go, or they've had limited contact with it in some recent project.<br />
<div>
<br /></div>
<div>
We had only two hours to pack a good deal of content. There were, however, some key points that we made sure to include in those exciting hours:<br />
<br />
<ul>
<li>Learning should be fun</li>
<li>The learning process can be improved when we cooperate</li>
<li>Testing is a serious matter, and Go's design brings in some peculiarities to writing tests that are not seen in other languages.</li>
</ul>
<br />
The official Go documentation is really good, and, thus, part of the workshop was about following along <a href="https://tour.golang.org/" target="_blank">The Tour of Go</a>. The other part was about testing, and how to approach the coding exercises from the tour using Test Driven Development.<br />
<br />
Due to our time constraints, we covered all of the "Basics" topics from the tour, and we had about one hour and twenty minutes of effective hands-on coding, which I consider great.<br />
<br />
During the retrospective, I remember people talking about function closures, error handling in Go, testing. It was satisfying to see it was useful and everybody had something they've learned to share with the group.<br />
<br />
I've heard from one participant that he got so excited about Go that he kept playing with it until late in the morning...<br />
<br />
The slides I've used are available here:<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="420" marginheight="0" marginwidth="0" scrolling="no" src="//www.slideshare.net/slideshow/embed_code/key/51zWDBBWxgDhGV" style="border-width: 1px; border: 1px solid #ccc; margin-bottom: 5px; max-width: 100%;" width="510"> </iframe> <br />
<div style="margin-bottom: 5px;">
<strong> <a href="https://www.slideshare.net/rhcarvalho/a-tour-of-go-workshop" target="_blank" title="A Tour of Go - Workshop">A Tour of Go - Workshop</a> </strong> from <strong><a href="https://www.slideshare.net/rhcarvalho" target="_blank">rhcarvalho</a></strong></div>
</div>
Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com2tag:blogger.com,1999:blog-396083382034174439.post-76450131277156552142017-01-25T01:42:00.003-08:002017-01-25T05:49:39.891-08:00Notes from Golang-Brno #4: Refactoring, containers, plugins, ...Yesterday, I facilitated <a href="https://www.meetup.com/Golang-Brno/events/236846434/" target="_blank">an introductory Go workshop</a> here in Brno, CZ. This post is not about the workshop though, but just some notes from the talks that followed in the <a href="https://www.meetup.com/Golang-Brno/events/236693598/" target="_blank">evening meeting</a>.<br />
<br />
Update: I've written some notes about the <a href="http://blog.rodolfocarvalho.net/2017/01/go-workshop.html" target="_blank">Go workshop</a>.<br />
<br />
There were two talks. The first one was an excellent pick of interesting talks and stories from dotGo 2016, very well presented by Jan Klat. I was glad to meet him :-)<br />
<br />
<h3>
Refactoring: difficulty with refactoring types</h3>
One of the talks Jan shared with us was about refactorings. While I haven't watched the original talk, one think that came to mind is the <b>Type Alias proposal</b> that is being tracked here:<br />
<a href="https://github.com/golang/go/issues/18130">https://github.com/golang/go/issues/18130</a><br />
<br />
<h3>
Self deploying Go: debuggability</h3>
<div>
Another talk was about deploying to "the cloud" very small containers with just statically linked Go programs. My remark was that this works really well for demos and proofs-of-concept, but has several limitations and drawbacks in practice.</div>
<div>
<br /></div>
<div>
Yeah, as part of my work in OpenShift I can say "been there, done that". The thing to keep in mind is that often you will want to spawn a remote shell in your container... but if all you have is a single binary... that means no shell, no common Linux utils... and very limited way of debugging problems unless you add all the things into your Go binary. No, don't do that. Save yourself.</div>
<div>
<br /></div>
<div>
Most of the time, it is a false economy and a misconceived objective to try to have 5 MB binaries in your containers in production. Once you deploy your image to something like OpenShift or Kubernetes, your nodes will already have a local copy of your image, so scaling, starting more instances of a container does not require pulling in more data over the network.</div>
<div>
<br /></div>
<div>
A more interesting thing is to layer your images properly to reuse the base layers across your containers images. Say you have a base image for all of your Go micro services that is 500 MB, and you have 3 services. Each binary implementing your service is roughly 10 MB. Now if you share a common base image, loading the first image for the very first time will transfer 110 MB, but the next 2 images will need to transfer only 10 MB each.</div>
<div>
<br /></div>
<h3>
Plugins in Go</h3>
Jan mentioned some talk about plugins, some "novel" attempts but folks at Drone.io.... but it all sounded to me more or less what we find already in production in software from Hashicorp, like Packer for example.<br />
<br />
The problem/solution is at least as old as April 2013:<br />
<a href="https://github.com/mitchellh/packer/issues/1">https://github.com/mitchellh/packer/issues/1</a><br />
<br />
More:<br />
<a href="https://www.youtube.com/watch?v=SRvm3zQQc1Q">https://www.youtube.com/watch?v=SRvm3zQQc1Q</a> (all the story behind plugins in Go, early attempts, current design)<a href="https://github.com/hashicorp/go-plugin">https://github.com/hashicorp/go-plugin</a><br />
<br />
<hr />
<br />
The second talk was about Mall.cz and their rewriting of an existing system into Go components. Unfortunately there was very little about Go, too much about internal details, and we were left with the feeling that the new solution is buzzword-compliant, more complex, and does not address the problem with the original system...<br />
<br />
That's honest feedback. Anyway, the two guys presenting were good, open to questions and explaining their thoughts and decisions, so I stayed until the end of the event and enjoyed it.<br />
<br />
My notes:<br />
<br />
<h3>
Iris Web framework, fast?!</h3>
<div>
Yeah, so they seem to have chosen to use a web framework that I've never heard of, because... because it is fast? Hmm... they came with a very suspicious graph, claiming not only Iris is orders of magnitude faster than anything else, but also that most of the existing "Go web frameworks" are "faster" than net/http in the standard library... how come?</div>
<div>
Most, if not all of those frameworks/tools/libraries do delegate the hard work to net/http, so there is no way on Earth or any other planet they would be faster than the net/http.</div>
<div>
<br /></div>
<div>
What's more, finding the source code on GitHub, it turns out that <a href="https://github.com/kataras/iris" target="_blank">Iris</a> has had code contributions from a single developer. All due respect to the Iris author, but in an Open Source world, that, plus the relative immaturity of the code, plus the speed claims are really really big warning signs.</div>
<div>
<br /></div>
<div>
People are free to choose whatever they want. Without going into much detail, my philosophy is keep is dependencies to a minimum. One must judge really well the ROI, the value, a given dependency is bringing compared to the complexity it is adding to your project. And keep in mind also transitive dependencies.</div>
<div>
<br /></div>
<h3>
Trash, Go vendoring tool</h3>
There is a myriad of tools out there to help you vendor your dependencies along with your code... and also a lot to be said and learned about this topic.<br />
<br />
Now, it was really funny to hear that the solution to Go vendoring is.... "<b>put all of your code to trash</b>". Sometimes that's really good advice -- fear not delete Thy code.<br />
<br />
By the way, if your dependencies are "trash", why do you even depend on them?!<br />
<br />
I never used <a href="https://github.com/rancher/trash" target="_blank">trash</a>, but what I found weird during the talk is that the speakers were happy about the fact that it deletes all the "useless" files, including "useless" tests, and parts of the dependencies that you do not use... It does look nice on the first sight, but left me with questions like what happens when you want to upgrade the versions of your dependencies and so on.<br />
<br />
<h3>
Containers in development and/or in production?</h3>
They were using Docker containers for development, and automating deployment with Chef in production.<br />
<br />
<h3>
Using net/http == using concurrency and goroutines</h3>
<div>
One of the reasons they were excited about Go was the existence of goroutines and channels. In the few minutes Go was mentioned, this was a recurring topic. But they seemed too excited about writing concurrent Go, apparently ignoring that is no trivial thing :-)</div>
<div>
<br /></div>
<div>
Throwing goroutines and channels into a code base will NOT magically improve performance. On the contrary, when done wrong it can harm performance, and introduce more subtle bugs.</div>
<div>
<br /></div>
<div>
However, one thing to note is that just because they are using Iris, and underneath net/http, their programs already have goroutines and all the fanciness of concurrency in Go! Yeah, that's another important lesson to be learned... the API of net/http has no channels, no explicit goroutines, and you get to write your handlers as regular functions, all the underlying complexity well factored away from your eyes.</div>
<div>
<br /></div>
<h3>
Tests: build tags</h3>
<div>
They've heard about "build tags", but I think they've misunderstood it. Their example of running tests was something like this:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">go test -run Unit</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">go test -run Integration</span></div>
<div>
<br /></div>
<div>
That means they understood tags as simply naming every test function as "TestUnitFoo". While that may work, it is a waste of time/characters/whatever to name your tests functions in that fashion.</div>
<div>
<br /></div>
<div>
Build tags, or build constraints, are well documented here:</div>
<div>
<a href="https://golang.org/pkg/go/build/#hdr-Build_Constraints">https://golang.org/pkg/go/build/#hdr-Build_Constraints</a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
For tests, one common and reasonable pattern is to write your unit tests normally, in *_test.go files that go along with your packages. Then, for integration or other types of tests, put them in separate packages, also in *_test.go files, but add a build constraint that is only satisfied when you intend to run integration tests. In other words, add this to the top of your files:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">// +build integration</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">package foo</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">import "testing"</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">...</span></div>
<br />
<hr />
<br />
That's all from the talks yesterday :-)Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-72802157409677331942017-01-11T12:58:00.000-08:002017-01-11T13:06:00.349-08:00Expanding the Coding Dojo Brno!I believe that learning computer programming is a continuous process that involves deliberate practice and gradually pushing yourself into mastering new skills.<br />
<br />
There are also important social skills involved, like team work and communication.<br />
<br />
In a coding dojo meeting, we work as a self-organized group to learn and share knowledge by following certain principles and practices. We practice:<br />
<ul>
<li>collective problem solving </li>
<li>Test-Driven Development </li>
<li>pair programming </li>
<li>baby steps </li>
<li>code refactoring </li>
<li>and others... </li>
</ul>
We also keep everybody in the loop, making the environment inclusive and welcoming for people with all sorts of background. It is a collaborative community, not a competition.<br />
<br />
All that happens while we solve computer programming exercises (called "katas") in a programming language of our choice.<br />
<div>
<br />
<h4>
A bit of history</h4>
Coding dojos started to appear around the globe throughout the boom of Agile development. The <a href="http://codingdojo.org/cgi-bin/index.pl?back=ParisDojo">ParisDojo</a> was founded back in December 2004, and then, four years later in December 2008, with the help of an awesome community of developers, I've founded the <a href="https://dojorio.org/">Coding Dojo Rio</a>. The community is so amazing that it has grown non-stop and holds regular meetings every week for over 8 years now.<br />
<br />
Last January, with two colleagues, I started the <a href="https://github.com/dojo-brno/dojo-brno">Coding Dojo Brno</a> <a href="https://groups.google.com/forum/#!forum/dojo-brno">group</a> here in Brno. We held over 40 meetings in the Red Hat office in the year 2016, and, though we've always been an open-to-all group, we've had limited participation from the external community. This year we're finally expanding, and we'll be holding meetings in a new venue, a room in the Masaryk University's Faculty of Informatics, <a href="https://www.facebook.com/events/1206562216096930/" target="_blank">starting next week</a>.<br />
<br />
We're also trying to gain more visibility through a Facebook group: <a href="https://www.facebook.com/groups/CodingDojoBrno">facebook.com/groups/CodingDojoBrno</a>.<br />
<br />
If you are interested in programming, knowledge sharing, agile, TDD, etc, get in touch and come to one of our next events!</div>
Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-87092561100035431302017-01-11T08:09:00.000-08:002017-01-11T08:10:04.249-08:00Go workshop and coding dojo in Brno<span style="color: #1d2129; font-family: "helvetica neue" , "helvetica" , "arial" , sans-serif;"><span style="font-size: 14px;">Later this month the <a href="https://www.meetup.com/Golang-Brno" target="_blank">Golang-Brno community</a> starts its activities in 2017 with an introductory workshop and coding dojo, followed by a regular meetup with talks:</span></span><br />
<span style="color: #1d2129; font-family: "helvetica neue" , "helvetica" , "arial" , sans-serif;"><span style="font-size: 14px;"><br /></span></span>
<span style="color: #1d2129; font-family: "helvetica neue" , "helvetica" , "arial" , sans-serif;"><span style="font-size: 14px;">More info:</span></span><br />
<span style="color: #1d2129; font-family: "helvetica neue" , "helvetica" , "arial" , sans-serif;"><span style="font-size: 14px;"></span></span><br />
<ul>
<li><span style="color: #1d2129; font-family: "helvetica neue" , "helvetica" , "arial" , sans-serif;"><span style="font-size: 14px;"><a href="https://www.meetup.com/Golang-Brno/events/236846434/">https://www.meetup.com/Golang-Brno/events/236846434/</a></span></span></li>
<li><span style="color: #1d2129; font-family: "helvetica neue" , "helvetica" , "arial" , sans-serif;"><span style="font-size: 14px;"><a href="https://www.meetup.com/Golang-Brno/events/236693598/">https://www.meetup.com/Golang-Brno/events/236693598/</a></span></span></li>
</ul>
<br />
<span style="background-color: white; color: #1d2129; font-family: "helvetica neue" , "helvetica" , "arial" , sans-serif; font-size: 14px;">I'll facilitate the workshop. The idea is to help people understand the basics of Go by following the <a href="https://tour.golang.org/" target="_blank">official tour</a>, and then put everyone to code in a randori coding dojo, where we'll use the <a href="https://golang.org/pkg/testing/" target="_blank">testing</a> package and the <a href="https://golang.org/pkg/cmd/go/#hdr-Test_packages" target="_blank">go tool</a> to write automated tests and small programs.</span>Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-28934815522752013742017-01-06T02:36:00.003-08:002017-01-14T10:29:19.266-08:00Configuring keyboard repeat rate on Gnome 3It's been some years that I use a rather fast keyboard repeat interval. With a well tuned delay, it just seems to make a lot more sense to the programmer in me.<br />
<br />
It allows me to focus on navigating the screen in more effective ways, like word-by-word instead of char-by-char, and also makes it quick to repeat keys when you intend to do so, like typing:<br />
<br />
--------------------------------------------------------------<br />
<br />
Can you type that without feeling like watching a slow motion movie?!<br />
<br />
I don't really know when I started doing it, nor the original motivation. I think when I met <a href="https://www.industriallogic.com/people/tottinge">Tim Ottinger</a> in a coding dojo in Beijing he mentioned how frustrated he got whenever he touched somebody else's slow keyboard on a workshop or some other event, and would immediately suggest and show how to change the key repeat rate settings.<br />
So it might have been Tim, or might have been someone else in that story, but the story is true :P<br />
<br />
Last year, doing coding dojos in Brno, I've noticed the opposite feeling in people touching my "fast" keyboard... they often get so scared when they unintentionally seeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee<br />
<br />
Phew!<br />
<br />
If you think fast key repeat rate is for you, here is how to set in in Gnome 3 (for reference, works on Fedora 25).<br />
<br />
First, inspect your current settings:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">$ gsettings list-recursively org.gnome.desktop.peripherals.keyboard </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">org.gnome.desktop.peripherals.keyboard repeat-interval uint32 0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">org.gnome.desktop.peripherals.keyboard delay uint32 500</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">org.gnome.desktop.peripherals.keyboard repeat true</span><br />
<br />
I've set the <b>repeat-interval</b> to the fastest value, 0. And the <b>delay</b> is just the default, 500ms. The <b>repeat</b> value controls whether keys repeat or never repeat.<br />
<br />
Set each key to your preferred value with the command:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">$ gsettings set org.gnome.desktop.peripherals.keyboard KEY VALUE</span><br />
<br />
Replace KEY and VALUE with the appropriate key and value.<br />
<br />
<br />
Note: the same configuration is available in a graphical interface in Gnome Settings > Universal Access > Typing > Repeat Keys. Unfortunately, with that interface you only have dials, and no way to enter precise values or to inspect the current values.<br />
If you want to do it with a graphical interface and have precise values, you can install and use the package <i>dconf-editor</i>.<br />
<br />
Update: after a reboot I realized that the minimum usable value for <b>repeat-interval</b> is 1. It was apparently okay to set it to zero, but after a reboot I could not login on a Wayland session (crash caused by a division by zero...), while Xorg would let me login, but with the keyboard settings silently defaulted (though gsetttings and Universal Settings would still display the values I've configured).<br />
<a href="https://bugzilla.redhat.com/show_bug.cgi?id=1413305">https://bugzilla.redhat.com/show_bug.cgi?id=1413305</a>Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com2tag:blogger.com,1999:blog-396083382034174439.post-37921951901667223132017-01-02T08:06:00.001-08:002017-01-02T13:00:49.719-08:00Backing up entire disks and making .img files smallerAs part of migrating to a new laptop and backing up an entire disk partition, here I document what I have done.<br />
<h3>
Creating full disk images</h3>
<div>
Work from a Live USB with Fedora 25 or any other modern distro, so that the partitions that will be backed up are not in use.</div>
<div>
Use the Disks utility to create a disk image of some partition, e.g., the original /home.</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://s.rodolfocarvalho.net/disks-create-image.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://s.rodolfocarvalho.net/disks-create-image.png" height="144" width="320" /></a></div>
<div>
<br /></div>
<div>
This will create a .img file as big as the partition size, independent of how much data is actually stored. Next, we shrink the image to a minimal size to fit the data it contains, potentially saving some backup space.</div>
<div>
<br /></div>
<h3>
Shrink disk image to its minimal size</h3>
<div>
If all you have is a single partition image, as created in the step above, we can use a <a href="https://en.wikipedia.org/wiki/Loop_device" target="_blank">loop device</a> and the <code>resize2fs</code> utility to make the image smaller.<br />
<br />
First, we'll find an available loop device with: <br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">sudo losetup -f</span><br />
<br />
Note down the name of the loop device, e.g., /dev/loop1, and use it in the next steps.<br />
<br />
Mount the image:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">sudo losetup /dev/loop1 'Disk Image of ... .img'</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">And resize it to its minimum size: </span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">sudo resize2fs -Mp /dev/loop1</span><br />
<br />
The <code>-M</code> flag resizes the image to the minimum size; while <code>-p</code>
prints progress information.<br />
Be patient, <code>resize2fs</code> may take some time depending on the partition size, disk
speed, etc.<br />
<br />
Note: if you get an error from the command above, it might be needed to run this before running <code>resize2fs</code> again (the error message will tell):<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">sudo e2fsck -f /dev/loop1</span><br />
<br />
When <code>resize2fs</code> finishes, unload the loop device:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">sudo losetup -d /dev/loop1</span><br />
<br />
Finally, run <code>resize2fs</code> on the .img file to resize it:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">resize2fs -Mp 'Disk Image of ... .img'</span><br />
<br />This should be relatively fast.<br />
We're done! Check the new image size.</div>
Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com1tag:blogger.com,1999:blog-396083382034174439.post-43604470782179050922017-01-01T13:45:00.000-08:002017-01-01T13:45:38.141-08:00Get a list of all RPM packages installedNew year, time to start with a fresh install of Fedora 25...<br />
While <code>dnf</code> has worked really well for in-place upgrades, this time I went with a migration into a clean install on new hardware.<br />
<br />
This is what I used to get a list of all RPM packages installed, so that I can reinstall on the new system:<br />
<pre style="overflow: auto;"><code>
sudo dnf --disableexcludes=all repoquery --qf '%{name}' --installed | sort
</code>
</pre>
Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-30595757581421748562016-03-14T04:27:00.001-07:002016-03-14T10:05:35.705-07:00PyCon SK 2016<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
This is a brief report of my weekend in Bratislava, at <a href="https://pycon.sk/en/index.html" style="color: #1155cc;" target="_blank">PyCon SK</a>, the first [inter]national Python conference in Slovakia!</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
On Saturday I gave a talk about OpenShift -- Docker and S2I builds, and deployment automation with our PaaS.</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvlZZRifWhGpDsGJSEWOAJa69I5CukQ9VvGisXaq9g0FR2i39Sn8MDzsDzBWHuzCODYec_ZOFfPEASzHMt8utIeyZqHYeEl3a5voXiLvsmz5KPj4k9wGFyOoVqWBm3nOZUVDFhO6QrCdJ6/s1600/2016-03-12+13.45.00.jpg" imageanchor="1"><img border="0" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvlZZRifWhGpDsGJSEWOAJa69I5CukQ9VvGisXaq9g0FR2i39Sn8MDzsDzBWHuzCODYec_ZOFfPEASzHMt8utIeyZqHYeEl3a5voXiLvsmz5KPj4k9wGFyOoVqWBm3nOZUVDFhO6QrCdJ6/s640/2016-03-12+13.45.00.jpg" width="640" /></a></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
Thanks to my new Turkish friend <a href="https://twitter.com/busrakoken" target="_blank">Büşra</a> for tweeting my photo!</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<span style="font-size: 12.8px;">Personally I always feel like there's something to improve, but the feedback I got was positive ;)</span></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
People were interested, asked several questions after the talk and I kept meeting people interested in OpenShift and Red Hat in the corridors throughout the day and on Sunday as well.</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
Thanks everybody for the conversations, it was a perfect weekend!</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<span style="font-size: 12.8px;">There was a live stream on YouTube, I imagine the recording should be out sometime soon.</span></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
Shadowman made an appearance in my arm during the conference:</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEge-UwFF6mdyklJPKFDuLNUv98x2ujXRfgkwq8JzR6h3mSJOhw4dg-z93aqJIitg2bgE1PgNu1ARMiF5KUTbCFnjt-DBWE3eYjA1W_FbhLIPfx4OuGv41BOpv7Zjlbxf7QhaPvtJACJoAQQ/s1600/2016-03-12+16.54.44.jpg" imageanchor="1"><img border="0" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEge-UwFF6mdyklJPKFDuLNUv98x2ujXRfgkwq8JzR6h3mSJOhw4dg-z93aqJIitg2bgE1PgNu1ARMiF5KUTbCFnjt-DBWE3eYjA1W_FbhLIPfx4OuGv41BOpv7Zjlbxf7QhaPvtJACJoAQQ/s400/2016-03-12+16.54.44.jpg" width="400" /></a></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
And, actually, it's still with me today, Monday ;)</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
Also on Saturday I gave a lighting talk with <a href="https://twitter.com/tati_alchueyr" target="_blank">Tatiana</a> to promote the Coding Dojo we did on Sunday.</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
Tatiana was fantastic at improvising with me in the stage! We had a spontaneous conversation talking about Coding Dojos that drove the attention of many people.</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
Thanks to that we learned that <a href="https://twitter.com/ntoll" target="_blank">Nick</a> is organizing the London Dojo, and perhaps will partner with Tatiana in the near future to keep moving their dojo forward, bringing in some Brazilian taste to the mix!</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
Sunday was awesome, or, to put it in the words of the feedback I got: it was INCREDIBLE FUN.</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
That day was left open by the organizers for spontaneous activities... and guess what gathered the most people together? The Coding Dojo!</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5x5KZkmK0tfOINJFKItiNsHouR52J7RF_-kJiRTPtMnTzogm7g0KoVRcSCuLBa6qdxpjTfCBVzT3ZfIUmvQJElI2TiLrZn0eAGnNuS-MjEhtB8KvIg0lQvoDgMqEV4qCRnyNwVaKmN4G4/s1600/2016-03-13+13.37.16.jpg" imageanchor="1"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5x5KZkmK0tfOINJFKItiNsHouR52J7RF_-kJiRTPtMnTzogm7g0KoVRcSCuLBa6qdxpjTfCBVzT3ZfIUmvQJElI2TiLrZn0eAGnNuS-MjEhtB8KvIg0lQvoDgMqEV4qCRnyNwVaKmN4G4/s640/2016-03-13+13.37.16.jpg" width="640" /></a></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
It was definitely a chance to inspire and be inspired! Gather together about 50 people in a Sunday morning? Not trivial.</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
We ran three sessions with a retrospective in the morning and in the afternoon.</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG0boH4w41PemUSf6NB7hoiHUq26XvZuUX8FowANK8BN5jzS3gkh0l46JIKi00enc2tJ031VAkBzRlklPl-gdNsuaAmtAVDbqUX6yp0D3aiBANlSC2X0xbnIEW0D35PyEn7PuZupe9mqIZ/s1600/2016-03-13+12.14.50.jpg" imageanchor="1"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhG0boH4w41PemUSf6NB7hoiHUq26XvZuUX8FowANK8BN5jzS3gkh0l46JIKi00enc2tJ031VAkBzRlklPl-gdNsuaAmtAVDbqUX6yp0D3aiBANlSC2X0xbnIEW0D35PyEn7PuZupe9mqIZ/s640/2016-03-13+12.14.50.jpg" width="640" /></a></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZdhrJ4HKgAr_zTepdjyVL_Pv6L54FVZWyPA20k2PlJA2f2lJl-bKFppuws1K1XUL4Xp4cmQuW1X4qpBeOPrGcoW99EbgBb1d5xI8rqUvAskZAw7bOzQdnEV_75pLMMiqk2xcMQD94HFqA/s1600/2016-03-13+15.31.50.jpg" imageanchor="1"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZdhrJ4HKgAr_zTepdjyVL_Pv6L54FVZWyPA20k2PlJA2f2lJl-bKFppuws1K1XUL4Xp4cmQuW1X4qpBeOPrGcoW99EbgBb1d5xI8rqUvAskZAw7bOzQdnEV_75pLMMiqk2xcMQD94HFqA/s640/2016-03-13+15.31.50.jpg" width="640" /></a></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
Even after what I call "self selection", we got down to about ~20 people who actively participated and engaged in coding, expressing their ideas, overcoming their fears and difficulties.</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
That's the power of building communities. I'm looking forward to hearing that the Slovaks in Bratislava will start their own meetings :)</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
I met a fantastic group from the Python community of Viena, and I'd definitely love to join them in the near future.</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
That's about it, a lot of informal conversations about Red Hat, how we develop OpenShift, open source, coding dojos, Brno, Turkey, Brazil, Functional Programming, etc etc.</div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
<br /></div>
<div style="background-color: white; color: #222222; font-family: arial, sans-serif; font-size: 12.8px;">
What a great conference!</div>
Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com2tag:blogger.com,1999:blog-396083382034174439.post-42693256053460644592015-04-17T13:11:00.000-07:002015-04-17T13:11:21.211-07:00Let's open source<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8yvWvYYMQ6ZVGmjo3axcvGQWM6XDYyFQ-ZgIx3jbOj1iYfdJtMMjsHaM3rY4eiyL2Hn61x1j55z9UI4CNLS14OSLe2K4gWg8aKUK7PU_ffXluyaiBRuYn4dbRbrWp_Yemf4q4UXSap7vI/s1600/2015-04-15+09.21.41.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8yvWvYYMQ6ZVGmjo3axcvGQWM6XDYyFQ-ZgIx3jbOj1iYfdJtMMjsHaM3rY4eiyL2Hn61x1j55z9UI4CNLS14OSLe2K4gWg8aKUK7PU_ffXluyaiBRuYn4dbRbrWp_Yemf4q4UXSap7vI/s1600/2015-04-15+09.21.41.jpg" height="180" width="320" /></a></div>
<br />
<br />
This has been a fantastic week for me. Last Wednesday I joined the <a href="http://www.openshift.com/" target="_blank">OpenShift</a> Developer Experience team in <a href="http://www.redhat.com/" target="_blank">Red Hat</a>.<br />
New life in Brno, Czech Republic, comes packed with a myriad of new opportunities to learn and share. I'm amazed by the people I've met so far. In a two-week time span it's been <a href="http://www.meetup.com/BrnoJS/" target="_blank">BrnoJS</a>, <a href="http://www.meetup.com/Docker-Brno/" target="_blank">Docker Brno</a>, <a href="http://www.meetup.com/Foreigners-cz-Brno-MeetUp/" target="_blank">Foreigners.cz Brno</a>, and other opportunities, and more coming day after day.<br />
<br />
One great thing about working with opensource is that I'll be able to share everything with the community. OpenShift is a big piece of software, and my first task to get started is to prepare a demo of how an end user can deploy and scale a project with OpenShift. In particular, it will be a Python application, powered by Django and Postgres.<br />
<br />
And by the end of May I'll be talking about <a href="http://summit.pywaw.org/#speakers" target="_blank">deployments with OpenShift</a> in <a href="http://summit.pywaw.org/" target="_blank">PyWAW Summit</a> in Warsaw! I'm looking forward to meeting friends again in Poland and talking about the things that I'm working on these days :-)Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com2tag:blogger.com,1999:blog-396083382034174439.post-85272446697486828742015-02-14T09:03:00.002-08:002015-02-14T09:03:59.115-08:00typokiller: my new tool to exterminate typos in software documentationLast year, during the Django Sprint we had in Kraków, I was working on <a href="https://github.com/rhcarvalho/django-sprint-krk-2014" target="_blank">finding and fixing typos</a> in the <a href="https://docs.djangoproject.com/" target="_blank">Django Documentation</a>.<br />
<br />
It was fun to automate spellchecking the docs, but it was also very laborious to use my rudimentary tools.<br />
<br />
This week, in a span of 2 nights and 1 morning, I worked on a <a href="https://github.com/rhcarvalho/typokiller/tree/v0.1" target="_blank">minimally usable version</a> of <a href="https://github.com/rhcarvalho/typokiller" target="_blank">typokiller</a>. The first outcome of this work was this <a href="https://github.com/openshift/origin/pull/1018" target="_blank">Pull Request</a> made just a few hours ago.<br />
<br />
Even though typokiller is still an alpha-quality baby project, I am pretty happy that it has an interactive terminal-based UI, thanks to the awesome <a href="https://github.com/nsf/termbox-go" target="_blank">termbox</a> library:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVKTRWehg2FoOeaJexxp4BYGqGyKvUb4peT3jwQ7JdnPh4Fn4_f6W3wws22Y9MgaAWJsbLkxgFubjN7O9y3dWLwUL40cdCCAg0UlrYSD7Zm1bUjzIgXvc1oD-cC-WLjMmeEdlwlAdBl4ic/s1600/Screen+Shot+2015-02-14+at+17.43.39.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVKTRWehg2FoOeaJexxp4BYGqGyKvUb4peT3jwQ7JdnPh4Fn4_f6W3wws22Y9MgaAWJsbLkxgFubjN7O9y3dWLwUL40cdCCAg0UlrYSD7Zm1bUjzIgXvc1oD-cC-WLjMmeEdlwlAdBl4ic/s1600/Screen+Shot+2015-02-14+at+17.43.39.png" height="122" width="400" /></a></div>
With typokiller running, a bit of patience and about 1 hour of careful inspection I was able to find 45 typos in <a href="http://www.openshift.org/" target="_blank">OpenShift Origin</a>'s <a href="http://godoc.org/github.com/openshift/origin" target="_blank">documentation</a>. As you can see in the screenshot I had to go through 1583 potential typos. Thank God I implemented replace all, edit all and ignore all commands :-)<br />
<br />
The idea behind typokiller is to have several small programs each responsible for one of these steps:<br />
<br />
<ol>
<li>Collect documentation excerpts</li>
<li>Check spelling</li>
<li>Interactively fix typos</li>
</ol>
<div>
Right now typokiller only supports inspecting the documentation of Go code, but I might include support for more languages in the future (or you can create and issue to tell me which language you need, or you can code it and make a pull request).</div>
<div>
<br /></div>
<div>
You start with a Git repository with some project containing potential typos in its documentation. You might want to create a new branch. Then you can run:</div>
<div>
<br /></div>
<div>
</div>
<br />
<div class="p1">
<span style="font-family: Courier New, Courier, monospace;">$ ./killtypos $(find /path/to/project -type d -not \( -name Godeps -prune -o -name .git -prune \))</span></div>
<br />
This will find all directories inside the project path, ignoring the subdirectories Godeps and .git, and pass that through the 3 stages of typokiller, leaving you in an interactive mode. After inspecting the potential typos, type "a" to apply the changes to the files. Review the files with Git, commit, push and make a PR.<br />
<br />
The design was made such that I can pipe the output of one command into another, and also easily integrate with other unix tools like head, grep, etc.<br />
<br />
That's all for now, let me know if you enjoy typokiller.Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0tag:blogger.com,1999:blog-396083382034174439.post-17314073563176272122015-02-08T09:18:00.000-08:002015-02-08T09:18:16.182-08:00Falcon, Django, PyPy & Docker<div class="separator" style="clear: both; text-align: left;">
Late last year I learned about the <a href="http://falconframework.org/" target="_blank">Falcon Framework</a>, one more to the list of many Python frameworks out there. Falcon focus on performance, having quite impressive <a href="http://www.techempower.com/benchmarks/#section=data-r9&hw=ec2&test=json&l=1kw&f=1k6q0-jz6s0-4ftog0-0" target="_blank">benchmarks</a>.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://falconframework.org/img/flight-silhouettes.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://falconframework.org/img/flight-silhouettes.png" height="125" width="200" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So I was wondering how can you have super fast API endpoints in your Python web service while still serving some legacy code in Django, or just any other WSGI-compliant framework.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The outcome of my experiment lives in this GitHub repo: <a href="https://github.com/rhcarvalho/django-plus-falcon-pypy" target="_blank">rhcarvalho/django-plus-falcon-pypy</a>.</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<a name='more'></a><br />
<div class="separator" style="clear: both; text-align: left;">
I'm using <a href="http://gunicorn.org/" target="_blank">Gunicorn</a> with <a href="http://www.tornadoweb.org/" target="_blank">Tornado</a> workers to serve this glue-code WSGI app:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<script src="https://gist.github.com/rhcarvalho/ea7391be16b1417ce9dd.js"></script>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
And the nicest part is how you can run this hybrid application: <b><span style="font-family: Courier New, Courier, monospace;">fig up</span></b></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<a href="http://www.fig.sh/" target="_blank">Fig</a> will build a <a href="https://www.docker.com/" target="_blank">Docker</a> image, pack it with all the necessary dependencies to run our example web server, then run it in a Docker container.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Behind the scenes you get a fresh operating system with <a href="http://pypy.org/" target="_blank">PyPy</a> installed, all Python dependencies and the application code.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Fig is a tool on top of Docker, and Docker...</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://pbs.twimg.com/profile_images/378800000124779041/fbbb494a7eef5f9278c6967b6072ca3e_400x400.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="200" src="https://pbs.twimg.com/profile_images/378800000124779041/fbbb494a7eef5f9278c6967b6072ca3e_400x400.png" width="200" /></a></div>
<br />
If you haven't done it yet, <a href="https://www.docker.com/tryit" target="_blank">try Docker now</a>! You can get started straight from your browser, no download required, and you'll experience a very immersive tutorial that guides you through the initial steps with Docker.<br />
<br />
Then I advise you to go trough the official documentation because it is great. You might want to start by <a href="http://docs.docker.com/introduction/understanding-docker/" target="_blank">understanding what Docker is</a>, <a href="http://docs.docker.com/installation/" target="_blank">install it</a>, <a href="https://hub.docker.com/account/signup/" target="_blank">create an account</a> on <a href="https://hub.docker.com/" target="_blank">Docker Hub</a> and then follow along the excellent <a href="http://docs.docker.com/userguide/" target="_blank">user guide</a>.<br />
<br />
The installation on Linux, Mac OS or Windows is generally painless. You can even have it inside some virtual machine.Rodolfohttp://www.blogger.com/profile/13115401885842551697noreply@blogger.com0