<rss version="2.0" xmlns:atom="https://www.w3.org/2005/Atom">
	<channel>
		<title>Posts on Matt Aimonetti</title>
		<link>https://matt.aimonetti.net/posts/</link>
		<description>Recent content in Posts on Matt Aimonetti</description>
		<generator>Hugo -- gohugo.io</generator>
		<language>en-us</language>
		<lastBuildDate>Thu, 18 Jan 2024 20:28:01 -0800</lastBuildDate>
		<atom:link href="https://matt.aimonetti.net/posts/index.xml" rel="self" type="application/rss+xml" />
		
		<item>
			<title>Thoughts on Generative AI and anime</title>
			<link>https://matt.aimonetti.net/posts/2024-01-thoughts-on-generative-ai-and-anime/</link>
			<pubDate>Thu, 18 Jan 2024 20:28:01 -0800</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2024-01-thoughts-on-generative-ai-and-anime/</guid>
			<description>For a little while, I&amp;rsquo;ve been considering the potential impact of generative Artificial Intelligence on various areas of our lives, more recently I&amp;rsquo;ve had very interesting conversations about applying AI to help the creations of manga/animé. This blurb was writing to help think through the challenges, but why not posting them.
Having witnessed the transition from analog to digital, and from local to cloud computing, I see generative AI as yet another significant shift.</description>
			<content type="html"><![CDATA[<p>For a little while, I&rsquo;ve been considering the potential impact of generative Artificial Intelligence on various areas of our lives, more recently I&rsquo;ve had very interesting conversations about applying AI to help the creations of manga/animé. This blurb was writing to help think through the challenges, but why not posting them.</p>
<p>Having witnessed the transition from analog to digital, and from local to cloud computing, I see generative AI as yet another significant shift.</p>
<blockquote>
<p>As an engineer, <strong>my focus is on enhancing human creativity and simplifying technical barriers to fun and self-expression</strong>. I advocate for a <strong>human-centric approach to AI</strong>, emphasizing user assistance over just output focus. Engaging in R&amp;D is vital, but it should align with addressing real human challenges.</p>
</blockquote>
<p>I&rsquo;m hesitant about the current generative AI approach most companies take. This may stem from my passion for real-time 3D rendering, but I&rsquo;ve observed a clear trend towards 3D (or 2.5D) in animation and I&rsquo;m concerned that focusing solely on 2D would be a bad thing for the industry and for storytelling in general.</p>
<p>To help me think through the process, I took <a href="https://www.imdb.com/title/tt21030032/">[Oshi no Ko]</a> as a recent example of an outstanding manga adaptation.</p>
<h3 id="current-parts-of-the-creative-process">Current parts of the creative process</h3>
<ul>
<li><strong>Character Design:</strong> Essential for translating manga, encompassing not just size and emotions, but also style elements like outlines, shadows, and blush.</li>
</ul>
<p><img src="/images/oshi-no-ko-char-1.png" alt="character design example"></p>
<p><img src="/images/oshi-no-ko-char-2.png" alt="character design example 2"></p>
<ul>
<li><strong>Storyboarding:</strong> Outlines the cuts, camera angles, lens, and motions.</li>
</ul>
<p><img src="/images/oshi-no-ko-storyboard.png" alt="storyboard example"></p>
<ul>
<li><strong>Environments:</strong> Backgrounds and props.</li>
</ul>
<p><img src="/images/oshi-no-ko-env.png" alt="3D-Environment example"></p>
<ul>
<li><strong>Colorization:</strong></li>
</ul>
<p><img src="/images/oshi-no-ko-colors.png" alt="color palette"></p>
<ul>
<li>
<p><strong>Art Approach/Compositing:</strong> Inklines, outlines, smears, shadows, color grading, particles, lights, basically putting everything together.</p>
</li>
<li>
<p><strong>Animation:</strong>
I skipped the most time-consuming aspect: traditional animation, involving &ldquo;hand-drawing&rdquo; or mocap, like the dance scenes in this example.</p>
</li>
</ul>
<p><img src="/images/oshi-no-ko-mocap.png" alt=""></p>
<p><img src="/images/keyframe-yoshitaka-mano.jpeg" alt=""></p>
<video width=100% id="loopedVideo" muted>
    <source src="/images/animation-example.mp4" type="video/mp4">
    Your browser does not support the video tag.
</video>
<p>This is the very well known/documented process of drawing keyframes and in-betweens. It&rsquo;s a tedious process a lot of folks have been trying to improve over time. The challenge is to maintain a human touch while also going fast. We see more and more of mix of 3D rendered + 2D drawing on top.</p>
<p>A significant challenge arises in the later stages when directors often want to modify storyboards or change elements like camera angles and lighting. This leads to expensive revisions. In contrast, the video game industry benefits from real-time rendering, allowing for quicker adjustments in animation, lighting, and camera work.</p>
<p>In [Oshi no Ko], only the backgrounds and dance scenes were 3D modeled and animated; the rest was hand-drawn. While large studios are shifting to 3D, the transition is not trivial for 2D animators.</p>
<h2 id="so-where-does-generative-ai-fit-in">So, where does generative AI fit in?</h2>
<ol>
<li><strong>Facilitating the 2D-to-3D Transition:</strong> Offering real-time previews and more flexible, faster, accessible workflows.</li>
<li><strong>Streamlining Processes:</strong> Letting artists focus on impactful storytelling elements.</li>
</ol>
<h3 id="facilitating-the-2d-to-3d-transition">Facilitating the 2D-to-3D Transition</h3>
<p>Tools such as <a href="https://www.blender.org/features/story-artist/">Blender&rsquo;s Grease Pencil</a> or <a href="https://www.dillongoostudios.com/gooengine">Goo&rsquo;s Engine</a> are making things easier, but artists have to think in 3D, which is harder than it sounds.</p>
<p>The reality is that newer artists will adapt more readily to 3D, but this transition won’t be instantaneous. AI can greatly simplify the process by automating some of the more intricate and tedious aspects. For instance:</p>
<ul>
<li>
<p><strong>Transforming character art into a comprehensive 3D model</strong>, including a single face mesh, blendshapes, animation tracks, face normals, and detailed settings for materials, shaders, and shadows. It also involves overlaying 2D assets like outlines, inklines, and blush on the 3D mesh. While the character may not be perfect initially, this step completes a substantial portion of the work. (and IMHO they key to do that is to generate code, not directly 3D assets)</p>
</li>
<li>
<p><strong>Automating and reusing animations.</strong> Animation fundamentally involves keyframes that move specific bones. AI models can rapidly produce high-quality animations and smoothly transition between them. (and they MUST to be manually editable)</p>
</li>
<li>
<p><strong>Generating backgrounds, environments, and props.</strong> Instead of creating full-fledged 3D environments, various shortcuts like skyboxes can be used for static scenes, while normal maps and PBR textures applied to low-poly meshes (generated by diffusion models or extracted from diffusion outputs) can create dynamic settings. A notable (free) example of a partial approach is <a href="https://stableprojectorz.com/">https://stableprojectorz.com/</a>. In this specific case, processing manga pages to identify and extract recurring props can be immensely helpful. Training a model to recognize these objects and either find matches in an asset database or generate synthetic data to create 3D models and/or materials/textyres can save countless hours, especially for artists less versed in 3D modeling.</p>
</li>
<li>
<p><strong>Creating rudimentary 3D scenes</strong> that can be refined and incorporated into control networks for video-to-video conversions and producing complex animated backgrounds, not limited by current diffusion model constraints.</p>
</li>
<li>
<p><strong>Producing shaders and materials</strong> to ensure consistent and editable colorization.</p>
</li>
</ul>
<p>These are just a few examples, and there’s much more potential, but time is limited.</p>
<h3 id="streamlining-processes">Streamlining Processes</h3>
<p>The focus should be on crafting a <strong>genuine &ldquo;product&rdquo; experience</strong>, where creators can concentrate on storytelling, liberated from technical complexities. Given that anime often follows recognizable patterns, this could be leveraged to offer immediate creative options or opportunities to deviate from the norm. The goal is for a director or even a mangaka to develop a solid episode prototype, which can then be refined by the team. All the elements mentioned in point #1 will underpin this product-focused approach. <strong>This strategic direction will define a startup&rsquo;s success, distinguishing them from merely being a service provider or consultancy.</strong> It&rsquo;s a challenging path, requiring disciplined decision-making and effective success metrics.</p>
<blockquote>
<p>In conclusion, employing AI should go beyond mere generation of 2D images or vectors. It&rsquo;s about reimagining the entire creative process, making each step more adaptable (with a strong emphasis on 3D), automating predictable elements (like materials, shapes, and animations), and providing creators the tools to manually refine and personalize their work. It’s crucial to allow for experimentation and discovery, which will prevent the end result from being just a less expensive version of existing content.</p>
</blockquote>
<script>
    var video = document.getElementById('loopedVideo');
    var playCount = 0;
    let maxPlays = 2;

    // Function to check if the video is in view
    function checkIfVideoInView() {
        var rect = video.getBoundingClientRect();
        var partlyVisible = rect.bottom > 0 && rect.top < (window.innerHeight || document.documentElement.clientHeight);
    return partlyVisible;
    }

    // Play the video if it's in view
    function playVideoIfNeeded() {
      if (checkIfVideoInView()) {
          if (playCount < maxPlays) {
            if (video.paused && !video.ended) {
                video.play();
            }
          }
        } else {
            video.pause();
            if (playCount != 0) {
              playCount = 0;
            }
        }
    }

    // Event listener for scrolling
    window.addEventListener('scroll', playVideoIfNeeded);

    // Event listener for video playing
    video.addEventListener('play', function () {
        video.playing = true;
    });

    // Event listener for video ending
    video.addEventListener('ended', function () {
        playCount++;
        // console.log("video ended");
        video.playing = false;
        if (playCount >= maxPlays) {
            video.pause();
            video.currentTime = 0; // Reset to start
        } else {
          video.play();
        }
    });
</script><blockquote>
</blockquote>
]]></content>
		</item>
		
		<item>
			<title>Solving real time collaboration using Eventual Consistency</title>
			<link>https://matt.aimonetti.net/posts/2020-09-solving-real-time-collaboration-using-eventual-consistency/</link>
			<pubDate>Wed, 09 Sep 2020 09:32:51 -0700</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2020-09-solving-real-time-collaboration-using-eventual-consistency/</guid>
			<description>The collaboration problem: overwriting each other changes In traditional online applications, when you make a modification to the state of the object you work on, the change propagates to a central server that holds the “truth”. The server registers the change and sends back a confirmation that the change was indeed applied.
The problem happens when Alice and Bob try to update the same database field at the same time. At this point, there will be a data race and whichever request gets to the database last, will “win”, the other will be discarded.</description>
			<content type="html"><![CDATA[<h2 id="the-collaboration-problem-overwriting-each-other-changes">The collaboration problem: overwriting each other changes</h2>
<p><img src="/images/eventual-consistency/rest-overwriting.svg" alt=""></p>
<p>In traditional online applications, when you make a modification to the state of the object you work on, the change propagates to a central server that holds the “truth”. The server registers the change and sends back a confirmation that the change was indeed applied.</p>
<p>The problem happens when Alice and Bob <strong>try to update the same database field at the same time</strong>. At this point, there will be a <strong>data race</strong> and whichever request gets to the database <strong>last, will “win”, the other will be discarded</strong>.  That’s quite a jarring experience especially because round-trip latency of up to a second aren’t unusual (especially on mobile), so Alice might have moved on thinking their change applied, only to realize later on that it was overwritten. This is quite regrettable especially since those two updates aren’t technically conflicting, they are modifying different parts of the same string.</p>
<blockquote>
<p>This traditional approach wasn’t designed with real time collaboration in mind and it naturally induces latency and flow challenges, making the collaboration experience worse.</p>
</blockquote>
<p>One way to work around the latency and some of the conflict resolutions challenges is to <strong>pretend that we don’t need to talk to a server and that all changes are local</strong>. This is the approach the <a href="https://fluidframework.com">Fluid framework</a> chose.  Fluid still needs to <strong>eventually have all collaborators agree on the current state of our object(s) and has to avoid all conflicts</strong>. For that, it relies on <strong>eventual consistency provided by distributed data structures</strong>.</p>
<p><a href="https://fluidframework.com">Fluid</a> abstracts the networking and backend layers so developers can focus on building an user experience by only thinking “local”. There isn’t a centralized canonical data truth to check against anymore, instead all connected users have the data locally and all these users always eventually end up with the exact same data. This “local” approach allows for a zero latency experience while keeping data consistent.</p>
<h2 id="eventual-consistency-using-special-data-structures">Eventual consistency using special data structures</h2>
<h3 id="example-alice-and-bob-are-co-editing-a-document-at-the-same-time">Example: Alice and Bob are co-editing a document at the same time</h3>
<p><strong>Alice and Bob both load a Fluidified application</strong>. The User Interface uses <strong>Fluid to load and manage the state</strong> of its underlying data. The application <strong>page has a title</strong> for which the initial state is loaded by <a href="https://fluidframework.com">Fluid</a> from a server, the title reads “hello world!”</p>
<p><img src="/images/eventual-consistency/fluidified-string.svg" alt="Fluid setup"></p>
<hr>
<p><strong>Alice edits the title</strong> so it reads “hello Alice!”, the change is applied right away to the data structure representing the title and an operation representing the change is sent to the <a href="https://fluidframework.com">Fluid server</a> to propagate to all connected collaborators.</p>
<p><img src="/images/eventual-consistency/Alice-change.svg" alt="Alice edits the title"></p>
<p>A new operation is sent to the <a href="https://fluidframework.com">Fluid server</a>:
<code>Replace characters at position 6, new content: &quot;Alice&quot;</code></p>
<hr>
<p><strong>At the very same time, Bob edits the title too</strong>. He injects an upside down exclamation mark so the title reads “¡hello world!”. The change is reflected right away on Bob’s screen and an operation is sent to the <a href="https://fluidframework.com">Fluid server</a> to propagate to the connected collaborators.</p>
<p><img src="/images/eventual-consistency/bob-change.svg" alt="Bob edits the same title"></p>
<p>A new operation is sent to the <a href="https://fluidframework.com">Fluid server</a>:
<code>Insert character at position 0, new content: &quot;¡&quot;</code></p>
<hr>
<p>Even though Alice and Bob edited the same text at the same time, both saw their change being <strong>applied right away</strong> and then saw their <strong>collaborator changes being applied without any conflicts</strong>. They <strong>eventually</strong> both see the same <strong>consistent title</strong>.</p>
<p><img src="/images/eventual-consistency/final-string.svg" alt="Final string"></p>
<hr>
<h2 id="summary">Summary</h2>
<p>By breaking down content into <strong>smart linked structures that know how to deal with granular changes</strong>, and can handle potential conflicts on each user’s device, users never wait for anything to happen and therefore feel like there isn’t any latency . Those <strong>smart structures are referred as Distributed Data Structures</strong> (DDSes) in <a href="https://fluidframework.com">Fluid</a> parlance and are the key to making Fluid feel real time. <strong>Fluid offers various DDSes</strong> to cover the diverse needs of developers besides working on a collaborative text. Most DDSes link one to one to known structures such as strings, maps or linked lists. <strong>Developers can focus solely on the creation of amazing User Experiences and data modeling</strong>, <em>the underlying concerns such as connectivity, data transfer and applying of operations and conflict resolutions are handled by the framework</em>.</p>
]]></content>
		</item>
		
		<item>
			<title>Automating a Linux in Windows dev setup</title>
			<link>https://matt.aimonetti.net/posts/2020-08-automating-a-linux-in-windows-dev-setup/</link>
			<pubDate>Mon, 03 Aug 2020 10:37:07 -0700</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2020-08-automating-a-linux-in-windows-dev-setup/</guid>
			<description>Last time I used Windows on my main development machine was sometime in the early 2000s. Over the years, I had several side Windows machines (usually because I needed Visual Studio) but I was never really serious about using a PC as my main dev machine. Things have changed a lot in almost 20 years, and especially recently. Apple is moving to ARM and to everybody&amp;rsquo;s shock the Windows team has been investing in letting us run Linux distributions &amp;ldquo;natively&amp;rdquo; for a few years now!</description>
			<content type="html"><![CDATA[<p>Last time I used Windows on my main development machine was sometime in the
early 2000s. Over the years, I had several side Windows machines (usually
because I needed Visual Studio) but I was never really serious about using a PC
as my main dev machine. Things have changed a lot in almost 20 years, and
especially recently. <a href="https://www.apple.com/newsroom/2020/06/apple-announces-mac-transition-to-apple-silicon/">Apple is moving to ARM</a> and to everybody&rsquo;s shock
the Windows team has been <a href="https://www.theverge.com/2020/5/19/21263377/microsoft-windows-10-linux-gui-apps-gpu-acceleration-wsl-features">investing</a> in letting us run Linux distributions &ldquo;natively&rdquo; for a <a href="https://blogs.windows.com/windowsdeveloper/2017/08/08/windows-subsystem-linux-windows-server/">few years</a> now!</p>
<figure><img src="/images/microsoftloveslinux.jpg"/><figcaption>
            <h4>Satya Nadella ❤️ Linux by The Verge</h4>
        </figcaption>
</figure>

<p>Microsoft used to have <a href="https://visualstudiomagazine.com/articles/2018/09/17/microsoft-open-source.aspx">an extremely negative view of Open Source</a> but under a <a href="https://en.wikipedia.org/wiki/Satya_Nadella">new
leadership</a> things have changed and they are making some drastic changes to be
more welcoming to FOSS developers.</p>
<p><strong>Could Windows provide me with a similar or maybe even better developer experience than macOs?</strong></p>
<p>There is only way to know: I need to a Windows machine as my main driver. To be clear, <strong>I&rsquo;m not trying to confirm/deny that Windows is becoming a better dev solution for developers in general</strong>. I&rsquo;m only focusing on my own case: an open source developer coding using open source languages such as TypeScript, Go, Python, Rust and years of experience using Unix/Linux.</p>
<p>The first thing I wanted to try was to automate the setup of my Windows and Linux
machine. I&rsquo;ve been spoiled by Docker for years and I love reproducible
environments. Here is my journey automating the set up of my Windows/linux dev environment.</p>
<h2 id="installing-linuxubuntu-on-windows">Installing Linux/Ubuntu on Windows</h2>
<p>The idea of having to use the Command Prompt or Regexit is reminding me of a
distant past full of pain and anger. Let&rsquo;s start by making this place a familiar
home and install Ubuntu (Linux). Turns out you can install Linux from the app
store thanks to a Windows 10 feature called <a href="https://docs.microsoft.com/en-us/windows/wsl/about">the Windows Subsystem for
Linux (WSL)</a>. The sales pitch
is that you can run a GNU/Linux environment, including most command-line tools,
utilities, and applications directly on Windows, unmodified, without the
overhead of a traditional virtual machine or dualboot setup. You pick your Linux
distribution from the Microsoft store, install it, and boom it runs locally. You
can even invoke Windows applications using a Unix-like command-line shell and
invoke GNU/Linux applications from Windows (you can even <a href="https://docs.microsoft.com/en-us/windows/wsl/interop#mixing-linux-and-windows-commands">mix and
match</a>
which is pretty crazy).</p>
<p><em>Bash command to copy the SSH key to the Windows clipboard</em></p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ cat ~/.ssh/id_rsa.pub | clip.exe
</code></pre></div><p>For Machine Learning devs, there&rsquo;s an extra good news:
you can <a href="https://docs.microsoft.com/en-us/windows/wsl/tutorials/gpu-compute">leverage your machine
GPU</a> from
the Linux side (how many times did I wish I could use a GPU on my Mac?) WSL has
been around for a little while and Microsoft recently released
<a href="https://docs.microsoft.com/en-us/windows/wsl/about#what-is-wsl-2">WSL2</a> to
address some performance issues (and give Linux programs access to the GPU).</p>
<h3 id="enabling-windows-subsystem-for-linux">Enabling Windows Subsystem for Linux</h3>
<p>To enable <a href="https://docs.microsoft.com/en-us/windows/wsl/wsl2-index">WSL2</a>, you have to be on <a href="https://docs.microsoft.com/en-us/windows/whats-new/whats-new-windows-10-version-2004">Windows 10 version 2004 (20H1)</a>. I know, the naming is
super confusing, this isn&rsquo;t the version from the year 2004 but the free update
that was released last May. Windows stopped giving brand new names to updates. A
bit like Mac OS X/MacOS but without the cute cat and location names. Since I was
on this latest version, installing WSL and Ubuntu was trivial and took a few
minutes. I just followed <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10">this very straightforward
tutorial</a>.</p>
<ol>
<li>Launch PowerShell as Administrator (click the start menu, type PowerShell, expand the options and pick run as Administrator).</li>
<li>Type <code>dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart</code></li>
<li>Type <code>dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart</code></li>
<li>Restart your machine manually</li>
</ol>
<h3 id="installing-ubuntu">Installing Ubuntu</h3>
<p>At this point, WSL2 is setup, and we need to pick a Linux flavor (aka distro or
distribution). I picked
<a href="https://www.microsoft.com/store/apps/9pjn388hp8c9">Ubuntu</a> from the Microsoft
Store (it&rsquo;s free and you don&rsquo;t need to signup or anything).</p>
<figure><img src="/images/Get_Ubuntu_-_Microsoft_Store.png"/><figcaption>
            <h4>Ubuntu on the Microsoft store</h4>
        </figcaption>
</figure>

<p>Ubuntu installed
automatically on my machine in a few seconds and I got a prompt to set my linux
username/password and I was done.</p>
<p><img src="https://docs.microsoft.com/en-us/windows/wsl/media/ubuntuinstall.png" alt="Ubuntu prompt to set admin user"></p>
<p>All in all, it probably took me less than 10 minutes, I&rsquo;m impressed!
Furthermore, I really like that I can run multiple versions of Linux while
maintaining my main OS very stable. I did mess up my mac stability a few time
when installing dependencies for some of the software I was developing. Also,
it&rsquo;s nice to be on a true Linux system, the same as the one I deploy to and it&rsquo;s
much lighter/easier than having to run everything in Docker.</p>
<h3 id="tips">Tips</h3>
<p>You might want to <a href="https://docs.microsoft.com/en-us/windows/wsl/wsl-config#configure-global-options-with-wslconfig">configure how much
resource</a>
you allocate to WSL if you feel Windows doesn&rsquo;t get enough resources (you can also
shut down the linux instance(s)).</p>
<p>You can export/import WSL distributions by using the wsl command from the windows side:</p>
<p>In Command Prompt, start by creating the folders we need</p>
<pre><code>&gt; mkdir %HOMEPATH%\Data\wsl\exports %HOMEPATH%\Data\wsl\distros
</code></pre><p>Then export the target Distro (here called Ubuntu)</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">&gt; wsl --export Ubuntu %HOMEPATH%/Data/wsl/exports/ubuntu_%DATE:~10,4%%DATE:~4,2%%DATE:~7,2%.tar
</code></pre></div><p>This created a distribution dump dated with today&rsquo;s date.</p>
<p>We can then import it to create a new distribution/instance.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">&gt; wsl --import UbuntuReloaded %HOMEPATH%/Data/wsl/distros/ubuntuReloaded %HOMEPATH%/Data/wsl/exports/ubuntu_20200730.tar
</code></pre></div><p>The new distribution is called UbuntuReloaded and is a copy of the first instance. This is practical if you want to run a distro for Python and one for JS for instance. It&rsquo;s also a nice way to backup an environment.</p>
<p>You can see the current distributions and their status by using:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">&gt; wsl -l -v
</code></pre></div><p><em>Note that exporting the distro requires shutting down the distro automatically, so save your work before running this command.</em></p>
<p><em>Note also that when importing an exported distro, wsl logs you in as root instead of the created admin user (which is obviously there).</em></p>
<figure><img src="/images/ubundos.jpeg"/><figcaption>
            <h4>Ubuntu running on Windows</h4>
        </figcaption>
</figure>

<h2 id="tooling--scripting">Tooling &amp; scripting</h2>
<p>One of the many reasons I was interested in doing all my development on Linux is
that I deploy my production code on Linux machines, so might as well develop on the
same platform I deploy to. I&rsquo;m also super familiar with Unix/Linux, not so much
with Windows. And while I can run code via the command prompt or PowerShell, I
really prefer not to and I miss my good old Terminal.</p>
<h3 id="terminal">Terminal</h3>
<p>Turns out Microsoft developed a great <a href="https://docs.microsoft.com/en-us/windows/terminal/">Terminal for Windows</a> (and they <a href="https://github.com/microsoft/terminal">open sourced it</a>)! It just doesn&rsquo;t ship with Windows but you can install it <a href="https://www.microsoft.com/en-us/p/windows-terminal/9n0dx20hk701">directly from the store</a>.</p>
<figure><img src="https://docs.microsoft.com/en-us/windows/terminal/images/overview.png"/><figcaption>
            <h4>Windows Terminal with panes for PowerShell, cmd and bash</h4>
        </figcaption>
</figure>

<h3 id="installation-script">Installation script</h3>
<p>Besides Terminal, I need a few other tools, drivers and software to make my
Windows machine truly useable. And like a lot of developers I like automating
things. Partly because I&rsquo;m a bit lazy but mainly because I hate to repeat the
same task over and over. So I decided to write a script to set up the Windows
and Linux side of things.</p>
<p>The idea is simple, I want to automate everything from the Linux side and for
that I&rsquo;ll use a <a href="https://gist.github.com/mattetti/9807e2a1e654a7c00bb9c13f340fc39f">bash script</a> that I will backup on github as a <a href="https://gist.github.com/mattetti/9807e2a1e654a7c00bb9c13f340fc39f">gist</a> so I will
eventually be able to pull it down and run it from a new machine. The bash
script is not designed to be generic but instead focuses on my machine with <strong>my dev env, my Windows apps, an option to install the device apps/drivers I might need</strong>.</p>
<h4 id="dot-files">dot files</h4>
<p>My Linux config files (dotfiles) are shared between my machines using a tool called
<a href="https://github.com/twpayne/chezmoi#what-does-chezmoi-do-and-why-should-i-use-it">chezmoi</a> and GitHub. I&rsquo;m still planning on using my Mac and various other machines so managing my configs across machines makes a lot of sense.</p>
<h4 id="editor">Editor</h4>
<p>I switched my editor to VSCode a long time and have been using a VSCode extension to keep my configuration/settings synchronized across machines. Note that I want VSCode to display on the Windows side but run code and tools from the Linux side (my programming tools won&rsquo;t be installed on the Windows side).
<em>Note that the extension won&rsquo;t be needed soon since <a href="https://code.visualstudio.com/docs/editor/settings-sync">VSCode
is going to have settings synchronization
built-in</a>.</em></p>
<p><img src="https://code.visualstudio.com/assets/docs/editor/settings-sync/turn-on-sync.png" alt="VSCode Preference sync option"></p>
<p>That said, there are still a bunch of things to coordinate so let me walk you
through what <a href="https://gist.github.com/mattetti/9807e2a1e654a7c00bb9c13f340fc39f">My
script</a> does
and how it does it.</p>
<h4 id="calling-the-windows-side-from-linux">Calling the Windows side from Linux</h4>
<p>The first trick is to get the Windows home path since we are going to need it for a few things. This is done using WSL specific linux commands called <code>wslpath</code> and <code>wslvar</code>.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">export WINHOME<span style="color:#f92672">=</span><span style="color:#66d9ef">$(</span>wslpath <span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">$(</span>wslvar USERPROFILE<span style="color:#66d9ef">)</span><span style="color:#e6db74">&#34;</span><span style="color:#66d9ef">)</span>
</code></pre></div><p>Then we wrap a calling winget from Linux:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#75715e"># winget calls winget on the windows side</span>
<span style="color:#66d9ef">function</span> winget <span style="color:#f92672">{</span> <span style="color:#e6db74">&#34;cmd.exe /C winget.exe </span>$1<span style="color:#e6db74"> </span>$2<span style="color:#e6db74"> </span>$3<span style="color:#e6db74">&#34;</span>;<span style="color:#f92672">}</span>
</code></pre></div><h4 id="windows-package-manager">Windows package manager</h4>
<p><a href="https://github.com/microsoft/winget-cli">winget</a> is the new Microsoft package
manager, the equivalent of homebrew but for Windows and officially developed by
Microsoft. As I&rsquo;m writing this article, winget is still in preview but it&rsquo;s
maturing quickly. Winget must be installed on the Windows side for the script to
work, so we are going to need to check if it&rsquo;s available before going further.</p>
<figure><img src="https://docs.microsoft.com/en-us/windows/package-manager/winget/images/install.png"/><figcaption>
            <h4>Installing PowerToys using winget</h4>
        </figcaption>
</figure>

<p>The bash script to check if winget is available on the windows side looks like that:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">wingetAlert<span style="color:#f92672">()</span> <span style="color:#f92672">{</span>
    echo <span style="color:#e6db74">&#34;winget could not be found&#34;</span>
    echo <span style="color:#e6db74">&#34;make sure winget is installed and available and restart this script - https://www.microsoft.com/en-us/p/app-installer/9nblggh4nns1&#34;</span>
    cmd.exe /C start <span style="color:#e6db74">&#34;https://www.microsoft.com/en-us/p/app-installer/9nblggh4nns1&#34;</span>
    exit
<span style="color:#f92672">}</span>

<span style="color:#75715e"># checking that winget is installed on the windows side</span>
ifCMDNotAvail <span style="color:#e6db74">&#34;winget.exe&#34;</span> wingetAlert
</code></pre></div><p>We are calling the <code>ifCMDNotAvail</code> function and passing 2 arguments, the name of the executable to check and the function to call if winget isn&rsquo;t available.
The alert prints some text and then opens the Microsoft store page for winget by using the Windows start.exe command.</p>
<p><code>ifCMDNotAvail</code> is a function using <code>command -v</code> to see if a command available or not, if it&rsquo;s not, then the second argument is called.</p>
<h4 id="installing-windows-applications">Installing Windows applications</h4>
<p>Here is the block of code installing the apps I&rsquo;d like if they aren&rsquo;t already installed:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">ifPathNotAvailWinInstall <span style="color:#e6db74">&#34;/mnt/c/Program Files/PowerToys/PowerToys.exe&#34;</span> Microsoft.Powertoys
ifCMDNotAvail <span style="color:#e6db74">&#34;wt.exe&#34;</span> Microsoft.WindowsTerminal
ifPathNotAvailWinInstall <span style="color:#e6db74">&#34;</span>$WINHOME<span style="color:#e6db74">/AppData/Local/1Password/app/7/1Password.exe&#34;</span> AgileBits.1Password
ifPathNotAvailWinInstall <span style="color:#e6db74">&#34;/mnt/c/Program Files/VideoLAN/VLC/vlc.exe&#34;</span> VideoLAN.VLC
ifPathNotAvailWinInstall <span style="color:#e6db74">&#34;/mnt/c/Program Files/7-Zip/7z.exe&#34;</span> 7zip
ifPathNotAvailWinInstall <span style="color:#e6db74">&#34;/mnt/c/Program Files (x86)/Adobe/Acrobat Reader DC/Reader/AcroRd32.exe&#34;</span> Adobe.AdobeAcrobatReaderDC

ifCMDNotAvail code installVSCode
</code></pre></div><p>Without going through the full explanation, we do a check on the command or path and call <code>winget</code> on the Windows side with the name of the package to install.
Pretty straightforward.</p>
<h4 id="linux-setup">Linux setup</h4>
<p>Nothing really special here, just installing my tools the linux way locally :)
Something interesting to show is how I setup my ssh key.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash"><span style="color:#66d9ef">function</span> setupSSHKey <span style="color:#f92672">{</span>
    echo <span style="color:#e6db74">&#34;Setting up Git&#34;</span>
    ssh-keygen -t rsa -b <span style="color:#ae81ff">4096</span> -C <span style="color:#e6db74">&#34;myemail@domain.com&#34;</span>
    echo <span style="color:#e6db74">&#34;new SSH key generated&#34;</span>
    ssh-agent
    ssh-add ~/.ssh/id_rsa
    cat ~/.ssh/id_rsa.pub | clip.exe
    cmd.exe /C start https://github.com/settings/ssh/new
    echo <span style="color:#e6db74">&#34;Your new ssh key was added to your clipboard, add it to GitHub (and consider turning on SSO)&#34;</span>
    echo <span style="color:#e6db74">&#34;Press any key when your key was added to GitHub&#34;</span>
    <span style="color:#66d9ef">while</span> true; <span style="color:#66d9ef">do</span>
        read -t <span style="color:#ae81ff">3</span> -n <span style="color:#ae81ff">1</span>
        <span style="color:#66d9ef">if</span> <span style="color:#f92672">[</span> $? <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span> <span style="color:#f92672">]</span> ; <span style="color:#66d9ef">then</span>
            break;
        <span style="color:#66d9ef">else</span>
            echo <span style="color:#e6db74">&#34;waiting for the keypress&#34;</span>
        <span style="color:#66d9ef">fi</span>
    <span style="color:#66d9ef">done</span>
<span style="color:#f92672">}</span>
</code></pre></div><p>I&rsquo;m definitely not a bash expert, far from it but the part that&rsquo;s interesting here is how I load the ssh key into the windows clipboard and open GitHub so I can paste it right there. I accomplish that by piping the result of the linux <code>cat</code> command into the Windows <code>clip.exe</code> command.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">cat ~/.ssh/id_rsa.pub  | clip.exe
</code></pre></div><p>Honestly, this blew my mind the first time I wrote this line and it just worked.</p>
<p>So <a href="https://gist.github.com/mattetti/9807e2a1e654a7c00bb9c13f340fc39f">Here</a> it is, the full script. Probably a work in progress, but I&rsquo;m quite happy with how convenient and maintainable this solution is. I got a new PC and was able to get it up and running in less than 30 minutes 🥳</p>
]]></content>
		</item>
		
		<item>
			<title>New Challenge</title>
			<link>https://matt.aimonetti.net/posts/2020-07-new-challenge/</link>
			<pubDate>Mon, 13 Jul 2020 08:42:42 -0700</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2020-07-new-challenge/</guid>
			<description>We&amp;rsquo;re approaching the first anniversary of when I stepped down from my operating role at Splice. The company kept on growing rapidly and be impactful, I am very proud of what the team is doing to change things from within the music industry.
I had a blast during my time off:
 I worked on a great project with Grimes which we started previewing but had to put on hold because of covid-19.</description>
			<content type="html"><![CDATA[<p>We&rsquo;re approaching the first anniversary of when <a href="https://matt.aimonetti.net/posts/2019-08-moving-on-with-gratitude/">I stepped down from my operating role at Splice</a>. The company kept on <a href="https://variety.com/2020/music/news/splice-sound-downloads-surge-1234597135/">growing rapidly</a> and be impactful, I am very proud of what <a href="https://variety.com/2020/music/news/splice-maria-egan-jen-mozenter-1234634399/">the team</a> is doing to <a href="https://variety.com/2020/music/news/splice-payouts-25-million-dollars-creators-female-producers-1203498893/">change things from within the music industry</a>.</p>
<p>I had a blast during my time off:</p>
<ul>
<li>I worked on a great project with Grimes which we started previewing but had to put on hold because of covid-19.</li>
<li>I had the privilege to listened to, coach and mentor talented startup leaders.</li>
<li>I hacked on so many research projects and learned a ton.</li>
<li>Due to the lockdown, I became an unqualified homeschool teacher and was able to spend time with my kids.</li>
<li>Finally, I was able to spend a lot of time reflecting and discuss with so many smart people. Having this time for myself has been invaluable given the current world situation.</li>
</ul>
<figure><img src="/images/ai_meditations_screengrab.jpg"/><figcaption>
            <h4>Preview of AI Meditations (collaboration with Grimes)</h4>
        </figcaption>
</figure>

<h2 id="generic-findings">Generic findings</h2>
<p>My goal was to use this time to <strong>better understand myself and the world around me.</strong> Here are 4 things that I found exacerbated by the coronavirus crisis:</p>
<ol>
<li><em><strong>We want and need to be active</strong></em>, not passive (<a href="https://www.washingtonpost.com/video-games/2020/05/12/video-game-industry-coronavirus/">During the pandemic the increase in video gaming dwarfed the increase in Netflix/video streaming</a>).</li>
<li><em><strong>We want to develop ourselves, grow</strong></em>, we might not always have the tools to do so, but are driven by some sort of growth feeling (from playing Animal Crossing to DYI or learning new skills).</li>
<li><em><strong>Ego is a powerful enemy</strong></em>. This bullet point would require a full post on its own, but the short version is that many not-ideal decisions are based on ego and results in missed opportunities or worse.</li>
<li><em><strong>We&rsquo;re less and less of a social society</strong></em>. We might have huge social networks, I think it&rsquo;s pretty clear to everyone who suffered from the lockdown that we somewhat become so self-centered that we lost real/deep human connections.</li>
</ol>
<h2 id="personal-insights">Personal insights</h2>
<p>Besides these generic point, <strong>here is what I learned about myself</strong>:</p>
<p>While I started my journey wanting to focus on impact, I realized that <strong>measuring personal impact is surprisingly subjective</strong>. This is a topic that would deserve more time, but the short version is that chasing impact seems to be a fool&rsquo;s errand that might lead to megalomania. <strong>Maintaining and increasing one&rsquo;s happiness while having a positive impact on others is probably a better goal</strong> (at least more measurable).</p>
<p><img src="/images/mediterranean.jpg" alt="ingredients"></p>
<p>To increase my happiness I found a few required ingredients:</p>
<ol>
<li><em><strong>hard challenges that I haven&rsquo;t yet accomplished</strong></em></li>
<li><em><strong>a team of people I respect and want to collaborate with</strong></em></li>
<li><em><strong>a sense of progress</strong></em></li>
</ol>
<p>Writing down those bullet points, I realize that they might not seem like big revelations. After all, aren&rsquo;t we all after those 3 things? The thing is though, <em><strong>I can&rsquo;t be happy unless I have those three things</strong></em>. I can tolerate not having of those items for a little bit but if the situation doesn&rsquo;t get fixed, I quickly burnout or move on.</p>
<p>The other thing I realized is that <em>I need to be active, I need to be focused and I need be seriously challenged or I eventually lose sense of &ldquo;active purpose&rdquo;</em>. The covid19 lockdown made this very clear, even if I thought that I could just chill and hack on a new project every week. Instead I needed and wanted to focus on a new challenge with people that would push me to become even better.</p>
<h2 id="my-new-adventure">My new adventure</h2>
<p>The direction I chose might surprise some of you, I have to admit it&rsquo;s a bit of an unorthodox and unexpected move but I think it&rsquo;s the right thing for me. <em><strong>I&rsquo;m not becoming a VC, developing modular synths nor jumping back on a new startup, instead I&rsquo;m joining Microsoft and will work on on new technology focusing on collaboration</strong></em> (the tech will be free and open sourced). I&rsquo;m particularly excited to rethink the concept of open source within a 2020 and enterprise context of 2020. Open Source evolved in surprising ways and there is an opportunity to help the overall tech community, I&rsquo;m looking forward to this challenge.
Finally, <strong>I&rsquo;m very thankful that most of my work with be done transparently and in the open</strong>. So while It&rsquo;s premature for me to share more details, <strong>I&rsquo;m looking forward to blogging/posting more and hear your feedback</strong>.</p>
<p><img src="https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31" alt="Microsoft"></p>
]]></content>
		</item>
		
		<item>
			<title>Our first Braintrust LA Event</title>
			<link>https://matt.aimonetti.net/posts/2020-01-our-first-braintrust-la-event/</link>
			<pubDate>Fri, 31 Jan 2020 10:05:48 -0800</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2020-01-our-first-braintrust-la-event/</guid>
			<description>This week, Chang Xu and I are running our very first Braintrust LA event. While the event is private and we won&amp;rsquo;t talk about who&amp;rsquo;s presenting and who&amp;rsquo;s attending, I wanted to share with you a note we wrote to the attendees.
The idea of organizing Braintrust LA came to us when we discussed what we could do to help the LA ecosystem. Between the two of us, Chang as a VC and Matt as a founder, we wanted to find a selfless way to support entrepreneurs beyond introducing them to our networks or helping them with their decks.</description>
			<content type="html"><![CDATA[<p>This week, <a href="https://www.linkedin.com/in/changx/?lipi=urn%3Ali%3Apage%3Ad_flagship3_pulse_read%3BhvtzXUM3RriWJTOvhIQbrg%3D%3D">Chang Xu</a> and I are running our very first Braintrust LA event. While the event is private and we won&rsquo;t talk about who&rsquo;s presenting and who&rsquo;s attending, I wanted to share with you a note we wrote to the attendees.</p>
<p>The idea of organizing Braintrust LA came to us when we discussed what we could do to help the LA ecosystem. Between the two of us, Chang as a VC and Matt as a founder, we wanted to find a selfless way to support entrepreneurs beyond introducing them to our networks or helping them with their decks. We opted to follow an early Pixar key mechanism: the Braintrust. <strong>The concept is pretty simple, we put smart, passionate people in a room together and encourage them to be candid with one another. This process naturally pushes us towards excellence.</strong></p>
<p>We handpicked Braintrust attendees because we believe each of you have tremendous value to bring to the discussions and because we trust you. <strong>This process can only work if there is trust.</strong> Two Entrepreneurs trusted us and will make themselves vulnerable so they can benefit from the collective brain power in the room. And <strong>we trust each of you to be candid and benevolent.</strong></p>
<p>It&rsquo;s natural for attendees to have self-preservation tendencies causing you to hold back. But candor is forthrightness and frankness. Chang and I will be there to moderate. Entrepreneurs are constantly lied to, all the time, from friends to investors to even customers. <strong>The reason we are bringing you all together is to help the Entrepreneurs see what they might have missed and/or to learn from your experience. Don&rsquo;t hold back, let them hear what people are thinking but not telling them.</strong></p>
<p>The Braintrust, unlike a potential board of directors, has no authority. The Entrepreneur does not have to follow any of the specific suggestions given. After a Braintrust session, it&rsquo;s up to her or him to to figure out how to address the feedback. Braintrust meetings are obviously not top-down or do-this-or-else affairs. <strong>By removing from the Braintrust the power to mandate solutions, we affect the dynamic of the group in ways we believe will benefit entrepreneurs and Braintrust attendees.</strong></p>
<p><strong>The Braintrust feedback is never about asking for a specific remedy or answer. The Braintrust is benevolent. We are here to help and we have no selfish agenda.</strong></p>
]]></content>
		</item>
		
		<item>
			<title>Security Privacy &amp; Trust: Major 2020 Themes</title>
			<link>https://matt.aimonetti.net/posts/2020-01-security-privacy-trust-major-2020-themes/</link>
			<pubDate>Wed, 22 Jan 2020 09:45:16 -0800</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2020-01-security-privacy-trust-major-2020-themes/</guid>
			<description>Security, Privacy and Trust will be major themes in 2020. Looking at this arm report, 30% of surveyed folks were more concerned in 2019 over data privacy and security than they were in 2018. Add the elections, legal actions against Google &amp;amp; Facebook, Apple and others pushing for less tracking and safer data and we are going to see a huge need to push compute power to the edge (on device).</description>
			<content type="html"><![CDATA[<p><img src="/images/armReport.jpg" alt="ARM report"></p>
<p>Security, Privacy and Trust will be major themes in 2020. Looking at <a href="https://www.arm.com/blogs/blueprint/wp-content/uploads/2019/12/Arm-2020-Predictions-Report.pdf">this arm report</a>, 30% of surveyed folks were more concerned in 2019 over data privacy and security than they were in 2018. Add the elections, legal actions against Google &amp; Facebook, Apple and others pushing for less tracking and safer data and we are going to see a huge need to push compute power to the edge (on device).</p>
<p>A big problem is that we spent the last 10+ years centralizing compute on the cloud and now we need to also run major computations on user devices and we are nowhere ready for that (ML for instance runs very poorly on CPUs and uses a lot of battery). Expect lots of excuses and delays around securing data. Excuses will be made for at least another year or until someone steps up and uses that as a commercial advantage.</p>
<p>In the meantime Google seems to start <a href="https://coral.ai/">testing the industry appetite with ML dedicated edge co-processors</a>. I&rsquo;ll definitely keep an eye on this project.</p>
]]></content>
		</item>
		
		<item>
			<title>Most Startups Should Not Invest in ML/AI (yet)</title>
			<link>https://matt.aimonetti.net/posts/2020-01-most-startups-should-not-invest-in-ml/ai-yet/</link>
			<pubDate>Wed, 15 Jan 2020 09:40:44 -0800</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2020-01-most-startups-should-not-invest-in-ml/ai-yet/</guid>
			<description>Chances are you should instead be investing in data engineering so you can take a deep look at your properly labeled and processed data instead of throwing hundreds of thousands of dollars in Machine Learning (ML).
ML isn&amp;rsquo;t magical, you need a lot of clean, labeled data. Then you need a specific use case to design and deploy a great model that can help your product. Most startups don&amp;rsquo;t have clean, reliable and labeled data that can be used to train models.</description>
			<content type="html"><![CDATA[<p>Chances are you should instead be investing in data engineering so you can take a deep look at your properly labeled and processed data instead of throwing hundreds of thousands of dollars in Machine Learning (ML).</p>
<p>ML isn&rsquo;t magical, you need a lot of clean, labeled data. Then you need a specific use case to design and deploy a great model that can help your product. Most startups don&rsquo;t have clean, reliable and labeled data that can be used to train models. That&rsquo;s why you need data engineers.</p>
<p>The reality is that given a specific opportunity and the right data, your product &amp; engineering team should be able to build a decently fast solution and get you to 80-90% there. ML is awesome at giving you the last 10-20% and to not require an entire eng team. But building, validating and deploying a ML model is time consuming. Plus, very few people have experience going through this process which means higher risks.</p>
<p>My recommendation:</p>
<ol>
<li>hire data engineers and build an amazing data set</li>
<li>test your hypotheses quickly and in prod</li>
<li>invest in ML to replace the validated &ldquo;80% prototype&rdquo;</li>
</ol>
<p>I originally posted this note on Linkedin, see insights and comments <a href="https://www.linkedin.com/posts/mattaimonetti_startups-machinelearning-ml-activity-6622566543119257600-ZXi7">there</a></p>
]]></content>
		</item>
		
		<item>
			<title>Slow Down in Startup Innovation</title>
			<link>https://matt.aimonetti.net/posts/2020-01-slow-down-in-startup-innovation/</link>
			<pubDate>Tue, 07 Jan 2020 09:31:02 -0800</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2020-01-slow-down-in-startup-innovation/</guid>
			<description>Looking back at the last 10 years, two specific trends are very clear to me, here they are highlighted by Fred Wilson:
 &amp;ldquo;The massive experiment in using capital as a moat to build startups into sustainable businesses has now played out and we can call it a failure for the most part.&amp;rdquo;
   &amp;ldquo;The big four tech companies own monopolies or duopolies in their core markets and are using the power of those market positions to extend their reach into tangential markets and beyond.</description>
			<content type="html"><![CDATA[<p>Looking back at the last 10 years, two specific trends are very clear to me, here they are <a href="https://avc.com/2019/12/what-happened-in-the-2010s/">highlighted by Fred Wilson</a>:</p>
<blockquote>
<p>&ldquo;The massive experiment in using capital as a moat to build startups into sustainable businesses has now played out and we can call it a failure for the most part.&rdquo;</p>
</blockquote>
<hr>
<blockquote>
<p>&ldquo;The big four tech companies own monopolies or duopolies in their core markets and are using the power of those market positions to extend their reach into tangential markets and beyond.&rdquo;</p>
</blockquote>
<p><strong>Startups are now focusing on becoming sustainable and big tech companies are focusing on consolidation</strong> via acquisitions or by taking over smaller markets by using their market positions. <strong>This leaves very little room for creative and innovative thinking.</strong> At the very least, we will see less resources and time dedicated to experimenting with new approaches. <strong>Revenue and more importantly net revenue is back to being the primary driver.</strong> While this is a healthy economical correction, it also means that we will see very small companies fight for their survival relying on differentiating themselves from big companies (strong values such as ethics, privacy, different business models, better support&hellip;) while big companies will spend money to grow as big as possible so they can&rsquo;t fail.</p>
<p><strong>This environment is unfortunately not conductive to crazy new ideas.</strong> Everything must be weighed against OKRs or KPIs which themselves are directly correlated to net revenue. It will be hard for independent entrepreneurs to innovate unless they already have a solid economical engine.</p>
<p>On the other hand, <strong>while the open-source movement was promising, the experience somewhat failed</strong> when big tech companies started taking over and used FOSS as a way to dominate or extend their market reach. Open-source turned into more of a marketing and recruiting strategy than a way to drive new ideas. Very few open-source maintainers can sustain that lifestyle developing new ideas while big companies make millions off of the work that the open source community has done over the last decades. Fascinating turn of event.</p>
<p>I might sound pessimistic but I believe defining a clear baseline of where we are at now, is the best way to find medium to long term opportunities. <strong>Things are changing, non revenue driven innovation might be negatively affected in the short term but new models are about to be revealed and put to the test. That&rsquo;s something I am excited to see.</strong></p>
]]></content>
		</item>
		
		<item>
			<title>Moving on with Gratitude</title>
			<link>https://matt.aimonetti.net/posts/2019-08-moving-on-with-gratitude/</link>
			<pubDate>Wed, 21 Aug 2019 07:42:15 -0700</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2019-08-moving-on-with-gratitude/</guid>
			<description>In a lot of ways, I owe my professional career to music. If it wasn&amp;rsquo;t for music, I wouldn&amp;rsquo;t have learned about samplers, sequencers, MIDI and the crazy world of synthesizers. Those machines led me to computers and computer music which led me to both sound engineering and reverse engineering (RE). RE led me to a social community of hackers with strong values caring about education and musicians. They gave me a chance to learn a lot about audio software and eventually software engineering.</description>
			<content type="html"><![CDATA[<p>In a lot of ways, <strong>I owe my professional career to music.</strong> If it wasn&rsquo;t for music, I wouldn&rsquo;t have learned about samplers, sequencers, MIDI and the crazy world of synthesizers. Those machines led me to computers and computer music which led me to both sound engineering and <a href="https://en.wikipedia.org/wiki/SoftICE">reverse engineering</a> (RE). RE led me to a social community of <a href="https://en.wikipedia.org/wiki/List_of_warez_groups#Radium">hackers</a> with strong values caring about education and musicians. They gave me a chance to learn a lot about audio software and eventually software engineering. When I saw that both the music and the web industries were changing so rapidly, I switched industry and sadly left music behind me for more than 10 years.</p>
<p>But in 2013, I was very lucky to be able to create and grow a company putting musicians first and trying to create a positive long lasting impact on our industry. <a href="https://splice.com">Splice</a> has been a fascinating journey. I&rsquo;ve been able to bring my 20+ years of experience and empathy for producers and musicians, as well as my years of digging deep into the code base of the software our users use daily. It&rsquo;s been an educational, emotional, passionate and certainly challenging ride at times. It&rsquo;s been amazing to meet and hang with the people who developed the software that made me want to learn how to program a computer. It&rsquo;s been humbling to be in studio with people shaping the world&rsquo;s culture by translating their emotions into music. I can&rsquo;t be prouder of what <a href="https://splice.com/blog/splice-creator-initiative/">we accomplished</a> and can&rsquo;t wait to see what&rsquo;s still to come.
Nonetheless, I decided to transition out and <strong>stepped down from my operating role at <a href="https://splice.com">Splice</a></strong>. I will remain an advisor to the company but It&rsquo;s time for me to ride off into the sunset, take some time to relax and focus on some other things such as making music, hacking, spending time with my family here in beautiful Southern California and of course finding other ways to be impactful.</p>
<p><img src="https://media.giphy.com/media/qEbo6MHIjbu1O/giphy.gif" alt="journey"></p>
<h2 id="why">Why?</h2>
<p>Being a founder, I have to admit that deciding to move on from your own project is a really hard decision. But a startup isn&rsquo;t a baby you give birth to. As a parent myself, I realized that way before starting Splice, but seeing so many of my friends <a href="https://hbr.org/2008/02/the-founders-dilemma">deeply hurt</a> because of this misunderstanding made it clearer than ever. A startup is a project you care a lot about and want to see become reality but that doesn&rsquo;t mean it can&rsquo;t keep going without you. <strong>I believe founders should maximize for impact and I think that Splice will keep on reaching its potential and serve the mission Steve and I set on day one, even after my departure.</strong></p>
<p>The team has been laser focused, learning from our past mistakes and moving towards great autonomy and increased quality. I can&rsquo;t go to a studio session without everyone knowing and using Splice, from hollywood music composers to k-pop producers to Nashville greatests. Two things I care a lot about are impact and decisions and I measure my own impact by analyzing the ROI of my efforts in relation to the impact I have. Clearly our impact is visible every time I talk to users. But <strong>as I take a deep look at today and tomorrow, I believe my impact outside of Splice will be even greater than what it could be inside</strong>. I even believe that this impact has the potential to have positive consequences on Splice continuous success. As so many people before me said, your goal should be to make yourself redundant and I feel that&rsquo;s exactly where we are now.</p>
<p>I also have to admit that <strong>I am personally motivated to explore things that aren&rsquo;t and won&rsquo;t be on Splice&rsquo;s roadmap.</strong> I&rsquo;m a doer, a maker, a dreamer, a hacker and I realized that lately I&rsquo;ve been really enjoying being surrounded by creative people. I loved reverse engineering all the DAW formats, architecting our technical solutions, grow the engineering team and learning a ton along the way. But now the team has things under control and I have a strong desire to expand my horizons, to pour my energy into different projects: from crazy artistic concepts, <a href="https://en.wikipedia.org/wiki/Mixed_reality">MR</a>, low level hardware hacking, building synthesizers with my daughter, video games and more. The list of crazy ideas I want to hack on is endless and I am so excited that it will be hard for me to prioritize. It&rsquo;s therefore logical that to be able to explore those things, <strong>I need mental space and free time.</strong> I also I hope that through this journey I will be able to better discover who I am and who I want to become.</p>
<p><img src="https://media.giphy.com/media/kaH2MG30rZIFNFvZJe/source.gif" alt="moving on"></p>
<h2 id="thank-you">Thank you</h2>
<p>I&rsquo;m thankful for the splice team - from my co-founder Steve, to the the board, to the team: Juan-Pablo, thanks for everything, I learned a ton from you. Thank you to our early employees who gave everything they had, our colleagues that jumped in during the crazy growth phase and the entire team that allowed Splice to become what it is. But beyond all the people involved into building Splice and our partners who helped us get where we are, I want to thank our users, our deeply passionate users who supported us and gave me so much energy on a daily basis. Music is a really really hard space to operate in and musicians is the group of people the most lied to. <strong>I&rsquo;m so glad you saw that we are truly here to advocate for you and help create more seats at the table, your support means the world, thank you 🙏🙏🙏</strong></p>
<p><img src="https://media.giphy.com/media/J2PSJxabjpELe1BZCL/giphy.gif" alt="beautiful"></p>
<h2 id="whats-next">What&rsquo;s next?</h2>
<p>I don&rsquo;t have a job lined up, nor am I looking for one :) As a matter of fact, I started a &ldquo;sabbatical&rdquo; during which I am exploring a lot of things I never had time for previously. As mentioned earlier, <strong>I have a few artistic projects lined up, I want to go deep into some technical skills I haven&rsquo;t had the chance to develop yet and I am planning on reading, watching amazing shows, spending time with my family and taking naps, lots of naps.</strong> Last time I took a real break in between projects was more than 30 years ago. It&rsquo;s exciting and scary at the same time. People who know me, know that it&rsquo;s hard for me to not get passionate and jump straight into a project as soon as I have a little free time. But I am lucky to have close friends and a family who are keeping me accountable!
I will still remain involved with Splice as an advisor and champion. I obviously really want Splice to continue with its success and I&rsquo;ll do what I can to support the company I co-created. I&rsquo;ll also eventually start new projects and hope to continue having a positive impact and assist others in their journey here in LA and around the world.
You will certainly find me surrounded by creative people, trying to understand what makes the creative process so amazing and universal. I will forever remain an advocate to the people who make our hearts beat faster, our feet stomp and our heads spin with emotions. &ldquo;Here&rsquo;s to the crazy ones. The misfits. The rebels. The troublemakers. The round pegs in the square holes. The ones who see things differently.&rdquo;</p>
<p><img src="https://media.giphy.com/media/Tfj3qeKv704byAtrUe/giphy.gif" alt="keep going"></p>
]]></content>
		</item>
		
		<item>
			<title>Drawing Waveforms in Flutter</title>
			<link>https://matt.aimonetti.net/posts/2019-07-drawing-waveforms-in-flutter/</link>
			<pubDate>Mon, 08 Jul 2019 12:08:35 -0700</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2019-07-drawing-waveforms-in-flutter/</guid>
			<description>In the previous article, I explained what data we needed to generate waveforms and showed how to use a BBC Free Open Source Software to generate that data. In this article, I will show how to draw a waveform using Google&amp;rsquo;s Flutter UI toolkit for mobile, desktop and web. Here is the end result will are going for:
You can play with the web version of the UI here, thanks to Flutter web!</description>
			<content type="html"><![CDATA[<p>In the previous article, I explained what <a href="https://matt.aimonetti.net/posts/2019-06-generating-waveform-data-audio-representation/">data we needed to generate waveforms</a> and showed how to use a <a href="https://github.com/bbc/audiowaveform">BBC Free Open Source Software</a> to generate that data. In this article, I will show how to draw a waveform using <a href="https://flutter.dev/">Google&rsquo;s Flutter UI toolkit for mobile, desktop and web</a>. Here is the end result will are going for:</p>
<p><img src="/images/waveforms/waveform-final.gif" alt="audio waveform rendering in flutter"></p>
<p>You can play with the <a href="https://matt.aimonetti.net/demos/waveform#/">web version of the UI here</a>, thanks to <a href="https://flutter.dev/web">Flutter web!</a></p>
<p><a href="https://matt.aimonetti.net/demos/waveform#/"><img src="/images/waveforms/FlutterWeb.png" alt="Flutter web version of the waveform"></a></p>
<h2 id="why-flutter">Why Flutter?</h2>
<p>You might not be familiar with Flutter and might be surprised I&rsquo;m using this technology to demonstrate how to draw waveforms. There are a few reasons behind my choice, first and foremost, drawing waveforms on the web is pretty well taken care of by a bunch of JS libraries. On the other hand, drawing waveforms in non-browser based environments isn&rsquo;t as well documented. The second reason is that since Flutter now also targets the web (in beta), I can link to actual renderings from this blog. Finally, it&rsquo;s a good excuse to write a fun Flutter tutorial :)</p>
<h2 id="setting-up-our-project">Setting up our project</h2>
<p>I don&rsquo;t expect that most of you to already know Flutter but the good news is that
ramping up is quite fast and I&rsquo;ll walk you through the steps. Start by heading
to <a href="https://flutter.dev/">https://flutter.dev/</a> and
<a href="https://flutter.dev/docs/get-started/install">install Flutter</a>. You can use Flutter on
Windows, Mac and Linux. If you want to target iOS, you need to have Xcode
installed. Install Android studio if you want to target Android. The instructions
are quite clear and the tooling is very helpful to make sure you have everything
setup correctly (thanks <code>$ flutter doctor</code>). Note that you don&rsquo;t need a physical
device to test your code, you can run everything in the iOS simulator or the
Android emulator.</p>
<p>Start by creating an empty project:</p>
<p><code>$ flutter create waveform_demo</code></p>
<p>Flutter will let you know that everything went well and tell you how to
compile and run your project inside your connected device or simulator/emulator.
It will also indicate where our entry point is located (that&rsquo;s the <code>main.dart</code>
file in the lib folder).</p>
<pre><code>In order to run your application, type:

  $ cd waveform_demo
  $ flutter run

Your application code is in waveform_demo/lib/main.dart.
</code></pre><h3 id="vscode-tips">VSCode tips</h3>
<p>I personally use <a href="https://code.visualstudio.com/">VSCode</a> as an editor and it
has a great Flutter plugin with <a href="https://flutter.dev/docs/development/tools/vs-code">amazing tool integration</a> from code
completion to emulator launcher, debugger, profiler and refactoring tools. As a
side note I also recommend <a href="https://marketplace.visualstudio.com/items?itemName=Nash.awesome-flutter-snippets">Awesome Flutter Snippets</a>
and <a href="https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer-2">Bracket Pair Colorizer</a>.</p>
<h3 id="tools-youd-usually-use">Tools you&rsquo;d usually use</h3>
<p>For this demo, we are going to keep our code simple so I won&rsquo;t setup <a href="https://dart.dev/guides/language/analysis-options">custom
static analysis options</a>, nor
<a href="https://pub.dev/packages/flutter_launcher_icons">custom launcher icons</a> and
unfortunately, I won&rsquo;t show how to write <a href="https://flutter.dev/docs/testing">Flutter
tests</a>. Note that in a real life project,
you&rsquo;d want to set those things up (the good news is that you can find plenty of
documentation on those topics).</p>
<h3 id="code-organization">Code organization</h3>
<p>We are going to need two views, one that I will call <code>painter_view</code> and
another I&rsquo;ll call <code>clipper_view</code>. We&rsquo;ll set the app to render the <code>clipper_view</code>
view by default and add a bottom nav bar to go to the <code>painter_view</code>. In order
to save us time, I created a <a href="https://github.com/mattetti/waveform_demo/releases/tag/v1-setup">git
tag</a> with the
code base.</p>
<p>To retrieve the code locally, clone the repo and switch to the tag:</p>
<pre><code>git clone git@github.com:mattetti/waveform_demo.git
git checkout tags/v1-setup
</code></pre><p>I organized the files as shown below:</p>
<p><img src="/images/waveforms/file_structure_setup.png" alt="project files"></p>
<p><em>There aren&rsquo;t hard conventions in the Flutter community on how to organize your
files but that&rsquo;s the pattern I personally use. I isolate UI concerns and
model/logic.</em></p>
<p>You can run the project (F5 in VSCode) to see our setup:</p>
<p><img src="/images/waveforms/default-flutter-views.gif" alt="Default flutter views"></p>
<h2 id="loading-the-waveform-data">Loading the waveform data</h2>
<p>We are almost to the drawing part of the article but we need to do one more
thing, load the data. In a real life application we would probably make an HTTP
call to load the json or binary file we <a href="/posts/2019-06-generating-waveform-data-audio-representation/">generated server
side</a> but for
this example, we will bundle our pre-generated file in the app and load it
directly. For that we need to do 4 things:</p>
<ol>
<li>generate a json file (covered in the <a href="/posts/2019-06-generating-waveform-data-audio-representation/">previous article</a>)</li>
<li>add it to the app</li>
<li>create a model to load the file content</li>
<li>create a loader function that we can use to load the content asynchronously.</li>
</ol>
<p>To add json files to our app, we need to create an assets folder to move the files to and register the files in our <code>pubspec.yaml</code> manifest file.</p>
<p>I <a href="/posts/2019-06-generating-waveform-data-audio-representation/">generated 2 json files</a> called <code>one-shot.json</code> and <code>loop.json</code> and added them to <code>assets/waveforms/</code>.</p>
<p><img src="/images/waveforms/flutter-assets.png" alt="flutter json assets"></p>
<p>We then need to register them into our <code>pubspec.yaml</code> manifest:</p>
<pre><code>  assets:
    - assets/waveforms/loop.json
    - assets/waveforms/oneshot.json
</code></pre><p>The files are now bundle with the app and we can load them programmatically.
Let&rsquo;s add a loader service to do that. In <code>lib/core/services</code> let&rsquo;s create a
<code>waveform_data_loader.dart</code> file. This file looks more like a helper than a
service but that&rsquo;s fine for this demo. We want to setup an async function that
will return a future of the parsed json data. Returning a future is key here,
since we don&rsquo;t know how long it takes to load and parse the json (especially if
it was to come from the network) and we can rely on Flutter&rsquo;s excellent
<a href="https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html">FutureBuilder
widget</a>. The
future builder builds itself once the data is available.</p>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe src="https://www.youtube.com/embed/ek8ZPdWj4Qo" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>

<p>Here is what our code will look like:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart">Future<span style="color:#f92672">&lt;</span>WaveformData<span style="color:#f92672">&gt;</span> loadWaveformData(<span style="color:#66d9ef">String</span> filename) <span style="color:#66d9ef">async</span> {
  <span style="color:#66d9ef">final</span> data <span style="color:#f92672">=</span> <span style="color:#66d9ef">await</span> rootBundle.loadString(<span style="color:#e6db74">&#34;assets/waveforms/</span><span style="color:#e6db74">$</span>filename<span style="color:#e6db74">&#34;</span>);
  <span style="color:#66d9ef">return</span> WaveformData.fromJson(data);
}
</code></pre></div><p>While very straightforward, we need to first define our <code>WaveformData</code> class
that will parse the JSON file.</p>
<p>Let&rsquo;s create a model file as <code>lib/core/models/waveform_data_model.dart</code> and have
that class represent the waveform data. I don&rsquo;t usually write JSON
serializers/deserializers by hand since it&rsquo;s quite cumbersome and can be
automated quickly and reliably. I like to use
<a href="https://app.quicktype.io/">https://app.quicktype.io/</a> and paste the JSON data I
want to parse and have it generate the dart code I can use in my app. The code
on its own isn&rsquo;t very interesting, but here is a quick snapshot of the class
members:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">WaveformData</span> {
  <span style="color:#66d9ef">int</span> version;
  <span style="color:#75715e">// number of channels (only mono files are currently supported)
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">int</span> channels;
  <span style="color:#75715e">// original sample rate
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">int</span> sampleRate;
  <span style="color:#75715e">// indicates how many original samples have been analyzed per frame. 256 samples -&gt; frame of min/max
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">int</span> sampleSize;
  <span style="color:#75715e">// bit depth of the data
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">int</span> bits;
  <span style="color:#75715e">// the number of frames contained in the data
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">int</span> length;
  <span style="color:#75715e">// data is in frames with min and max values for each sampled data point.
</span><span style="color:#75715e"></span>  List<span style="color:#f92672">&lt;</span><span style="color:#66d9ef">int</span><span style="color:#f92672">&gt;</span> data;

  WaveformData({
    <span style="color:#66d9ef">this</span>.version,
    <span style="color:#66d9ef">this</span>.channels,
    <span style="color:#66d9ef">this</span>.sampleRate,
    <span style="color:#66d9ef">this</span>.sampleSize,
    <span style="color:#66d9ef">this</span>.bits,
    <span style="color:#66d9ef">this</span>.length,
    <span style="color:#66d9ef">this</span>.data,
  });

 <span style="color:#75715e">// ...
</span><span style="color:#75715e"></span>}
</code></pre></div><p>And we are done with data loading. We now have a way to load the json files we
bundled in the app load make their content available to our UI.</p>
<p>The code is available in <a href="https://github.com/mattetti/waveform_demo/releases/tag/v2-data-loading">this tag</a>.</p>
<h2 id="drawing-the-actual-waveform">Drawing the actual waveform</h2>
<p>We are finally getting to the core of this article.</p>
<p>What we want is to render a waveform like this but inside our app:
<img src="/images/waveform.png" alt="loop waveform"></p>
<p><img src="/images/oneshot-64-waveform.png" alt="oneshot waveform"></p>
<h3 id="painted-view">Painted view</h3>
<p>This view is quite straightforward:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart">Center(
  child: FutureBuilder<span style="color:#f92672">&lt;</span>WaveformData<span style="color:#f92672">&gt;</span>(
    future: loadWaveformData(<span style="color:#e6db74">&#34;oneshot.json&#34;</span>),
    builder: (BuildContext context, AsyncSnapshot<span style="color:#f92672">&lt;</span>WaveformData<span style="color:#f92672">&gt;</span> snapshot) {
      <span style="color:#66d9ef">if</span> (snapshot.hasData) {
        <span style="color:#66d9ef">return</span> PaintedWaveform(sampleData: snapshot.data);
      } <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> (snapshot.hasError) {
        <span style="color:#66d9ef">return</span> Text(<span style="color:#e6db74">&#34;Error </span><span style="color:#e6db74">${</span>snapshot.error<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>, style: TextStyle(color: Colors.red));
      }
      <span style="color:#66d9ef">return</span> CircularProgressIndicator();
    },
  ),
)
</code></pre></div><p>We are using a <code>FutureBuilder</code> widget, to render/build once the JSON data is
parsed. The builder function will receive a snapshot containing the waveform
data. Because the builder is called right away, we want to check the state of
the snapshot and render a progress indicator or an error if the parsing failed!
However if the snapshot has good data, we are going to render the waveform!</p>
<p>Note that the code above renders a widget called <code>PaintedWaveform</code>, this is a widget we need to create ourselves.
Let&rsquo;s write it!</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">PaintedWaveform</span> <span style="color:#66d9ef">extends</span> StatefulWidget {
  PaintedWaveform({
    Key key,
    <span style="color:#960050;background-color:#1e0010">@</span>required <span style="color:#66d9ef">this</span>.sampleData,
  }) <span style="color:#f92672">:</span> <span style="color:#66d9ef">super</span>(key: key);

  <span style="color:#66d9ef">final</span> WaveformData sampleData;

  <span style="color:#960050;background-color:#1e0010">@</span>override
  _PaintedWaveformState createState() <span style="color:#f92672">=&gt;</span> _PaintedWaveformState();
}

<span style="color:#66d9ef">class</span> <span style="color:#a6e22e">_PaintedWaveformState</span> <span style="color:#66d9ef">extends</span> State<span style="color:#f92672">&lt;</span>PaintedWaveform<span style="color:#f92672">&gt;</span> {
  <span style="color:#66d9ef">double</span> startPosition <span style="color:#f92672">=</span> <span style="color:#ae81ff">1.0</span>;
  <span style="color:#66d9ef">double</span> zoomLevel <span style="color:#f92672">=</span> <span style="color:#ae81ff">1.0</span>;

  <span style="color:#960050;background-color:#1e0010">@</span>override
  Widget build(context) {
    <span style="color:#66d9ef">return</span> Container(
      color: Colors.black87,
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <span style="color:#f92672">&lt;</span>Widget<span style="color:#f92672">&gt;</span>[
          Flexible(
            flex: <span style="color:#ae81ff">4</span>,
            child: LayoutBuilder(
              builder: (context, BoxConstraints constraints) {
                <span style="color:#75715e">// adjust the shape based on parent&#39;s orientation/shape
</span><span style="color:#75715e"></span>                <span style="color:#75715e">// the waveform should always be wider than taller
</span><span style="color:#75715e"></span>                <span style="color:#66d9ef">var</span> height;
                <span style="color:#66d9ef">if</span> (constraints.maxWidth <span style="color:#f92672">&lt;</span> constraints.maxHeight) {
                  height <span style="color:#f92672">=</span> constraints.maxWidth;
                } <span style="color:#66d9ef">else</span> {
                  height <span style="color:#f92672">=</span> constraints.maxHeight;
                }

                <span style="color:#66d9ef">return</span> Container(
                  child: Row(
                    children: <span style="color:#f92672">&lt;</span>Widget<span style="color:#f92672">&gt;</span>[
                      CustomPaint(
                        size: Size(
                          constraints.maxWidth,
                          height,
                        ),
                        foregroundPainter: WaveformPainter(
                          widget.sampleData,
                          zoomLevel: zoomLevel,
                          startingFrame: widget.sampleData.frameIdxFromPercent(startPosition),
                          color: Color(<span style="color:#ae81ff">0xff3994DB</span>),
                        ),
                      ),
                    ],
                  ),
                );

              },
            ),
          ),

          Flexible(
            child: Slider(
              activeColor: Colors.indigoAccent,
              min: <span style="color:#ae81ff">1.0</span>,
              max: <span style="color:#ae81ff">95.0</span>,
              divisions: <span style="color:#ae81ff">42</span>,
              onChanged: (newzoomLevel) {
                setState(() <span style="color:#f92672">=&gt;</span> zoomLevel <span style="color:#f92672">=</span> newzoomLevel);
              },
              value: zoomLevel,
            ),
          ),

          Flexible(
            child: Slider(
              activeColor: Colors.indigoAccent,
              min: <span style="color:#ae81ff">1.0</span>,
              max: <span style="color:#ae81ff">95.0</span>,
              divisions: <span style="color:#ae81ff">42</span>,
              onChanged: (newstartPosition) {
                setState(() <span style="color:#f92672">=&gt;</span> startPosition <span style="color:#f92672">=</span> newstartPosition);
              },
              value: startPosition,
            ),
          )

        ],
      ),
    );
  }
}
</code></pre></div><p>It might seem like there is a lot going on in there but it&rsquo;s not that bad, let&rsquo;s
break it down.</p>
<p>The first thing you should notice is that instead of rendering our waveform
right away, we are using a <code>LayoutBuilder</code> widget so we can get the size of the
rendering area at runtime and adjust the dimensions accordingly.</p>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe src="https://www.youtube.com/embed/IYDVcriKjsw" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>

<p>The builder creates the layout which contains a <code>CustomPaint</code> widget. That&rsquo;s the
key widget to render our waveform!</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart">CustomPaint(
  size: Size(
    constraints.maxWidth,
    height,
  ),
  foregroundPainter: WaveformPainter(
    widget.sampleData,
    zoomLevel: zoomLevel,
    startingFrame: widget.sampleData.frameIdxFromPercent(startPosition),
    color: Color(<span style="color:#ae81ff">0xff3994DB</span>),
  ),
),
</code></pre></div><p>Here is a great quick video about <code>CustomPaint</code>:</p>

<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
  <iframe src="https://www.youtube.com/embed/kp14Y4uHpHs" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" allowfullscreen title="YouTube Video"></iframe>
</div>

<p>As explained in the video, we need to implement a custom painter to tell the
widget what to draw. For that, we are going to code <code>WaveformPainter</code>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">WaveformPainter</span> <span style="color:#66d9ef">extends</span> CustomPainter {
  <span style="color:#66d9ef">final</span> WaveformData data;
  <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">int</span> startingFrame;
  <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">double</span> zoomLevel;
  Paint painter;
  <span style="color:#66d9ef">final</span> Color color;
  <span style="color:#66d9ef">final</span> <span style="color:#66d9ef">double</span> strokeWidth;

  WaveformPainter(<span style="color:#66d9ef">this</span>.data,
      {<span style="color:#66d9ef">this</span>.strokeWidth <span style="color:#f92672">=</span> <span style="color:#ae81ff">1.0</span>, <span style="color:#66d9ef">this</span>.startingFrame <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>, <span style="color:#66d9ef">this</span>.zoomLevel <span style="color:#f92672">=</span> <span style="color:#ae81ff">1</span>, <span style="color:#66d9ef">this</span>.color <span style="color:#f92672">=</span> Colors.blue}) {
    painter <span style="color:#f92672">=</span> Paint()
      ..style <span style="color:#f92672">=</span> PaintingStyle.fill
      ..color <span style="color:#f92672">=</span> color
      ..strokeWidth <span style="color:#f92672">=</span> <span style="color:#66d9ef">this</span>.strokeWidth
      ..isAntiAlias <span style="color:#f92672">=</span> <span style="color:#66d9ef">true</span>;
  }

  <span style="color:#960050;background-color:#1e0010">@</span>override
  <span style="color:#66d9ef">void</span> paint(Canvas canvas, Size size) {
    <span style="color:#66d9ef">if</span> (data <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span>) {
      <span style="color:#66d9ef">return</span>;
    }

    <span style="color:#66d9ef">final</span> path <span style="color:#f92672">=</span> data.path(size, fromFrame: startingFrame, zoomLevel: zoomLevel);
    canvas.drawPath(path, painter);
  }

  <span style="color:#960050;background-color:#1e0010">@</span>override
  <span style="color:#66d9ef">bool</span> shouldRepaint(WaveformPainter oldDelegate) {
    <span style="color:#66d9ef">if</span> (oldDelegate.data <span style="color:#f92672">!=</span> data) {
      debugPrint(<span style="color:#e6db74">&#34;Redrawing&#34;</span>);
      <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>;
    }
    <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>;
  }
}
</code></pre></div><p>You probably expected to see the path drawing code in this class, however the
<code>paint</code> method delegates most of the heavy lifting to the <code>WaveformData</code> class
as shown here:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart"><span style="color:#66d9ef">void</span> paint(Canvas canvas, Size size) {
  <span style="color:#66d9ef">if</span> (data <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span>) {
    <span style="color:#66d9ef">return</span>;
  }

  <span style="color:#66d9ef">final</span> path <span style="color:#f92672">=</span> data.path(size, fromFrame: startingFrame, zoomLevel: zoomLevel);
  canvas.drawPath(path, painter);
}
</code></pre></div><p>I ended up moving the path generation to the <code>WaveformData</code> class since we need
some logic to implement scrolling and zooming and we might want to use the path
to render within a widget that might not take a painter.</p>
<p>Let&rsquo;s jump to <code>WaveformData</code> and see how I implemented the path drawing:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">WaveformData</span> {
  <span style="color:#75715e">// [...]
</span><span style="color:#75715e"></span>  List<span style="color:#f92672">&lt;</span><span style="color:#66d9ef">int</span><span style="color:#f92672">&gt;</span> data;
  List<span style="color:#f92672">&lt;</span><span style="color:#66d9ef">double</span><span style="color:#f92672">&gt;</span> _scaledData;
  <span style="color:#75715e">// [...]
</span><span style="color:#75715e"></span>
  List<span style="color:#f92672">&lt;</span><span style="color:#66d9ef">double</span><span style="color:#f92672">&gt;</span> scaledData() {
    <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span>_isDataScaled()) {
      _scaleData();
    }
    <span style="color:#66d9ef">return</span> _scaledData;
  }

  Path path(Size size, {zoomLevel <span style="color:#f92672">=</span> <span style="color:#ae81ff">1.0</span>, <span style="color:#66d9ef">int</span> fromFrame <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>}) {
    <span style="color:#66d9ef">if</span> (<span style="color:#f92672">!</span>_isDataScaled()) {
      _scaleData();
    }

    <span style="color:#66d9ef">if</span> (zoomLevel <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span> <span style="color:#f92672">||</span> zoomLevel <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">1.0</span>) {
      zoomLevel <span style="color:#f92672">=</span> <span style="color:#ae81ff">1.0</span>;
    } <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> (zoomLevel <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">100.0</span>) {
      zoomLevel <span style="color:#f92672">=</span> <span style="color:#ae81ff">100.0</span>;
    }

    <span style="color:#66d9ef">if</span> (zoomLevel <span style="color:#f92672">==</span> <span style="color:#ae81ff">1.0</span> <span style="color:#f92672">&amp;&amp;</span> fromFrame <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>) {
      <span style="color:#66d9ef">return</span> _path(_scaledData, size);
    }

    <span style="color:#75715e">// buffer so we can&#39;t start too far in the waveform, 90% max
</span><span style="color:#75715e"></span>    <span style="color:#66d9ef">if</span> (fromFrame <span style="color:#f92672">*</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">&gt;</span> (data.length <span style="color:#f92672">*</span> <span style="color:#ae81ff">0.98</span>).floor()) {
      debugPrint(<span style="color:#e6db74">&#34;from frame is too far at </span><span style="color:#e6db74">$</span>fromFrame<span style="color:#e6db74">&#34;</span>);
      fromFrame <span style="color:#f92672">=</span> ((data.length <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>) <span style="color:#f92672">*</span> <span style="color:#ae81ff">0.98</span>).floor();
    }

    <span style="color:#66d9ef">int</span> endFrame <span style="color:#f92672">=</span> (fromFrame <span style="color:#f92672">*</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">+</span> ((_scaledData.length <span style="color:#f92672">-</span> fromFrame <span style="color:#f92672">*</span> <span style="color:#ae81ff">2</span>) <span style="color:#f92672">*</span> (<span style="color:#ae81ff">1.0</span> <span style="color:#f92672">-</span> (zoomLevel <span style="color:#f92672">/</span> <span style="color:#ae81ff">100</span>)))).floor();
    <span style="color:#66d9ef">return</span> _path(_scaledData.sublist(fromFrame <span style="color:#f92672">*</span> <span style="color:#ae81ff">2</span>, endFrame), size);
  }

  Path _path(List<span style="color:#f92672">&lt;</span><span style="color:#66d9ef">double</span><span style="color:#f92672">&gt;</span> samples, Size size) {
    <span style="color:#66d9ef">final</span> middle <span style="color:#f92672">=</span> size.height <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>;
    <span style="color:#66d9ef">var</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;

    List<span style="color:#f92672">&lt;</span>Offset<span style="color:#f92672">&gt;</span> minPoints <span style="color:#f92672">=</span> [];
    List<span style="color:#f92672">&lt;</span>Offset<span style="color:#f92672">&gt;</span> maxPoints <span style="color:#f92672">=</span> [];

    <span style="color:#66d9ef">final</span> t <span style="color:#f92672">=</span> size.width <span style="color:#f92672">/</span> samples.length;
    <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">var</span> _i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>, _len <span style="color:#f92672">=</span> samples.length; _i <span style="color:#f92672">&lt;</span> _len; _i<span style="color:#f92672">++</span>) {
      <span style="color:#66d9ef">var</span> d <span style="color:#f92672">=</span> samples[_i];

      <span style="color:#66d9ef">if</span> (_i <span style="color:#f92672">%</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span>) {
        minPoints.add(Offset(t <span style="color:#f92672">*</span> i, middle <span style="color:#f92672">-</span> middle <span style="color:#f92672">*</span> d));
      } <span style="color:#66d9ef">else</span> {
        maxPoints.add(Offset(t <span style="color:#f92672">*</span> i, middle <span style="color:#f92672">-</span> middle <span style="color:#f92672">*</span> d));
      }

      i<span style="color:#f92672">++</span>;
    }

    <span style="color:#66d9ef">final</span> path <span style="color:#f92672">=</span> Path();
    path.moveTo(<span style="color:#ae81ff">0</span>, middle);
    maxPoints.forEach((o) <span style="color:#f92672">=&gt;</span> path.lineTo(o.dx, o.dy));
    <span style="color:#75715e">// back to zero
</span><span style="color:#75715e"></span>    path.lineTo(size.width, middle);
    <span style="color:#75715e">// draw the minimums backwards so we can fill the shape when done.
</span><span style="color:#75715e"></span>    minPoints.reversed.forEach((o) <span style="color:#f92672">=&gt;</span> path.lineTo(o.dx, middle <span style="color:#f92672">-</span> (middle <span style="color:#f92672">-</span> o.dy)));

    path.close();
    <span style="color:#66d9ef">return</span> path;
  }

  <span style="color:#75715e">// get the frame position at a specific percent of the waveform. Can use a 0-1 or 0-100 range.
</span><span style="color:#75715e"></span>  <span style="color:#66d9ef">int</span> frameIdxFromPercent(<span style="color:#66d9ef">double</span> percent) {
    <span style="color:#66d9ef">if</span> (percent <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span>) {
      <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
    }

    <span style="color:#75715e">// if the scale is 0-1.0
</span><span style="color:#75715e"></span>    <span style="color:#66d9ef">if</span> (percent <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">0.0</span>) {
      percent <span style="color:#f92672">=</span> <span style="color:#ae81ff">0.0</span>;
    } <span style="color:#66d9ef">else</span> <span style="color:#66d9ef">if</span> (percent <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">100.0</span>) {
      percent <span style="color:#f92672">=</span> <span style="color:#ae81ff">100.0</span>;
    }

    <span style="color:#66d9ef">if</span> (percent <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">0.0</span> <span style="color:#f92672">&amp;&amp;</span> percent <span style="color:#f92672">&lt;</span> <span style="color:#ae81ff">1.0</span>) {
      <span style="color:#66d9ef">return</span> ((data.length.toDouble() <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>) <span style="color:#f92672">*</span> percent).floor();
    }

    <span style="color:#66d9ef">int</span> idx <span style="color:#f92672">=</span> ((data.length.toDouble() <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>) <span style="color:#f92672">*</span> (percent <span style="color:#f92672">/</span> <span style="color:#ae81ff">100</span>)).floor();
    <span style="color:#66d9ef">final</span> maxIdx <span style="color:#f92672">=</span> (data.length.toDouble() <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">*</span> <span style="color:#ae81ff">0.98</span>).floor();
    <span style="color:#66d9ef">if</span> (idx <span style="color:#f92672">&gt;</span> maxIdx) {
      idx <span style="color:#f92672">=</span> maxIdx;
    }
    <span style="color:#66d9ef">return</span> idx;
  }

  <span style="color:#66d9ef">bool</span> _isDataScaled() {
    <span style="color:#66d9ef">return</span> _scaledData <span style="color:#f92672">!=</span> <span style="color:#66d9ef">null</span> <span style="color:#f92672">&amp;&amp;</span> _scaledData.length <span style="color:#f92672">==</span> data.length;
  }

  <span style="color:#75715e">// scale the data from int values to float
</span><span style="color:#75715e"></span>  <span style="color:#75715e">// TODO: consider adding a normalization option
</span><span style="color:#75715e"></span>  _scaleData() {
    <span style="color:#66d9ef">final</span> max <span style="color:#f92672">=</span> pow(<span style="color:#ae81ff">2</span>, bits <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>).toDouble();

    <span style="color:#66d9ef">final</span> dataSize <span style="color:#f92672">=</span> data.length;
    _scaledData <span style="color:#f92672">=</span> List<span style="color:#f92672">&lt;</span><span style="color:#66d9ef">double</span><span style="color:#f92672">&gt;</span>(dataSize);
    <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">var</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>; i <span style="color:#f92672">&lt;</span> dataSize; i<span style="color:#f92672">++</span>) {
      _scaledData[i] <span style="color:#f92672">=</span> data[i].toDouble() <span style="color:#f92672">/</span> max;
      <span style="color:#66d9ef">if</span> (_scaledData[i] <span style="color:#f92672">&gt;</span> <span style="color:#ae81ff">1.0</span>) {
        _scaledData[i] <span style="color:#f92672">=</span> <span style="color:#ae81ff">1.0</span>;
      }
      <span style="color:#66d9ef">if</span> (_scaledData[i] <span style="color:#f92672">&lt;</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1.0</span>) {
        _scaledData[i] <span style="color:#f92672">=</span> <span style="color:#f92672">-</span><span style="color:#ae81ff">1.0</span>;
      }
    }
  }

}

</code></pre></div><p>So there is a lot going on in here, let&rsquo;s unpack it and take a look at how we
scale the samples. The BBC tool we use stores the peaks and valleys as integer
values with a specific bit depth (8 or 16bit). We want to scale this data to a
-1,+1 range and that&rsquo;s what <code>_scaleData()</code> does if we haven&rsquo;t yet scaled the
samples. To access our scaled data, we can simply call <code>scaledData()</code> which will
check if scaling is needed and return a scaled version of our samples.</p>
<p>Now that the data scaling is out of the way, let&rsquo;s jump to our entry point:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart">Path path(Size size, {zoomLevel <span style="color:#f92672">=</span> <span style="color:#ae81ff">1.0</span>, <span style="color:#66d9ef">int</span> fromFrame <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>}) {
  <span style="color:#75715e">//...
</span><span style="color:#75715e"></span>}
</code></pre></div><p>This is the function that returns the waveform path based on a provided size and
some optional zooming and scrolling arguments. I&rsquo;ll skip the zooming and
scrolling explanations in this post to focus on the drawing itself.
That takes us to this line:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart"><span style="color:#66d9ef">return</span> _path(_scaledData.sublist(fromFrame <span style="color:#f92672">*</span> <span style="color:#ae81ff">2</span>, endFrame), size);
</code></pre></div><p>We are delegating to a private method passing a potential subset of our samples and our size.
This is where the path drawing is actually happening.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart">Path _path(List<span style="color:#f92672">&lt;</span><span style="color:#66d9ef">double</span><span style="color:#f92672">&gt;</span> samples, Size size) {
  <span style="color:#66d9ef">final</span> middle <span style="color:#f92672">=</span> size.height <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>;
  <span style="color:#66d9ef">var</span> i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>;

  List<span style="color:#f92672">&lt;</span>Offset<span style="color:#f92672">&gt;</span> minPoints <span style="color:#f92672">=</span> [];
  List<span style="color:#f92672">&lt;</span>Offset<span style="color:#f92672">&gt;</span> maxPoints <span style="color:#f92672">=</span> [];

  <span style="color:#66d9ef">final</span> t <span style="color:#f92672">=</span> size.width <span style="color:#f92672">/</span> samples.length;
  <span style="color:#66d9ef">for</span> (<span style="color:#66d9ef">var</span> _i <span style="color:#f92672">=</span> <span style="color:#ae81ff">0</span>, _len <span style="color:#f92672">=</span> samples.length; _i <span style="color:#f92672">&lt;</span> _len; _i<span style="color:#f92672">++</span>) {
    <span style="color:#66d9ef">var</span> d <span style="color:#f92672">=</span> samples[_i];

    <span style="color:#66d9ef">if</span> (_i <span style="color:#f92672">%</span> <span style="color:#ae81ff">2</span> <span style="color:#f92672">!=</span> <span style="color:#ae81ff">0</span>) {
      minPoints.add(Offset(t <span style="color:#f92672">*</span> i, middle <span style="color:#f92672">-</span> middle <span style="color:#f92672">*</span> d));
    } <span style="color:#66d9ef">else</span> {
      maxPoints.add(Offset(t <span style="color:#f92672">*</span> i, middle <span style="color:#f92672">-</span> middle <span style="color:#f92672">*</span> d));
    }

    i<span style="color:#f92672">++</span>;
  }

  <span style="color:#66d9ef">final</span> path <span style="color:#f92672">=</span> Path();
  path.moveTo(<span style="color:#ae81ff">0</span>, middle);
  maxPoints.forEach((o) <span style="color:#f92672">=&gt;</span> path.lineTo(o.dx, o.dy));
  <span style="color:#75715e">// back to zero
</span><span style="color:#75715e"></span>  path.lineTo(size.width, middle);
  <span style="color:#75715e">// draw the minimums backwards so we can fill the shape when done.
</span><span style="color:#75715e"></span>  minPoints.reversed.forEach((o) <span style="color:#f92672">=&gt;</span> path.lineTo(o.dx, middle <span style="color:#f92672">-</span> (middle <span style="color:#f92672">-</span> o.dy)));

  path.close();
  <span style="color:#66d9ef">return</span> path;
}
</code></pre></div><p>The path drawing methods are close to the methods you&rsquo;d find on the HTML canvas
or other path drawing solutions, we want to draw a path showing the
outline of the waveform and close it at the end.</p>
<p>Waveforms can be drawn as a stereo rendering where the top part is a channel and
the bottom part is the other channel. But most of the time, the signal is
converted into one channel (mono). There are 2 common approaches to drawing mono
waveforms. The first one is to take the amplitude average of a time window and
draw each window. Then we can mirror the graph to create the expected waveform
shape.</p>
<p>This seems to be the approach SoundCloud went for:</p>
<p><img src="/images/waveforms/soundcloud-waveform.png" alt="soundcloud waveform"></p>
<p>Which seems to be confirmed by looking at the JSON data they use to draw the waveforms:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-json" data-lang="json">{
  <span style="color:#f92672">&#34;width&#34;</span>:<span style="color:#ae81ff">1800</span>,
  <span style="color:#f92672">&#34;height&#34;</span>:<span style="color:#ae81ff">140</span>,
  <span style="color:#f92672">&#34;samples&#34;</span>:[<span style="color:#ae81ff">4</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">10</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">8</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">10</span>,<span style="color:#ae81ff">9</span>,<span style="color:#ae81ff">22</span>,<span style="color:#ae81ff">101</span>,<span style="color:#ae81ff">100</span>,<span style="color:#ae81ff">100</span>,<span style="color:#ae81ff">94</span>,<span style="color:#ae81ff">91</span>,<span style="color:#ae81ff">85</span>,<span style="color:#ae81ff">75</span>,<span style="color:#ae81ff">69</span>,<span style="color:#ae81ff">60</span>,<span style="color:#ae81ff">53</span>,<span style="color:#ae81ff">46</span>,<span style="color:#ae81ff">45</span>,<span style="color:#ae81ff">42</span>,<span style="color:#ae81ff">42</span>,<span style="color:#ae81ff">39</span>,<span style="color:#ae81ff">34</span>,<span style="color:#ae81ff">34</span>,<span style="color:#ae81ff">35</span>,<span style="color:#ae81ff">34</span>,<span style="color:#ae81ff">32</span>,<span style="color:#ae81ff">26</span>,<span style="color:#ae81ff">27</span>,<span style="color:#ae81ff">57</span>,<span style="color:#ae81ff">55</span>,<span style="color:#ae81ff">55</span>,<span style="color:#ae81ff">53</span>,<span style="color:#ae81ff">52</span>,<span style="color:#ae81ff">48</span>,<span style="color:#ae81ff">42</span>,<span style="color:#ae81ff">35</span>,<span style="color:#ae81ff">33</span>,<span style="color:#ae81ff">57</span>,<span style="color:#ae81ff">61</span>,<span style="color:#ae81ff">57</span>,<span style="color:#ae81ff">58</span>,<span style="color:#ae81ff">5</span>, <span style="color:#960050;background-color:#1e0010">...</span>]
}
</code></pre></div><p>This is an absolutely valid approach but it provides less details than the BBC/Audacity approach which might be used by audio editors or musicians.</p>
<p>This second approach has 2 amplitude ranges, the max values and the min values. The top part of the waveform shows the peak value for each sampled time windows, the bottom part shows the minimum value for the same time windows. This approach is nice if you want to highlight the dynamic range of an audio signal. Knowing that, we can can draw our two waveform shapes.</p>
<p>The drawing algorithm is quite simple, we convert each sample value into a coordinate knowing that the lowest value is at the middle of the display area and the max value is all the way to the top for max values, and all the way to the bottom for the min values.
Another way to say the same thing is that we need to calculate the <code>x</code> and <code>y</code> values for each sample where:</p>
<blockquote>
<p><code>x = (display size / number of samples) * index of specific sample</code>
<code>y = half the display height - (half the display height * sample value)</code></p>
</blockquote>
<p>In code where <code>i</code> is the index of the sample we want to convert to coordinates:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart">middle <span style="color:#f92672">=</span> size.height <span style="color:#f92672">/</span> <span style="color:#ae81ff">2</span>;
t <span style="color:#f92672">=</span> size.width <span style="color:#f92672">/</span> samples.length;
Offset(
  dx: t <span style="color:#f92672">*</span> i,
  dy: middle <span style="color:#f92672">-</span> middle <span style="color:#f92672">*</span> samples[i]
);
</code></pre></div><p>Once we have our 2 vectors of points, we can draw our max line:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart"><span style="color:#66d9ef">final</span> path <span style="color:#f92672">=</span> Path();
path.moveTo(<span style="color:#ae81ff">0</span>, middle);
<span style="color:#75715e">// draw a line going through each max value coordinate
</span><span style="color:#75715e"></span>maxPoints.forEach((o) <span style="color:#f92672">=&gt;</span> path.lineTo(o.dx, o.dy));

<span style="color:#75715e">// back to zero
</span><span style="color:#75715e"></span>path.lineTo(size.width, middle);

</code></pre></div><p>This will draw a line going from middle left all the way to the right, going back to the zero value. To draw our minimum value contour, we want to continue the line we started. Reading our coordinates in the reverse order going from the last sample back to the first one would allow us to draw the line continuously. We also need to draw our line mirrored meaning that our max value should be at the bottom of the display/drawing area. This is something we can so on the fly by altering the <code>y</code> coordinate value.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart"><span style="color:#75715e">// draw the minimums backwards so we can fill the shape when done.
</span><span style="color:#75715e"></span>minPoints.reversed.forEach((o) <span style="color:#f92672">=&gt;</span> path.lineTo(o.dx, middle <span style="color:#f92672">-</span> (middle <span style="color:#f92672">-</span> o.dy)));

path.close();
</code></pre></div><p>Here is how the path looks like if we don&rsquo;t fill it:</p>
<p><img src="/images/waveforms/waveform-path.png" alt="waveform path"></p>
<p><em>If you wanted to customize the rendering style, you would do that in the <code>WaveformPainter</code> class.</em></p>
<h3 id="alternative-renderings">Alternative renderings</h3>
<p>I opted to draw a line going straight through each coordinate, note that if you wanted the SoundCloud style, you&rsquo;d instead draw rectangles for each sample. There are a lot of options to make the rendering more interesting, for instance you could draw rectangles when zoomed out, draw lines when getting closer and draw curved lines and sample dots when zoomed-in really closely as shown here in <a href="https://www.ableton.com/">Ableton Live</a>:</p>
<p><img src="/images/waveforms/ableton-live.png" alt="Ableton Live zoom waveform"></p>
<h3 id="clipper-view">Clipper view</h3>
<p>Finally, I want to show another cool way to use our waveform path by creating a clipper view allowing us to use our waveform path as a mask for another image (a gradient in this case, but you could use an image or anything really). A concrete product example would be if you analyzed the spectrum of your signal and wanted to show the main frequency range of each window by assigning different colors. This feature is commonly seen in DJ software.</p>
<p><img src="/images/waveforms/waveform-clipper.png" alt="Clipper view"></p>
<p>To do that, we are going to use the <a href="https://api.flutter.dev/flutter/widgets/ClipPath-class.html"><code>ClipPath</code> widget</a> which will render our waveform through a gradient container (also provided by built-in widgets).</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart"><span style="color:#66d9ef">return</span> ClipPath(
  clipper: WaveformClipper(snapshot.data),
  child: Container(
    height: height,
    decoration: BoxDecoration(
      gradient: LinearGradient(
        begin: Alignment.centerLeft,
        end: Alignment.centerRight,
        stops: [<span style="color:#ae81ff">0.1</span>, <span style="color:#ae81ff">0.3</span>, <span style="color:#ae81ff">0.9</span>],
        colors: [
          Color(<span style="color:#ae81ff">0xffFEAC5E</span>),
          Color(<span style="color:#ae81ff">0xffC779D0</span>),
          Color(<span style="color:#ae81ff">0xff4BC0C8</span>),
        ],
      ),
    ),
  ),
);
</code></pre></div><p>We need to implement our <code>CustomClipper</code> which is super straightforward since we already extracted the path drawing logic into our <code>WaveformData</code> class. This refactoring results in allowing us get a clipper in just a few lines of code:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-dart" data-lang="dart"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">WaveformClipper</span> <span style="color:#66d9ef">extends</span> CustomClipper<span style="color:#f92672">&lt;</span>Path<span style="color:#f92672">&gt;</span> {
  WaveformClipper(<span style="color:#66d9ef">this</span>.data);

  <span style="color:#66d9ef">final</span> WaveformData data;

  <span style="color:#960050;background-color:#1e0010">@</span>override
  Path getClip(Size size) {
    <span style="color:#66d9ef">return</span> data.path(size);
  }

  <span style="color:#960050;background-color:#1e0010">@</span>override
  <span style="color:#66d9ef">bool</span> shouldReclip(WaveformClipper oldClipper) {
    <span style="color:#66d9ef">if</span> (data <span style="color:#f92672">!=</span> oldClipper.data) {
      <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>;
    }
    <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">false</span>;
  }
}
</code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>Drawing waveforms isn&rsquo;t that complicated but you need to assemble a lot of parts together to get there.
First we need data processing to extract a reduced version of the information we need to draw an amplitude map.
Then we need a way to load and parse this data.
We need to have a way to position our rendered waveform in our layout in a dynamic way (based on screen size, device orientation etc..).
And finally we need to draw the waveform.</p>
<p>Once we have everything setup, we have a flexible and performant solution to explore more creative ways to render our waveform such as using a clipper, animations or maybe going for a totally different style like circular waveforms.</p>
]]></content>
		</item>
		
		<item>
			<title>Generating Waveform Data - audio representation</title>
			<link>https://matt.aimonetti.net/posts/2019-06-generating-waveform-data-audio-representation/</link>
			<pubDate>Wed, 26 Jun 2019 09:27:11 -0700</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2019-06-generating-waveform-data-audio-representation/</guid>
			<description>Audio visualization is a fascinating topic. We often take it for granted, but sound isn&amp;rsquo;t visible and only exists over time. In the case of a video stream, you can pick a frame/image and you have a snapshot of the video at this specific time. But you can&amp;rsquo;t do that with sound. Sound is the oscillation/vibration of molecules over time, it&amp;rsquo;s by definition a sensation and therefore not something easily visualized.</description>
			<content type="html"><![CDATA[<p>Audio visualization is a fascinating topic. We often take it for granted, but
sound isn&rsquo;t visible and only exists over time. In the case of a video stream,
you can pick a frame/image and you have a snapshot of the video at this specific
time. But you can&rsquo;t do that with sound. Sound is the oscillation/vibration of
molecules over time, it&rsquo;s by definition a sensation and therefore not something
easily visualized.
In this article, I will cover the most common representation of an audio file: the <strong>waveform</strong>.</p>
<p><img src="/images/waveform.png" alt="waveform rendering"></p>
<p>In audio, a waveform represents the amplitude of the signal over time. In other words, it shows the maximum extent of a vibration or oscillation, basically the volume of the sound over time. Note that while commonly used, it&rsquo;s not the only sound representation we have and we will see that even if waveforms look alike, they are often not calculated and rendered the same way.</p>
<p>By the end of this article, you will understand how waveforms are generated and how to create the data you need to more easily and efficiently draw waveforms yourself.</p>
<hr>
<h2 id="understanding-the-audio-signal">Understanding the audio signal</h2>
<p>In the case of a waveform, we are looking at a sound source over a certain
amount of time. Usually that content comes from an audio file (or a in-memory
buffer). Audio content is usually stored in two different ways: compressed and
uncompressed (AKA PCM). You probably encountered <em>.wav</em> or <em>.aiff</em> files, those
are uncompressed files meaning that the amplitude of the signal is stored as is
in the file. On the other hand files such as <em>.mp3</em>, <em>.flac</em> or <em>.m4a</em> are
compressed meaning that an algorithm was used to pack the content more
efficiently, kind of like zipping the audio file. I covered this topic a bit
more in depth in <a href="/posts/2015/12/15/audio-dsp-demystified-sampling/">this
article</a>, but the short
version is that to record audio digitally, we sample the signal x times per
second (44,100 times in CD quality) and we store this information in the file so
we can then re-use the data to move speaker membranes. An audio file contains
the amplitude of the signal, which is exactly what we need to draw a waveform.</p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/b/bf/Pcm.svg" alt="audio sampling"></p>
<p>But there are two problems.</p>
<h2 id="compressed-audio-files">Compressed audio files</h2>
<p>If you have a MP3 file, you have to first decompress its content to get the amplitude. That&rsquo;s a bit problematic because it&rsquo;s a CPU intensive task and the file might be big so we don&rsquo;t want to keep everything in memory. A simple approach might be to convert the mp3 file into a wav file and store it to disk so we can process it. It does require however that the code cleans up after itself and if the same file is reopened/rendered later on, the expensive operation will need to happen again.</p>
<h2 id="too-much-data">Too much data</h2>
<p>To draw a waveform, we don&rsquo;t need as much samples as when playing it back. Processing so much data is expensive and slow, especially on big files where we need to reduce the data because we have more samples that pixels to draw the waveform on. That&rsquo;s why software like <a href="https://ableton.com">Ableton Live</a> and <a href="http://audacity.sourceforge.net/">Audacity</a> create summary files.</p>
<blockquote>
<p>&ldquo;If Audacity is asked to display a four hour long recording on screen it is not acceptable for it to process the entire audio each time it redraws the screen. Instead it uses summary information which gives the maximum and minimum audio amplitude over ranges of time. When zoomed in, Audacity is drawing using actual samples. When zoomed out, Audacity is drawing using summary information.&rdquo;</p>
</blockquote>
<p>You can read more about Audacity <a href="http://www.aosabook.org/en/audacity.html">BlockFiles here</a></p>
<h2 id="generating-a-summary-information-file">Generating a summary information file</h2>
<p>From the <a href="https://www.bbc.co.uk">BBC</a> to <a href="https://soundcloud.com">Soundcloud</a> most services offering audio playback need a way to efficiently render waveforms. This is usually done by pre-calculating a summary server side when the audio file is first seen. This pre-calculated summary can then be loaded by the client at the same time (or even before) the audio file is downloaded and ready to play.</p>
<p>There are various ways to create a summary file and store its data. But the overall concept is always the same, we need to reduce the amount of data so we group samples together and we extract a value representing the time window we are reducing. One option is to create an average value of that window. Let&rsquo;s say we group 256 samples together, we could add all the values together and then divide by 256, that would give us the average amplitude during that time period.
Another option is to follow Audacity&rsquo;s approach and for each window, we get the min and max values. This is less efficient from a storage perspective because we will end up with twice the data size, but it gives us more resolution on the data to draw an arguably better waveform.</p>
<p>Luckily for us, the BBC R&amp;D group wrote a free and open source tool to do just that:
<a href="https://github.com/bbc/audiowaveform">https://github.com/bbc/audiowaveform</a></p>
<p>The <em>audiowaveform</em> command line tool can generate summary files in binary and json formats and can also generage waveform images but I&rsquo;m not interested in this last feature since fixed size waveforms don&rsquo;t go well with modern responsive UI designs.</p>
<p>I picked this tool because it&rsquo;s free, we can dig into the source code, wrap it to be used from another programming language and the default options are great to get started. It&rsquo;s also well documented, written and maintained. Finally, the BCC also released JS tools to consume the data, while you might not care to use those libraries, it&rsquo;s great to have a reference implementation to understand how things work.</p>
<p>I would suggest to spin a web service that would receive an audio file (more likely via a GCS/S3 reference), copy the file locally and summarize it using the <em>audiowaveform</em> tool:</p>
<p><code>$ audiowaveform -i input.mp3 -o test.json</code></p>
<p>Then copy the json or binary data to GCS/S3 so it can be easily accessible.</p>
<p>The window size (by default 256 samples) depends very much on what you are going to do with the waveform and the average duration and sample rates of your audio files. Grouping 256 samples together on a 44.1KHz audio files means that we still have more than 172 data points per second. But if you deal with very short sounds it might not be enough, here is an example if a short cymbal sample, the entire file is less than 2 seconds and the hit itself last around 500ms:</p>
<p><img src="/images/oneshot-256-waveform.png" alt="cymbal waveform without enough resolution"></p>
<p><em>(the example waveforms are rendered in a <a href="https://flutter.dev/">Flutter</a> app using path drawing, the same results can be achieved on the web using canvas, more on that in a later post)</em></p>
<p>As you can see the resolution isn&rsquo;t great. So we can try again by using a smaller window. Here is the same rendering but with the grouping using half the number of samples: <code>-z 128</code></p>
<p><img src="/images/oneshot-128-waveform.png" alt="cymbal waveform at 128"></p>
<p>It&rsquo;s better but we can&rsquo;t really zoom in, the resolution is still quite low. Let&rsquo;s try with a window of 64 samples:</p>
<p><img src="/images/oneshot-64-waveform.png" alt="cymbal waveform at 64"></p>
<p>That&rsquo;s much better!</p>
<p>Note that the BCC tool is only one of the many freely available tools out there. I chose it for this article because it&rsquo;s easy to use and demo. However, depending on your use case, you might prefer to do normalized averages instead. To do that, you might want use other existing tools such as <a href="http://sox.sourceforge.net/">SoX</a> or <a href="https://ffmpeg.org/">FFmpeg</a>. If you don&rsquo;t care about zooming, I&rsquo;d suggest you pick a resolution that works for most of your files (let&rsquo;s say 800 points per file) and average dynamically based on the source length. Also, as the BBC tool does, I&rsquo;d suggest to keep the data in integer values instead of using floats and specify the bit depth so you can then convert the data during rendering on a range of -1/+1. This approach results in much smaller files and faster parsing. Finally you&rsquo;re better off using a binary format but whatever you do, make sure to store the file gzipped to save network transfer time.</p>
<h2 id="conclusion">Conclusion</h2>
<ul>
<li>Pre-calculate waveforms server side.</li>
<li>It&rsquo;s not that complicated, use FOSS such as the BBC&rsquo;s or SoX/FFmpeg.</li>
<li>Tweak the sampling window based on your use cases or the file duration.</li>
<li>Leverage modern cloud solutions such as PubSub/SQS and on-demand cloud functions to make sure you can ingest a large volume and keep the costs low.</li>
</ul>
<p>Next, we will cover rendering waveforms.</p>
]]></content>
		</item>
		
		<item>
			<title>Programmer toolkit — an opinionated tour — Part I</title>
			<link>https://matt.aimonetti.net/posts/2019-05-programmer-toolkit-an-opinionated-tour-part-i/</link>
			<pubDate>Thu, 02 May 2019 02:24:51 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2019-05-programmer-toolkit-an-opinionated-tour-part-i/</guid>
			<description>Here’s a very opinionated tour of some of the various technologies available to individuals and companies. This is far from a complete list and the comments are based on my personal opinions which might not match your expectations, values or even experience. This first part will focus on programming languages.
Programming languages Safe bets and my preferred languages Go https://golang.org Free and open source, from Google.
Go has been my goto language for many years now, it’s a great server and system programming language that shines for its simplicity and performance.</description>
			<content type="html"><![CDATA[<p>Here’s a very opinionated tour of some of the various technologies available to individuals and companies. This is far from a complete list and the comments are based on my personal opinions which might not match your expectations, values or even experience. This first part will focus on programming languages.</p>
<h3 id="programming-languages">Programming languages</h3>
<p><img src="/posts/2019-05-02_programmer-toolkitan-opinionated-tourpart-i/images/1.jpeg" alt="image"></p>
<h4 id="safe-bets-and-my-preferred-languages">Safe bets and my preferred languages</h4>
<h4 id="go">Go</h4>
<p><a href="https://golang.org/">https://golang.org</a> Free and open source, from Google.</p>
<p>Go has been my goto language for many years now, it’s a great server and system programming language that shines for its simplicity and performance. It works <strong>best when developed server side APIs/services and client side CLIs</strong>. It’s a language that is easy to transition to, supports large team working on the same code base and has great tooling and compilation time. The language could offer more flexibility (Go 2 means to address some of those complaints) and the C interop could be faster/better (Gophers would tell you not use C). Go is a very popular programming language in the “devops” world (Docker, Kubernetes, Terraform, CloudFoundry and many more). <em>Recommendation:</em> adopt as server side language if you agree with the strong philosophy.</p>
<h4 id="typescript">TypeScript</h4>
<p><a href="https://www.typescriptlang.org/">https://www.typescriptlang.org/</a> Free and open source, from Microsoft.</p>
<p>TypeScript has been my recommended way to write JS for a few years now. It’s a <strong>superset of JavaScript that compiles to plain JS but adds optional static typing and a</strong> <a href="https://en.wikipedia.org/wiki/TypeScript#Language_features"><strong>other features</strong></a>. I prefer it over React’s <a href="https://en.wikipedia.org/wiki/React_%28JavaScript_library%29#JSX">JSX</a> and it looks like TS is slowly but certainly becoming a standard alternative to JS. Great documentation, tooling and debugging support. <em>Recommendation:</em> adopt if you have a decent team or decent amount of JavaScript and don’t have 10+ years of JS experience.</p>
<h4 id="javascript">JavaScript</h4>
<p><a href="https://www.javascript.com/">https://www.javascript.com/</a> spec with free and open source implementations, originally from Netscape.</p>
<p>JS is the language that runs almost everywhere, <strong>the language has a lot of challenges but it’s ubiquitous</strong>. It certainly provides a lot of flexibility and allows new developers to feel progress really quickly. It’s however a really hard language to master and the tooling around the language seems to be moving really fast without a change to mature. My biggest issue with the language its interpreted nature and flexibility often results in runtime issues that are hard to catch/debug. <em>Recommendation:</em> if you are targeting JS, I’d suggest to take a look at TS, while it requires a little more onboarding/setup, I feel the superset provides a lot of answers to the problems I see in JS.</p>
<h4 id="java">Java</h4>
<p><a href="https://www.java.com/en/">https://www.java.com/</a> Free and open source implementations, originally from Sun Microsystems.</p>
<p>Java is a sure bet, it really managed to catch-up after years without design evolution. Java is a language for the masses, <strong>it’s pretty easy to learn, lots of resources and libraries, it performs well but it uses a LOT of RAM</strong>. In a world where RAM still comes at a premium that’s a bummer, also having to spend days tweaking the GC settings because the language allocates so many objects isn’t ideal. I still prefer Go for server side tasks, but based on the team skills and the project being worked on, Java can be a great solution. <em>Recommendation:</em> not the most exciting language but it will get the job done and you will find talented devs, adopt if you are ok being conservative in your tech choices.</p>
<h4 id="c">C</h4>
<p><a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/">https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/</a> Free and open source implementations, from Microsoft.</p>
<p>C# is <strong>Microsoft version of Java but with better tooling, more language features and limited cross platform support</strong>. Very much like Java, C# is a solid choice, it’s a flexible language with a performing runtime, lots of skilled developers but unlike Java, it doesn’t run as well on other platforms than Windows. Thanks to mono and .NET Core, C# is becoming more popular outside of the Windows ecosystem and is the de facto language of <a href="https://unity.com/">Unity</a>. <em>Recommendation:</em> unless you have very specific needs, I probably wouldn’t choose C# as server side programming language but would use it for Unity or Xamarin projects, especially if you have previous experience with C#.</p>
<h4 id="python">Python</h4>
<p><a href="https://www.python.org/">https://www.python.org/</a> Free and open source by Guido van Rossum.</p>
<p>Python is the standard scripting language these days and while the community is still having issues migrating developers from v2 to v3, it’s the default language of <strong>data scientists and machine learning</strong> developers for which no other programming languages comes close to having the same quality of libraries. <em>Recommendation:</em> stick to what Python is best at: data science and ML.</p>
<h4 id="ruby">Ruby</h4>
<p><a href="https://www.ruby-lang.org/">https://www.ruby-lang.org</a> Free and open source by Yukihiro Matsumoto.</p>
<p>Ruby can be considered a more flexible/dynamic version of Python. As a language, it isn’t very popular outside of the Rails framework and became very popular at the same time as Rails in the web 2.0 boom. While not as popular as it once was, it’s found in many companies with legacy Ruby code or Rails applications. <em>Recommendation:</em> use when Rails makes sense.</p>
<h4 id="hot-takes-on-less-safe-choices">Hot takes on less safe choices</h4>
<p><strong>Rust</strong>: if Go is supposed to be an alternative to C, Rust is an alternative to C++. Very powerful system language especially to write safer low level code, but challenging to learn. <em>Recommendation:</em> only use for low level or embedded programs.</p>
<p><strong>Swift:</strong> great replacement for Objective-C, fine language but stuck on the Apple ecosystem. <em>Recommendation:</em> use if you are focusing on native and Apple first.</p>
<p><strong>Kotlin:</strong> was a promising language when Android started supporting it making it a viable Java replacement but now Google is moving to Flutter/Dart for Fuschia and mobile dev, I’m less excited about this language that sometimes feels a bit overly engineered. <em>Recommendation:</em> stick to writing Android apps with Kotlin and only if you are focusing on native (server side Kotlin is fine but sticking to modern Java would be a safer bet).</p>
<p><strong>Scala:</strong> I tried, but nobody seems to agree on how good Scala should look like. Fascinating academic language that took a big hit when Twitter switched from Scala to Java. <em>Recommendation:</em> pick an alternative language.</p>
<p><strong>Clojure:</strong> I loved the idea of writing Scheme/Lisp on top of the JVM then I realized I wasn’t smart enough to track the state/shape of the values through the processing chain. Process a big chunk of data to only realize 4 hours later than the data half way through the pipe wasn’t what you expected. <em>Recommendation:</em> learn for fun, pick an alternative language for a professional project.</p>
<p><strong>Elixir:</strong> very interesting language on top of Erlang/OTP, it captivated the interest of early Ruby developers but didn’t become a standard, stayed niche and isn’t backed by a big name. <em>Recommendation:</em> play with it because it’s a great language and a fun web framework (<a href="https://phoenixframework.org/">Phoenix</a>), but consider an alternative language for a professional project.</p>
<p><strong>PHP</strong>: unless you work at Facebook, pick an alternative language.</p>
]]></content>
		</item>
		
		<item>
			<title>A framework for R&amp;D</title>
			<link>https://matt.aimonetti.net/posts/2019-01-a-framework-for-rd/</link>
			<pubDate>Wed, 23 Jan 2019 17:00:59 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2019-01-a-framework-for-rd/</guid>
			<description>Originally posted on Medium
Impactful innovation is what Research &amp;amp; Development (R&amp;amp;D) teams around the world are working hard towards. Yet, there don’t seem to be blueprints that are reused and trusted across companies. On one hand, we get very little visibility into this process and on the other, it seems very challenging to define and measure success.
I love challenges, the harder the better. And the R&amp;amp;D challenge while also building sustainable businesses or growth is something I’ve been thinking a lot about for a while.</description>
			<content type="html"><![CDATA[<p><a href="https://medium.com/@mattetti/a-framework-for-r-d-6aaaf8c05841">Originally posted on Medium</a></p>
<p>Impactful innovation is what Research &amp; Development (R&amp;D) teams around the world are working hard towards. Yet, there don’t seem to be blueprints that are reused and trusted across companies. On one hand, we get very little visibility into this process and on the other, it seems very challenging to define and measure success.</p>
<p>I love challenges, the harder the better. And the R&amp;D challenge while also building sustainable businesses or growth is something I’ve been thinking a lot about for a while. So here are my thoughts and some of the things I’m experimenting with at <a href="https://splice.com">Splice</a>. It will take some time for me to confirm, self-correct and codify a solid, empirical approach but I like the idea of documenting my findings and experiments as a way to break the cycle and to keep myself honest. I will start by mentioning some of the main challenges that R&amp;D teams must surmount and will then share my own framework.</p>
<h4 id="rampd-is-just-a-label-for-accelerated-and-impactful-innovation">R&amp;D is just a label for accelerated and impactful innovation</h4>
<p>The first think I’d like to clarify is that R&amp;D is just a label. It’s not a goal, it’s not even a strategy, it’s a label used to refer to things moved out of the normal process with specific expectations. The objective is clear tho: companies invest in “R&amp;D” because they usually want <strong>accelerated and impactful innovation</strong>. The short version of the rational is that <em>it’s really hard to focus on delivering on short term objectives (OKRs/KPIs) while also exploring risky hypotheses</em>. So comes a time when companies decide to have teams focused solely on “innovation”. Hoping that <strong>by isolating them from the day-to-day concerns</strong>, they can <strong>find breakthroughs that will empower the business and make a difference</strong>.</p>
<p><img src="/posts/2019-01-a-framework-for-rd/images/1.jpeg" alt="image">
Leonardo da vinci, Crossbow Machine</p>
<p>Before going further, I’d like to define a few useful terms used in the rest of this document:</p>
<ul>
<li><em>experiments:</em> measurable procedure undertaken to make a discovery, test a hypothesis, or demonstrate a known fact without being sure of the eventual outcome. Concretely, that usually means building and running some sort of prototypes and measuring its impact.</li>
<li><em>learnings:</em> answers to questions we might have or discovered as we went. Learnings reduce the unknowns around a specific topic.</li>
<li><em>local vs. global innovations</em>: by local innovations, I refer to innovations being made by the teams working on the current roadmap. Global here, means outside of the scope of the roadmap, innovations that might span across teams or even outside the current roadmap.</li>
<li><em>local exploration</em>: refers to the discovery phase done by teams already focusing on a particular domain area.</li>
</ul>
<p>Discussing with many industry R&amp;D leaders and driving myself this effort at Splice, I defined three significant challenges:</p>
<h4 id="primary-challenge-making-decisions">Primary challenge: making decisions</h4>
<p>This seems like an obvious challenge but yet it took me a while to grasp how critical it is to understand and plan for this challenge. Being in charge of bringing accelerated and impactful innovation sounds exciting, but where do we start, why, how do we communicate that? Are we too focused on “local innovations” vs big picture innovations? Making any kind of decisions, technical or not, is much harder in a context without clear directions, guide rails and metrics. Especially if we don’t have a way to evaluate success/failure.</p>
<h4 id="secondary-challenge-what-does-success-look-like">Secondary challenge: what does success look like?</h4>
<p>This is the biggest question I faced and one that I felt most compelled to answer before committing resources to R&amp;D at Splice. Because innovation isn’t always tangible and because people within our organizations have different expectations, I wanted a clear framework of evaluation. Selfishly, I wanted to know if I was doing a good job or not, and I wanted to be able to have this discussion with others using a baseline we all agreed on. There is another aspect to this challenge: if we do find an adequate approach to R&amp;D, we can create a framework by which to make decisions. Not all decisions and high fives in our framework would necessarily lead to “breakthroughs” or features shipped to prod. On the contrary, success lies also in the ability to decide on what shouldn’t be shipped or better yet, not worked on at all. Success is about decisions we manage to make, and in that sense, everything we prove we shouldn’t do, must also be celebrated as a huge win!</p>
<h4 id="third-challenge-communication">Third challenge: communication</h4>
<p>There is so much stigma around R&amp;D that communication is a huge part of what R&amp;D teams should excel at. It might sound counter productive to many, especially if you imagine a R&amp;D team as a bunch of crazy scientists running experiments in a basement lab. Turns out most R&amp;D teams work very much in isolation and rarely interface with Product or Engineering. When they do, the relationship doesn’t have deep roots, and it is often perceived as a distraction. We end up with 2 common scenarios:</p>
<ul>
<li>R&amp;D team doesn’t feel like they are shipping anything and aren’t valued.</li>
<li>The Product &amp; Engineering teams feel that they are forced to change their roadmap to ship (sometimes subpar) experiments that they have to maintain.</li>
</ul>
<p>These 2 scenarios can be avoided if we all work on the same objectives, reduce our ego to a minimum and provide value to each other.</p>
<p>R&amp;D is removed from the day-to-day so that the team can focus on out of band hypotheses. But they also want to see their work being shipped and be impactful. To accomplish that, finding amazing actionable learnings isn’t enough. Work needs to be done to have everyone in sync, expose valuable findings to other teams and build the relationships to make sure these findings make it to the roadmap. You can’t be impactful if you are totally isolated, building those bridges is absolutely critical so you can become and champion and find other champions within the organization.</p>
<h3 id="experiment-developing-an-rampd-framework">Experiment: developing an R&amp;D framework</h3>
<p>Here is the framework I put together for Splice and something I am still tweaking. It’s far from perfect but it tries to address some of the challenges I highlighted earlier.</p>
<p><strong>Process:</strong> Have stakeholders define one or more key hypotheses. For each hypothesis agree on desired learnings, budget and timeline.</p>
<p><strong>Output:</strong> Regular communication, actionable (and documented) learnings, product briefs that summarize the research and make suggestions and finally prototypes/demos that helped us come to our conclusions and help others “feel” the potential.</p>
<p><strong>Success evaluation:</strong> stakeholders evaluate the extracted learnings and how it impacts the roadmap.</p>
<h4 id="stakeholders">Stakeholders</h4>
<p>R&amp;D is a service to the company and having a “Braintrust” to help steer, bring a different perspective and champion your work is a huge advantage. This is similar to <a href="https://amzn.to/2QSJTHR">Pixar’s approach to creative guidance</a>. R&amp;D doesn’t technically report to the stakeholders, they are a support mechanism. Those experienced experts work on their own challenges but come together to discuss how innovation can help the company, discuss hypotheses that aren’t explored but could be extremely impactful. Finally, they help refine the direction to maximize the impact on the work on the roadmap. Those stakeholders have to be influential people who can see the great big picture and can express candid feedback. I chose 3 stakeholders, depending on how your company works, you might pick other stakeholders:</p>
<blockquote>
<p><strong>Product Partner:</strong> Looks <strong>past our current roadmap</strong> and finds areas that if explored would help us <strong>make better decisions</strong>.&gt; <strong>Business Partner:</strong> Looks at the <strong>current &amp; future economical situation</strong>, helping define <strong>business opportunity areas</strong> to explore.&gt; <strong>Transfer Partner:</strong> <strong>Makes sure learnings are properly transferred</strong>. This stakeholder is also the best judge of what should be explored locally vs by a dedicated future-looking team.</p>
</blockquote>
<h3 id="main-hypothesis">Main Hypothesis</h3>
<p>Together we define a big hypothesis we want to explore. The hypothesis will be our North Star for a few months. From there, we define desired learnings to focus on. Those desired learnings will be used to extract initiatives but also to evaluate our work.</p>
<p>Let’s say our business provides services to the elderly. We’ve been focusing on a watch type device to monitor their health and falls. Our product is backed by a subscription service. We have a solid roadmap to execute on this vision, but we also believe that innovation could have a huge impact.</p>
<blockquote>
<p><strong>Hypothesis</strong>: <em>“We believe that leveraging home automation integration would bring children and parents closer, thereby increasing the mental health of both groups.”</em></p>
</blockquote>
<p><strong>Context:</strong> The business partner is very interested in a potential new revenue line, the Product partner is thinking about next year’s roadmap and the feasibility of such an approach. Everybody is thinking about differentiating themselves from the competition as well as the potential ROI. Everybody is excited about the project but there are way too many unknowns to add this project to the roadmap.</p>
<h3 id="desired-learnings"><strong>Desired learnings</strong></h3>
<ol>
<li>Who are the main home automation providers, what does it take to integrate with them?</li>
<li>What kind of experiences can we provide to our users?</li>
<li>What’s the technical investment required to build/ship a first experience on the biggest platform? How about integrating with other platforms?</li>
<li>How to measure usage, traction and the relationship between our 2 groups?</li>
<li>What are ways to monetize such a service if we were to ship it?</li>
</ol>
<p>Those desired learnings come from discussions with the R&amp;D stakeholders. They need to be able to answer the obvious questions the teams would have if the hypothesis is confirmed and the stakeholders decide to add a related project to the roadmap. <strong>The goal isn’t to have something ready to ship to users, but to have gathered enough facts so that the company has enough visibility to make the right planning decisions.</strong> The decision might be as simple as whether or not to pursue the opportunity pursue an opportunity, or should we not. Both outputs are great since they are decisions and decisions are what help companies move forward. Also, proving that we should not do something will save a huge amount of time and money, as well as solidify the direction the company is taking.</p>
<h3 id="budget-and-timeline">Budget and timeline</h3>
<p>We defined a North Star and we have specific questions we’d like to answer but we also need to timebox our research. This is a very important phase because we are setting the expectations for the team and for the rest of the company. <strong>We aren’t building a product we are shipping to all our users, we are building confidence in whatever direction the company will take.</strong> This is an interesting exercise which helps the stakeholders and the R&amp;D team define how much we want to invest in the hypothesis and each desired learning. Concretely that avoids treating R&amp;D as a black box with results coming at unexpected times. It also gives an opportunity for the stakeholders to change focus at the end of a budgeted period. I hear Google X works a bit like that, each year, each project lead presents their team progress and asks for a renewal or increase of budget. This is somewhat similar except at a smaller scale. We need to evaluate more than one hypothesis per year and need to influence the current business instead of creating brand new ones.</p>
<h3 id="output">Output</h3>
<p>The goal is to have significant impact on the future of the company and we do that by influencing the roadmap. So our output has to be supporting this goal. In most companies, the roadmap is managed by a Product organization. We therefore need to provide them with what they need to understand and decide if altering the roadmap makes sense. There are 3 main forms of output that seem to help:</p>
<ul>
<li><strong>Product Briefs</strong>— use the Product language to summarize learnings. It’s a bit awkward at times, since we are answering a question and making a recommendation but don’t have a full integration plan, that would be something the Product team would do later on. However awkward it might feel to non Product people, it is super important to speak a common language. I used a simple template that I’ll refine as I go, here are some of the sections: the idea in one sentence, goals, counter-goals, opportunity, hypothesis, use cases, key open questions, key open questions, suggestions. And finally a detailed breakdown of the experiment, with links to the research, code and demos.</li>
<li><strong>Prototypes/demos</strong>— whenever possible, providing people an opportunity to experience themselves what we could build together.</li>
<li><strong>Documentation</strong>, lots of documentation and examples — there are two reasons for that, first the product briefs don’t go into all the details of what we learned and tangents discoveries. Secondly, because if the learnings turn into a solution that will make it to the roadmap, you want to provide all teams (eng, design etc…) with as much information as possible so they don’t waste time and feel confident they can work within a certain timeline.</li>
</ul>
<h3 id="conclusion">Conclusion</h3>
<p>If you are looking into building an R&amp;D team or are considering working with one, consider defining a process around it. Have clear discussions about expectations and accountability. While leaders often love investing in “Innovation”, the meaning and expected output are often too unclear to set an R&amp;D team up for success. Instead of expecting such a framework to be delivered to you, consider offering the framework you think would help the company and the R&amp;D team to stay aligned. It won’t be perfect, and will need to be tweaked, don’t overthink it, R&amp;D the “R&amp;D process”. Learn, evaluate and adapt, the company and the team will feel and be motivated by the impact.</p>
]]></content>
		</item>
		
		<item>
			<title>Being the co-founder of a VC backed startup</title>
			<link>https://matt.aimonetti.net/posts/2019-01-being-the-co-founder-of-a-vc-backed-startup/</link>
			<pubDate>Sat, 12 Jan 2019 23:00:19 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2019-01-being-the-co-founder-of-a-vc-backed-startup/</guid>
			<description>I’ve now been the co-founder and CTO of Splice for almost 6 years. It’s officially the longest place I ever worked at. It’s funny because it does feel like we just started yesterday. I decided to write down some unedited thoughts and share them here. I remembered thinking that I’d love to know what it was really like to be a founder, but that’s not something I could find on the internet.</description>
			<content type="html"><![CDATA[<p>I’ve now been the co-founder and CTO of Splice for almost 6 years. It’s officially the longest place I ever worked at. It’s funny because it does feel like we just started yesterday. I decided to write down some unedited thoughts and share them here. I remembered thinking that I’d love to know what it was really like to be a founder, but that’s not something I could find on the internet. Hopefully a future entrepreneur will find this post and will get a glimpse at what it is like for me. (sorry for the raw/unedited version, but I felt the post would otherwise stay in my draft folder forever)</p>
<p>I remember so clearly building the first prototype and hearing the excitement in the voice of my co-founder. The first pitches, the first hires, the first people we had let go 😥 The first arguments, the first fights, the first wins, the first 1:1s, the first dollars we made, the firsts disappointments. The first bugs, the first crashes, the first breakthroughs, the first townhome meetings. The first term sheets, the first board meetings, the first no, the first yes! The first employee departures, the first M&amp;A, the first team off-site. The first exec meeting, the first OKR meetings, the first advisors, the first $10M paid to creators! Wow, so many memories, I certainly spent too much time thinking about tomorrow and not enough celebrating.</p>
<p><img src="/posts/2019-01-12_being-the-cofounder-of-a-vc-backed-startup/images/1.gif" alt="image"></p>
<p><strong>Kruskal-Szekeres spacetime diagram</strong></p>
<p>It’s been and still is a wild ride. It feels like we started yesterday, yet it feels like it’s been forever. Often people want to know what it is like to be the founder of a startup. They have this glamorous silicon valley image clashing with the image reflected by Silicon valley, the HBO TV show. The reality is hard to describe, it’s full of pain, excitement, highs and lows. It’s a processes that forces you to reevaluate and reinvent yourself constantly. It’s lonely yet you are surrounded by others going through the same thing.</p>
<p>The experience seems to be different for each founder depending on their personality, cultural, social and economical background (and unfortunately also their gender and skin color). Running a VC backed company is like playing a board game where only a few select group of people know the rules. It’s not like the rules are secret or anything, it’s just that they aren’t the rules most of us grow up learning. Those rules seem very foreign at first. Worse, those rules are implicit, they are enforced guidelines that are believed to guide you to a predefined notion of success. Mind you, those rules change with the market. The way you were raising money in 2013, would probably not work in 2019. So you have to stay up to date with those implicit and changing rules. Let’s be honest, this part of the system is very unfair, it favors a small group of privileged people who have the social capital to be taught those rules. Talent is everywhere, opportunities are not. I have to admit that this is something that really bothers me. I had the chance to discuss this topic with some VC partners I trust. It’s clear they are very aware of the situation and in some cases try to induce local change. It’s clearly not enough but I honestly appreciate their effort when they try.</p>
<p>A thing I also learned the hard way is that you rarely have an opportunity to correct your mistakes. Running a VC backed startup is like strapping a rocket to your chair, it might get you to the finish line faster, but a few small mistakes and you are out (and a crappy rocket might blow up). It’s an exciting process, especially if you have little patience, but the g-force you have to endure will take its toll on most of us. Another funny thing about this analogy is that if you don’t pass you, you get used to the initial speed and when the rocket is slowing down because you are getting close to orbit, you miss the initial speed and thrill.</p>
<p><img src="/posts/2019-01-12_being-the-cofounder-of-a-vc-backed-startup/images/2.jpg" alt="image"></p>
<p>Robert Courter in the Bell Rocket Chair.</p>
<p>I’m not a nostalgic person and I don’t live in the past regretting things, but I often think of the many mistakes I made so I don’t make them again. I wish I could fix those mistakes now that I know the consequences, but the time window is often closed. The best I can do is assume the consequences and not making those mistakes again as well as helping others who are going through the same challenges. As much as we love saying that we embrace failure, ask a founder how they are doing, the most common answer is probably a version of: crushing it! Unfortunately, the reality is probably very different. Self-doubt is probably the best feeling describing being a founder. But we don’t want people to doubt us, otherwise investors won’t support us, we won’t be able to hire top talent and we will fail to make the “X under X” list. So many founders at all stages struggle with depression, substance abuse, deep feeling of loneliness. It’s quite sad to see peers going through that while the media love glorifying or at least “glamourising” our self destructive behaviors.</p>
<p>VCs are not your friends, but they aren’t your enemy either. Like you, they are doing their job and their job is to make sure you exponentially increase the financial value of their investment. You can have a close relationship with some investors, they can provide you with great insights and be supportive. But their primary duty is to their firm and they LPs. They are being kept accountable and have to show results. This is not a secret, it’s their duty. It’s too easy to blame VCs when things go bad. Don’t get me wrong, there is a fair share of bad VCs out there, but remember that you are the one who agreed to tape a rocket to your chair. They provided you with the rocket, they didn’t force you, being VC backed is certainly not for everyone or every project. You told them you’d manage the pressure, the growth etc.. But did you make sure you were aligned on the conditions attached to using the rocket? If they don’t think you will make it, don’t be mad if they don’t want to add more gas in the rocket or suggest you stop the race. If they feel that you can make it but you are slowing down too quickly on purpose, don’t be mad if they pressure you to add more gas and take bigger risks. That’s part of the game.</p>
<p>Another thing to remember, <strong>it’s all about the story</strong>. That’s probably the number 1 rule of the VC club. The same way we say that the journey is more important than the destination, the story of a startup is almost more important than its actual output. The story is constantly developing but is always promising that there is always better things coming soon. If bad things were to happen, we turn them into good things. The story must always sell a better future so the valuation keeps going up and the excitement doesn’t die. At least that has to be true on the outside. I don’t think this approach is good or bad, this is just the way it is. It’s just part of the culture and everyone in it knows it.</p>
<p>Finally, something I didn’t hear a lot of founders talk about. Non-CEO founders aren’t seen as equals to the CEO. That usually becomes more and more real over time when the company grows to a big enough stage where the CEO founder has to start being a 100% CEO, making harder and bigger decisions and focusing on “CEO’ing” the company. VCs will provide more support and resources to a CEO than any other C suite roles and it makes total sense. It’s pretty logical when you think about it, the CEO sets the direction for the company, they energize, drive and motivate the exec team to accomplish the vision. VCs are most impactful when they can support the person setting the direction. Now here is what’s not often talked about. This is both a curse and blessing. As we all know, the people who are at the start of a company aren’t often the right people for later stages. And that keeps staying true as long as the company evolves. The thing is, as non-CEOs, it’s easier to redefine our roles or even move on in some cases. It’s much much harder for a CEO-founder. That can be very tough to realize that the company you dreamed of, built, launched might have overgrown you. Actually, scratch that, I don’t like this term overgrowing. It implies that you might not have grown fast enough. In my experience, it’s the opposite, I saw amazing founders who grew so much that they realized that their current role was not what they wanted or should be doing and they went out there and hired amazing execs (presidents, CEOs, CTOs, COOs..) who were a better fit for the current company stage. Because you have a rocket pushing your back, you don’t have much time to think about it, you just need to have a way to evaluate things quickly and make those decisions as fast as possible.I hope I was able to give you a glimpse of what it might be to the founder of a startup. It’s exciting, thrilling and very often tough in ways you didn’t quite expect. Being VC backed is a choice, it’s a path and it comes with its set of rules. If it’s your first time, you might not know those rules and it’s ok to ask (also start reading blogs like <a href="https://avc.com/">Fred Wilson’s</a>, <a href="https://bothsidesofthetable.com/">Mark Suster’s</a> and many more, you will find patterns). If your partners have more experience than you ask them to share, good VCs also know to explain those things clearly and the ones I know won’t judge you for asking but they will keep you accountable. If you learn how to ask questions, you will be able to catch-up very quickly.</p>
<p>Finally, for those who might think I sound a bit pessimistic, you probably don’t know me well 😎 Lately, there has been some increased backlash against being VC and VC backed startups. Some arguments were absolutely valid and some maybe less. My hope is that this post will bring some color to the discussion in a form that I hope is as objective as I could be.</p>
]]></content>
		</item>
		
		<item>
			<title>Building confidence as a CTO</title>
			<link>https://matt.aimonetti.net/posts/2018-07-building-confidence-as-a-cto/</link>
			<pubDate>Mon, 02 Jul 2018 19:38:56 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2018-07-building-confidence-as-a-cto/</guid>
			<description>I’ve been the CTO of Splice for more than 5 years now, from early prototypes to today’s 100+ employees. When Steve and I started Splice, I never thought we would get this big. What I didn’t know was that one the challenges of being a CTO post product-market fit would be to build internal and external confidence around the engineering group. I’m not talking about making sure we use the right technology, or that we have the best engineers, I’m talking about our ability to function as a critical part of a complex system.</description>
			<content type="html"><![CDATA[<p>I’ve been the CTO of <a href="https://splice.com">Splice</a> for more than 5 years now, from early prototypes to today’s 100+ employees. When Steve and I started Splice, I never thought we would get this big. What I didn’t know was that one the challenges of being a CTO post product-market fit would be to build internal and external confidence around the engineering group. I’m not talking about making sure we use the right technology, or that we have the best engineers, I’m talking about our ability to function as a critical part of a complex system.</p>
<p>There are a decent amount of books, events, talks and coaches for CEOs but we hear very little about the struggles of being a CTO. I get it, talking about mistakes we made learning on the job isn’t glamorous, it’s actually quite embarrassing and painful to think about. But part of this exercise is therapeutic, the other will hopefully help current or future CTOs. So here is one thing I’ve learned the hard way and was a very valuable lesson:</p>
<h3 id="set-expectations-and-put-together-an-evaluation-framework">Set expectations and put together an evaluation framework</h3>
<p>This probably sounds painful, unnecessary and something that might slow you down. Yet, I so wish I had done it a few years back, it would have saved me from so many mistakes. Much the same way a test suite guards against regressions, an evaluation framework can make sure we aren’t backsliding on our responsibilities. Writing tests helps us ensure the proper behavior of a system and to avoid regressions. But more importantly, it builds confidence in what we ship and the process around it.</p>
<p><strong>As CTO, one of my responsibilities is to build confidence in the engineering org.</strong> We wouldn’t ship code without tests, yet we might ship an entire org without an objective way to define and evaluate if it matches our expectations. One very important detail about this point is that engineering isn’t the sole stakeholder of this initiative. <em>Confidence must be provided to the rest of the organization to keep it healthy</em>. It doesn’t matter if you feel great about your part of the org when the rest of the company doesn’t feel the same. We also owe that to the CEO who has to justify the speed/quality of the org and for that they need to be able to trust the team can deliver or handle hard situations.</p>
<h3 id="to-build-confidence-measure-and-monitor-those-3-areas">To build confidence measure and monitor those 3 areas</h3>
<ol>
<li>Velocity</li>
<li>Quality</li>
<li>Organization Maturity</li>
</ol>
<h4 id="velocity">Velocity</h4>
<p>Most startups who grow decently fast, start feeling they are getting slower. New employees, new processes, management and paying back technical debts are all well known reasons for a slower team throughput. But how do we determine if we are slow or fast? Having a baseline and a way to measure is critical to building confidence. I can’t feel stronger about the requirement of having a way to measure the throughput of the team. The metrics you will pick won’t be perfect, they actually probably won’t be great but you need this baseline to help build confidence, detect issues and celebrate progress. The metrics you pick will depend on your development style, from story points of delivered stories to development flow metrics such as the number of deployments per day.</p>
<p>As much as I hated on <strong>agile story points</strong> for years, even if deeply flawed, this approach is still one of the best compromises I know of. <strong>Alternatively, measuring the speed at which code is shipped</strong> isn’t a bad idea. Consider the following metrics:</p>
<ul>
<li>the number of <em>pull requests opened</em> per week</li>
<li>the <em>number of pull requests merged per week</em></li>
<li>the <em>average time-to-merge</em> (or % of Pull Requests (PRs) merged under a certain threshold),</li>
<li><em>the number of production deploys</em></li>
</ul>
<p>Those could give you a sense of the constant throughput of engineering team. If that number stagnates as you hire more, there might be a problem related to a new process in place, lack of investment on the infrastructure or a technical debt that needs to be addressed. However, if it increases too quickly you might have a quality issue. Don’t forget that measuring the speed of a team without evaluating the quality of the work is extremely dangerous.</p>
<h4 id="quality-confidence-in-the-code-base">Quality (confidence in the code base)</h4>
<p>As a team, we should aim for a good balance between speed and quality. Aiming at 100% test coverage and perfect APIs, data models and documentation isn’t quite rational when we need to also ship at a decent velocity. However, regressions should be exceptional, churn in our code base should be reduced to a minimum, new team members should quickly find their way in the code base and new experiments should be launched without fear of taking down the entire system. Quality isn’t a goal in an of itself, the confidence in being able to grow and change behaviors in a safe matter is what matters. Some of the metrics to consider:</p>
<ul>
<li><em>Test coverage ratio</em> (no need for 100% coverage but knowing where you stand helps a lot)</li>
<li>% of times a <em>pull requests breaking the build</em> or fail to pass the test suite</li>
<li>% of <em>merged vs rejected PRs</em></li>
<li><em>Number of comments by PR</em> (you don’t want a too low number but you also don’t want too high of number)</li>
<li>Number of <em>found bugs</em> (or bug fixes vs feature shipped)</li>
<li><em>“turbulence” churn/complexity ratio in the code base</em>. If the same code area keeps changing over time, it’s usually a symptom of a technical challenge such as a bad abstraction, poor implementation or a tech/product/business misalignment</li>
<li>How outdated are the dependencies used in your code base</li>
</ul>
<p>Technical debt is normal, quality is quite subjective but you can define as a team, a set of objective criteria that help give you a limited perspective on the quality of the team work. It will also help define technical values which are crucial as the team grows. Like velocity, measuring quality is super flawed, but remember that it’s also super important for engineering and for the rest of the company.</p>
<h4 id="organization-maturity">Organization maturity</h4>
<p>This is the part I was trying to avoid early on as a founder. You remember that dream of running a tiny, flat team of great engineers not needing much maintenance? It might be at the beginning but isn’t sustainable and we owe the team to mature the org as we grow the company. I don’t yet have a good set of metrics since that’s the area I’m still the least comfortable with but here are some ideas:</p>
<p><em>Hiring / retention</em></p>
<p>Do we have hiring goals? Salary brackets? A good hiring process, a good on-boarding process? How about voluntary and involuntary departures? Ideally, your people org should support you with that, but in some cases, you are growing the team before you have a people org in place (HR).</p>
<p><em>Ratio of managers per Individual Contributor (ICs)</em></p>
<p>This is a simple metric to start measuring: define a target goal of the number of ICs you want to report to a manager and keep measuring. Managers focus on IC growth, quality, retention, and watch for trouble spots in the process. If you have too many ICs per managers, those managers probably won’t be as effective and that decision might cost the org a lot in retention and happiness.</p>
<p><em>Responsibilities, expectations and performance evaluations</em></p>
<p>This is one of the things that most growing startups struggle with. It often requires experienced managers focusing on transitioning from a flat organization to clearly defined expectations and performance evaluation. It’s also a costly thing to do and it comes with serious consequences. However, if the individuals on the team don’t know what they are expected to achieve and when they fall short, they can’t perform at their best. Those expectations need to be clear to everyone else in the company. By the way, this is something that I wish I had done for myself much earlier. By not putting that in place for my own role, I failed to lead by example and I would have honestly done my job better with a properly communicated set of responsibilities and performance evaluation.</p>
<p><em>Collaboration and flexibility with the rest of the company</em></p>
<p>Engineering is part of the greater picture, if it only operates well within its org, then it is failing the company as a whole. Empathy, adaptability, and creativity when it comes to working with the rest of the growing organization is key to a successful company. It is true that very often, tech startups have a big focus on engineering but that doesn’t make us the center of the company. If we aren’t able to communicate and serve others, we aren’t playing our role in the success of the company. This is a big reason why all the engineering metrics we discussed above are so meaningful for the rest of the company. Building trust, collaboration and being flexible in the way we all work towards the same objective is what make things happen.</p>
<p><em>One on ones</em></p>
<p>One on ones are dedicated meetings between two people in the company. This is often an opportunity for a manager and an IC to dig deeper in a safe place about how to become more productive, happier or develop one’s career. It’s also a great way to get to know people, detect patterns and build empathy. One on ones should happen regularly and across disciplines. They don’t have to be formal 1:1s, sometimes they are scheduled lunches once a month or a monthly small group hangout to discuss how things are going.</p>
<p><em>Written communication, information organization</em></p>
<p>As the team grows, information can’t be solely shared orally, we need things written down to last and to be efficient. We also need to quickly have access to those things. How does one find access to the latest metrics, how about this weird piece of software that was written by this early stage employee and that very few people understand? How does one find out who’s on vacation and who’s on call? Where and how do I report a bug, how can I contribute a test or a bug fix? Those things are simple when you are 20 or less, they get way more complicated as you grow.</p>
<h3 id="conclusion">Conclusion</h3>
<p>This is a vast topic and I am only scratching the surface, but this is also the kind of information I wish I could send to myself a few years back. I was lacking a framework of measurement and was evaluating the growth of our org from a gut feeling perspective. As an engineer, I should have known that there was a much better way. Note also that not all those metrics need to be driven or improved at all stages. Once you have an evaluation framework in place it’s much easier to talk about where and how to focus our energy and to see the result of your investment. Having this framework in place and evaluating the results together, builds something extremely powerful: confidence. Self confidence and organization confidence is what drives healthy teams to success because they can face more complex problems.</p>
]]></content>
		</item>
		
		<item>
			<title>Research &amp; Development in a startup</title>
			<link>https://matt.aimonetti.net/posts/2017-07-research-development-in-a-startup/</link>
			<pubDate>Tue, 11 Jul 2017 07:41:02 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2017-07-research-development-in-a-startup/</guid>
			<description>I’ve seen and been in Research &amp;amp; Development (R&amp;amp;D) teams in the past. Sadly I can’t say any of these teams have been successful making a significant impact on the directions company they were serving took. R&amp;amp;D is often mentioned in the context of the military (in 2015, the US Army’s research, development, testing and evaluation (RDT&amp;amp;E), coupled with procurement accounts, made up 18 percent of the budget) or big companies such as Amazon, Google, Apple, Microsoft etc…</description>
			<content type="html"><![CDATA[<p>I’ve seen and been in Research &amp; Development (R&amp;D) teams in the past. Sadly I can’t say any of these teams have been successful making a significant impact on the directions company they were serving took. R&amp;D is often mentioned in the context of the military (in 2015, the US Army’s research, development, testing and evaluation (RDT&amp;E), coupled with procurement accounts, made up 18 percent of the budget) or big companies such as Amazon, Google, Apple, Microsoft etc…</p>
<p><img src="/posts/2017-07-research-development-in-a-startup/images/1." alt="image"></p>
<p>Source: <a href="https://www.bloomberg.com/view/articles/2016-08-09/amazon-and-google-change-the-r-d-race">https://www.bloomberg.com/view/articles/2016-08-09/amazon-and-google-change-the-r-d-race</a></p>
<p>But we rarely talk about R&amp;D at a startup stage. As a matter of fact, if you google those terms you will find a lot of articles about R&amp;D tax credits and deductions but little about how other startups tackled setting up a R&amp;D team. As Splice CTO, I believe we reached the stage where it’s important to look ahead and start planning in advance instead of being purely responsive. But how can you plan if you can’t see 6 to 12 months ahead. If your product team (engineers, designers, PMs) are in good hands and executing quarterly objectives in a healthy manner, you probably should consider doing some R&amp;D. I previously talked about why hiring a VP of engineering is crucial and how I (as the CTO) am delegating the day to day operations. This is critical since without that, I couldn’t even consider thinking ahead.</p>
<h3 id="what-i-want-to-avoid">What I want to avoid</h3>
<p>I have been on both sides of the R&amp;D line, I know how frustrating it can be to receive a half done concept project that I’m in charge of shipping and maintaining ASAP. I also know how frustrating it feels to work on great research and realize it will never ship because the R&amp;D team is so disconnected from the engineering or business team. Too often R&amp;D teams end up being a group of misfits lead by someone who likes to tinker with new cool stuff and think they can recreate the genesis of the company in a vacuum. Often those people are seen are “smart” and left alone because “we don’t want to lose them” and who knows, maybe they will come up with something amazing? Another common situation is that the company has a special task force that tackles special projects they have to ship outside of the normal dev cycle. Those situations aren’t healthy, they create tension within the teams and put pressure on processes.</p>
<p>I really believe that R&amp;D should be designed to be an integral part of the company and not as a special island where cool projects are being developed. I also think it’s important for engineers and designers to get room to explore different possibilities without relying on a team that did all the design for them. It is important to keep the team motivated but also to help them grow.</p>
<h3 id="setting-goals-and-scope">Setting goals and scope</h3>
<p>Settings goals for a team is a great way to define expectations and making sure we are aligned on why we work a certain way and what we are doing. Let’s first start by breaking down what I hope R&amp;D will accomplish:</p>
<ul>
<li>Explore technical &amp; business opportunities</li>
<li>Evaluate feasibility</li>
<li>Evaluate technologies</li>
</ul>
<p>The big question is how do we do that, especially in a software company that believes in small iterations and agile planning? And how do we leave room for the engineering team to discover adequate solutions on their own.</p>
<h3 id="operating-timeline">Operating timeline</h3>
<p>Now that we have goals we need to understand where the team will operate. By that I mean what part of the company timeline should the team focus on. The way I see it, here is how I break down a yearly timeline:</p>
<p><img src="/posts/2017-07-research-development-in-a-startup/images/2.png" alt="image"></p>
<ol>
<li>
<p><strong>Current quarter</strong>: clear roadmap to execute on to well defined objectives coming from the executive team. This is the main focus of the VP of engineering and Product. R&amp;D is not involved.</p>
</li>
<li>
<p><strong>Next quarter</strong>: in planning, execs have rough business goals that need to be converted into objectives and metrics. Discuss strategic approaches to get there with VP of product and VP of engineering leading the concretization of the roadmap. R&amp;D to advise if needed, potentially researching something that comes up and that can’t be handled by the “execution team” (more on that later).</p>
</li>
<li>
<p><strong>6 months from now</strong>: R&amp;D to explore opportunities &amp; feasibility to help shape future objectives and strategies. R&amp;D team’s main focus.</p>
</li>
</ol>
<h3 id="execution-and-rampd-teams">Execution and R&amp;D teams</h3>
<p>Let’s talk about the execution team in comparison to the R&amp;D team. The execution team is the team in charge of shipping, it’s the frontline team that focuses on this quarter. That team’s primary objective is to deliver solutions to the problems the exec team decided we wanted to tackle this quarter. This is not a team made of “janitors” (term I heard from a manager in a previous company), it’s also not a team of “contractors” that go down a list of stories pre-defined for them. It’s a team made of awesome people who understand our products, necessary compromises, value delivery and see the rubber hit the road on a daily basis. This is the team constantly building and shipping.</p>
<p>In comparison, the R&amp;D team doesn’t ship, or at least not to users. This service team is there to explore very hypothetical or deeply complex questions. Their output is what feeds into the decision making that helps us as a company to pick the problems we want to tackle next quarter or the one after. They help the other teams understand our potential needs for planning, staffing or strategic decisions such as acquisitions. This is not a team of crazy scientists working on whatever might be cool one day. This is a team exploring questions that might get closer to our North Star faster. This is a team that is technical, product and business oriented since they serve those departments. This is a team that always give partial answers to difficult questions so others can use to decide if a problem is worth tackling and when.</p>
<h3 id="scoping">Scoping</h3>
<p>Some level of research should happens at almost all levels. Very rarely do we have exact answers to questions without spending some time researching/discussing options. Both the execution and the research teams should have room to do that. To help us with terms let’s talk about discovery vs research.</p>
<p><strong>Discovery</strong>: is becoming aware of the solution to a well scoped, measurable problem. Discovery is generally short (from a day to a week) and ready to implement almost right away. One way to think about it is that we know a solution is right there, but we need to make sure we discover it.</p>
<p><strong>Research</strong>: as per the dictionary definition: “the systematic investigation into and study of materials and sources in order to establish facts and reach new conclusions.” In other words, the gathering and establishments of facts that help us make educated decisions.</p>
<p>The execution team needs discovery time, they are given problems to tackle and have a lot of context but sometimes need room to explore and find the right approach to a specific problem we are about to tackle.</p>
<p>The R&amp;D team is working on longer term research projects, with a less concrete output and lots of throw away work to be able to extract facts and reach new conclusions.</p>
<h3 id="output">Output</h3>
<p>So what should be the output of the R&amp;D team. We talked about extracting facts and reaching new conclusions, but what does that mean?</p>
<ul>
<li>The R&amp;D team doesn’t ship code to production. At best the team output might live in a sandbox or as libraries.</li>
<li>The R&amp;D team doesn’t hand out half-way done projects for engineering &amp; product to finish.</li>
<li>The R&amp;D team provides engineers, PMs and designers with documented research, prototypes and at times suggestions.</li>
</ul>
<p>In other words, lots of research documentation that can be leveraged by the executive and execution teams as well as libraries, throw away prototypes and flows.</p>
<h3 id="misc">Misc</h3>
<ul>
<li>The R&amp;D team isn’t solely technical</li>
<li>R&amp;D doesn’t handle maintenance and support of their research with the exception of libraries that weren’t explicitly given to another engineering team.</li>
<li>R&amp;D priorities and backlog are maintained by the CTO based on input from the exec team &amp; other team members.</li>
</ul>
<p>Research and development isn’t about software architecture/design or solely about technical feasibility and cost. It is about exploring business opportunities ahead of schedule to help the company make educated decisions to define our backlog.</p>
<h3 id="researching-and-developing-in-the-open">Researching and Developing in the open</h3>
<p>It’s crucial that R&amp;D doesn’t operate in a vacuum. The R&amp;D team is a service offered to the rest of the company. While the team doesn’t usually ship things to users, there is a lot of information that can be very valuable to a lot of employees. The work has to be done in the open and make easily available for any employee to dig into or ask questions.</p>
<p>Research documents are organized and made available on an employee-only site.</p>
<h3 id="stakeholders">Stakeholders</h3>
<p>While the CTO is running the day to day of R&amp;D, the team can be seen as an “oracle” with various people asking “what if” questions.</p>
<p>The questions should focus around two large themes:</p>
<ul>
<li>Business opportunities</li>
<li>Feature inquires</li>
</ul>
<p>Here is an example. Marketing is interesting in growing our Windows market since they think there is room for expansion in a specific vertical. They might word a question such as: “what if we wanted to make our service A more valuable to people using products from company B. What could be done to increase conversion of users of company B?”</p>
<p>The request should come with some sort of importance level but with the understanding that the priority of what is being worked on will be made transparent and negotiable at an exec level.</p>
<p>Feature requests are more specific and usually come from designers, PMs and engineers. We have a theory that doing something around X would really help our metrics Y. What if we wanted to work on X, what are our options, what’s the feasibility and potential cost?</p>
<p>We are still at an early stage of settings up R&amp;D at Splice. There are still a lot of unknowns but by trying to define roles, expectations and scope, I believe we put all the odds on our side.</p>
]]></content>
		</item>
		
		<item>
			<title>My technical interview process</title>
			<link>https://matt.aimonetti.net/posts/2017-06-my-technical-interview-process/</link>
			<pubDate>Tue, 13 Jun 2017 15:55:46 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2017-06-my-technical-interview-process/</guid>
			<description>I don’t really do technical interviews anymore, I am lucky to be able to rely on a great VP of engineering and team that take care of the process. I still meet with the candidates but I do that more as a way for us to get to know each other and to answer their questions from both a CTO and founder.
I took some time to write down my thought process when interviewing candidates.</description>
			<content type="html"><![CDATA[<p>I don’t really do technical interviews anymore, I am lucky to be able to rely on a great VP of engineering and team that take care of the process. I still meet with the candidates but I do that more as a way for us to get to know each other and to answer their questions from both a CTO and founder.</p>
<p>I took some time to write down my thought process when interviewing candidates. Of course, the process changes based on the candidate, position and how the interview goes, but this is a decent albeit generic break down of how I’m approaching the experience. You should also take a look at <a href="https://github.com/catehstn/interview-prep/blob/master/README.md">this great document</a> talking about how to prepare to interview technical candidates. This was a good exercise for me, forcing me to be explicit about my thought process during the short amount of time I meet with a candidate. It was also a great way to share with the team the kind of expectations I have about interviews.</p>
<h3 id="initial-technical-question">Initial technical question</h3>
<blockquote>
<p>Please describe the lifecycle of a web request going from the browser back to the browser.</p>
</blockquote>
<p><strong>Expect</strong> the candidate to understand what a web request is, the concepts of DNS, ips, web server/app dispatch. Often candidates with less experience see the web app as a black box and can’t really explain routing and template/response rendering as well as returned responses.</p>
<p><strong>Pay attention</strong> to the level at which the candidate starts, based on that, ask them to go deeper or shallower and see how comfortable they can explain technical concepts. Don’t try to trick them, but listen to the vocabulary they use as well as their comfort level. Do they go in the nitty gritty details of what happens inside the trackpad when pressure is detected or do they skip entirely the request processing when it hits an application server.</p>
<h3 id="follow-up-technical-question">Follow up technical question</h3>
<blockquote>
<p>Let’s pretend our web app is now getting a lot of traffic, how can we handle more loads, ideally without increasing cost?</p>
</blockquote>
<p><strong>Expect</strong> the candidate to **** understand the concepts of caching and load balancing.</p>
<p>Make sure to bring up HTTP caching and make them explain how it works, if they worked with it, dig a little around status codes etc.. Bonus points if they understand and can explain pro/cons of HTTP/2. If they bring up technologies such as memcached, varnish, squid or other caching solutions, ask them about pros/cons.</p>
<p><strong>Pay attention</strong> to how they react when they get to a place they don’t know. For instance don’t hesitate to ask about HTTP/2 push and how the headers are different than HTTP 1.1 or if they know that, ask about DNS load balancing or whatever they might not know. Check if the candidate is defensive or interested in learning during the interview. Do they feel bad or curious. Don’t push too hard but get a sense of how you might interact with them when they are faced to something they don’t know yet. After all, the goal is for the candidate to become your coworker.</p>
<h3 id="getting-a-glimpse-of-the-candidate-technical-world-view">Getting a glimpse of the candidate technical world view</h3>
<blockquote>
<p>What’s the hardest technical problem you ever solved? Why was it so hard, what did you learn?</p>
</blockquote>
<p><strong>No specific expectations</strong>, listen and try to understand how the candidate shares a hard moment and talk about something you have little context about. As a few questions to see how they respond to you digging a little in a potentially hard memory. Imagine you are sitting with this candidate in a post-mortem. Is their answer helping the team move forward?</p>
<p><strong>Pay attention</strong> to see if they bring up a hard technical problem or a difficult to debug situation. Can they explain in depth what the problem was, did they learn anything? Think about the role you are hiring for and how you’d be expected to answer the same question.</p>
<h3 id="getting-a-glimpse-of-the-candidate-generic-world-view">Getting a glimpse of the candidate generic world view</h3>
<blockquote>
<p>What’s the hardest non-technical problem you ever solved that you’d be comfortable sharing?</p>
</blockquote>
<p><strong>No specific expectations</strong>, listen to the problem the candidate is bringing up to your attention. Do they over communicate or under communicate. Do they pick a problem that is easy to talk about or a problem that is unique? Be sensitive that the candidate might not want to share and that’s totally ok. In that case, diffuse by asking how they dealt with the first time they got stuck learning programming. Make sure the candidate understands that this isn’t about any kind of personal problems, but more of a generic non-technical situation and how the solution was debugged/solved.</p>
<p><strong>Pay attention</strong> to the maturity of the candidate. Do they have an optimistic or a pessimistic worldview, do they spend more time talking about the problem or the solution. Are they humble or show offs?</p>
<h3 id="cocky-candidate-special-question">Cocky candidate special question</h3>
<p>Come up with a question that you don’t expect the candidate to know the answer. Maybe something not related to tech such as the mother sauces, the capital of Mali or the country of Georgia.</p>
<p><strong>Expectation</strong> here is to ask a question that confuses the candidate because it’s poorly asked and not on topic (about food, geography, anything not technology). An arrogant candidate will probably make things up instead of admitting they don’t know. A humble candidate will admit they don’t understand or are surprised by the question, or even better they might admit they don’t know the answer. Don’t aim to make the candidate feel bad, just find a way to get passed their attitude. Be supportive.</p>
<p><strong>Pay attention</strong> to see if the candidate is asking for an answer or wait for you to move on. If the candidate doesn’t ask for the answer, volunteer the answer so they can see it was a bit of a trick question.</p>
<h3 id="shy-candidate-special-question">Shy candidate special question</h3>
<blockquote>
<p>Besides programming, do you have any passions? Maybe sport, music, craft, TV/movies, games? Can you please share your passion with me?</p>
</blockquote>
<p><strong>Expected behavior</strong> is that the shy candidate should be able to find a way to communicate why and how they consume their passion.</p>
<p><strong>Pay attention</strong> to not cutting them off, spend more time listening. Ask questions if they seem to be stuck. Make sure they see you are interested in what they are sharing.</p>
<h3 id="going-deeper-on-the-technical-level-of-the-candidate">Going deeper on the technical level of the candidate</h3>
<p>I like to take concrete examples of problems we actually encountered. Depending on the position we are hiring for, I pick a different problem we already solved and present the situation to the candidate and ask them to talk it through with me.</p>
<p>It’s important to note that I ask our candidates to do a technical exercise on their own as a first step. The exercise is meant as base to discuss technical topics and approaches, not to really evaluate the solution provided by the candidate. So at this point of the interview, I should have amore or less good understanding of their skillset. That said, sometimes a candidate can totally miss the point of the exercise or just have had a bad day. That’s why I have this optional step to see how deep they can go while being comfortable and where their safe technical zone is at.</p>
<h3 id="conclusion">Conclusion</h3>
<p>There aren’t any magical recipes for a good technical interview. As an interviewer, you should certainly be well prepared and your team and you must have defined the kind of profile you are interested in hiring for. Too often, the interviewer is looking for a candidate matching their interests and values. They are looking for a clone and that’s usually a bad idea. Sharing the same philosophy around how to tackle technical problems is critical but you also want diverse skillsets and perspectives. Having a discussion with your team about why you think the candidate will do well and what kind of assistance they will need should also really help you make a decision quickly.</p>
]]></content>
		</item>
		
		<item>
			<title>CTO bet: future of Splice desktop apps</title>
			<link>https://matt.aimonetti.net/posts/2017-06-cto-bet-future-of-splice-desktop-apps/</link>
			<pubDate>Tue, 06 Jun 2017 16:26:14 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2017-06-cto-bet-future-of-splice-desktop-apps/</guid>
			<description>The primary job of a CTO is to leverage technology to empower the business and the team. Sometimes that means making boring but safe choices, sometimes that means more risky or controversial choices. I am starting a new series to discuss some of the bets we are making at Splice and the thinking behind those choices.
Realizing that some of our company’s early assumptions around our user base might have been a bit off, we adopted a slightly unconventional technical approach to our desktop applications.</description>
			<content type="html"><![CDATA[<p>The primary job of a CTO is to leverage technology to empower the business and the team. Sometimes that means making boring but safe choices, sometimes that means more risky or controversial choices. I am starting a new series to discuss some of the bets we are making at Splice and the thinking behind those choices.</p>
<p>Realizing that some of our company’s early assumptions around our user base might have been a bit off, we adopted a slightly unconventional technical approach to our desktop applications.</p>
<p>Splice is the advocate, companion of the modern musician. We developed a creation hub that connects the musician workstation with the cloud meaning that we sit close by the musician as she goes through her creation process. We opted early on for a transparent, discreet, independent integration meaning that we have an app running in the background handling various events and presenting a UI only when needed (similar to Dropbox). More complex experiences were designed to happen on the web requiring the user to have a browser open. Long story short, Splice is amazingly successful but modern musicians feel that the browser is often too far away from their creation space, and it’s a source of distraction. We have native apps written in Objective-C and C# (Mac and Windows). Keeping them in sync, implementing rich UIs and QA testing have been challenging. The quality of the user interactions and limited feature set have prevented our users from fully benefiting from what we have to offer. After some research, an investigation period and lots of discussions we opted to go with a unified stack:</p>
<ul>
<li><strong>GUI</strong>: <a href="https://www.chromium.org/Home">Chromium</a> wrapper (<a href="https://electron.atom.io/">GitHub’s Electron</a>)</li>
<li><strong>Local UI/UX</strong>: <a href="https://www.typescriptlang.org/">TypeScript</a> + <a href="https://angular.io/">Angular</a> (currently v4)</li>
<li><strong>Business logic / network / audio</strong>: <a href="https://golang.org/">Go</a></li>
</ul>
<p>This stack is the same on Windows and Mac. We currently still have some legacy native code but we are quickly phasing it out. More on that below.</p>
<h3 id="tldr-summary">TL;DR summary</h3>
<p>We are moving away from native code and switching to Go + local web based views. Here is why:</p>
<ol>
<li>Simplify: Maintaining &amp; keeping in sync 2 desktop code bases is seriously complicated, painful &amp; expensive.</li>
<li>Empower: Unifying the technical stack allows the entire team to contribute &amp; innovate.</li>
<li>Enable: the new stack allows us to more easily/faster build new features in a cross platform fashion, using cutting edge technology while still having access to native APIs.</li>
<li>Acceptable overhead: while there is certainly a RAM overhead, it can and should be minimized.</li>
</ol>
<p>This decision is slightly controversial because of two things, the choice of using Electron and the fact that we don’t stay in the JavaScript world and instead bring in Go.</p>
<h3 id="electron-is-controversial">Electron is controversial</h3>
<p>Electron often attracts bad comments on Hacker News and it is associated with very large RAM usage. The Slack app being the usual cited example. The issue here is more complex than it looks. Electron is a wrapper around Chromium which is the heart of the Chrome browser. In other words, the application renders a web view as its main view. Web views aren’t by default as optimized as native GUI code and that often means a great RAM cost than purely native UIs. Besides that, Chromium itself loads its fair share of code in memory. The raw cost of an Electron window is around 40MBs vs ~4MBs for a native UI. Not great… but how much RAM do you have on your computer? Do you realize that Chrome allocates around the same amount of RAM when you open a new empty Chrome tab? That’s not an excuse for the memory overhead but it helped me put some context around the cost of the raw overhead.</p>
<h3 id="the-slack-app-problem">The Slack app problem</h3>
<p>People complaining about Electron RAM usage usually refer to apps like Slack using 1GB or more. This is often due to a couple issues: the architecture of the app and the way the frontend is coded.</p>
<p>During the investigation phase, I realized that it was best to avoid using <a href="https://nodejs.org/en/">node.js</a> modules, especially native modules. Those were hard to work with (odd behaviors at times, hard to debug, hard to test) and often memory heavy. The second part is the UI cost, load a web app in your browser and look at the memory usage go through the roof as you load pics, gifs, sounds and lots of data. Some apps are better than others and <a href="https://code.visualstudio.com/">VSCode</a> is a good example of an Electron based app with a very reasonable memory footprint. That said it is very true that most frontend developers don’t benchmark or track the memory usage of their apps.</p>
<p>So yes, an app that has a browser based UI will require a bit more ram but it should be reasonable if we expect people to have decently modern machines. Also, this quote from my colleague after I complained about how much RAM Chromium uses, made me smile:</p>
<blockquote>
<p>RAM is meant to be used, stop being cheap trying to keep all of it free - Loren to Matt</p>
</blockquote>
<p>He has a good point, but of course you don’t want to swap either and you don’t want apps you aren’t actively using to squat most of your RAM.</p>
<h3 id="web-frontend-empower-the-team-share-knowledge">Web frontend: empower the team, share knowledge</h3>
<p><img src="/posts/2017-06-06_cto-bet-future-of-splice-desktop-apps/images/1.png" alt="image"></p>
<p>Chromium</p>
<p>So on the cons side we saw that there is a bit of a RAM usage increase but what about the advantages of using a web based GUI?</p>
<p>The main advantage was obviously only developing the user interface once and reuse it everywhere. But it goes further than that. This decision also empowers a bigger part of the team: all our frontend developers can become desktop application developers. They certainly need to understand the difference between web and local (technical and behaviors) but they don’t need to learn <a href="https://en.wikipedia.org/wiki/Cocoa_%28API%29">Cocoa</a> or <a href="https://en.wikipedia.org/wiki/Windows_Presentation_Foundation">WPF</a>. Also modern web APIs such as a <a href="https://www.w3.org/TR/webmidi/">Web MIDI</a> and <a href="https://www.w3.org/community/web-bluetooth/">Web Bluetooth</a> are available via a cross-platform API in Chromium if we decide to go that way. Adding new UI features is now much faster than it used to be (even for our talented engineers).</p>
<h3 id="web-framework">Web framework</h3>
<p><img src="/posts/2017-06-06_cto-bet-future-of-splice-desktop-apps/images/2.png" alt="image"></p>
<p>Because we already use <a href="https://angular.io">Angular</a> on the web, we decided to also use Angular for the GUI. Our team is familiar with the idioms, patterns, challenges and in theory elements can be shared. But what’s even more interesting to me is that a frontend developer who’s used to working on the web should be able to jump in on the desktop and feel at home. This consistency is very nice allowing us more flexibility and knowledge sharing. As a side note, we aren’t serving the application from the web, resources are available locally but we will probably start using service workers in the future.</p>
<h3 id="separation-of-concerns">Separation of concerns</h3>
<p>Another interesting aspect of our approach is that our logic doesn’t live in Electron, it is common for applications to implement the logic so it runs in the N<a href="https://nodejs.org/en/">ode.js</a> process. We opted to not do that and instead are running a Go + native code process. The frontend and the “core” service communicate via <a href="https://www.grpc.io/">gRPC</a>. This design decision ensures that the separation of concerns is really enforced. In other words, we are implementing the same architecture we know very well and use everywhere else: client/server. The difference is that the GUI doesn’t talk to the web APIs but instead to a local server (which proxies some calls when needed and handles online/offline states). While that might sound like an over-engineered decision, we are planning on having other applications consume our services and having a local API is a huge win. We consider the app GUI one of the potential clients in an non-exclusive relationship. We can imagine that tomorrow, other applications, plugins or Digital Audio Workstations would want to communicate with our service in a standard, documented and cross platform interface. This separation of concern and design consideration would allow for that.</p>
<h3 id="unified-code-base-using-go">Unified code base using Go</h3>
<p><img src="/posts/2017-06-06_cto-bet-future-of-splice-desktop-apps/images/3.png" alt="image"></p>
<p>We invested many years in the native applications and some of the details were implemented as we found out edge issues around advanced features. Porting that code to Go isn’t trivial and we didn’t want to block on the port to ship the code. That’s why we still have an hybrid “core” architecture with native + Go code:</p>
<p><img src="/posts/2017-06-06_cto-bet-future-of-splice-desktop-apps/images/4." alt="image"></p>
<p>Connecting Go to original native code allows us to rewrite components in pieces and gRPC allows us to not break the contract between the UI/frontend and the core/backend. We are going to rewrite piece by piece until there is no more native code left. It’s also decently trivial to have Go communicate with native code so we can also still reach out to OS level features if really needed.</p>
<p>To us, gRPC is the most effective way to send data across boundaries, it is comparable to Websockets but with better tooling. gRPC has other advantages that I might cover them in a future post. The short version is that while it is a bit cumbersome at times, it’s be reliable and ensures a thought through API.</p>
<p>The heavy lifting remains in Go and was ported from native code. Go’s simplicity, native concurrency and testability gave us more confidence, reduce the amount of bugs and is empowering the entire backend team to join the fun. Go’s rich ecosystem also gives us access to a lot of interesting libraries for future features. Obj-C, Swift and C# are great languages but they aren’t part of our main languages. I did consider using C#/<a href="https://www.xamarin.com/platform">Xamarin</a> to create a single cross platform app. But we would have needed a specialized and isolated team and we wouldn’t be able to leverage as much of our knowledge and team expertise.</p>
<h3 id="conclusion">Conclusion</h3>
<p>My bet is that bringing the well known cloud architecture to the desktop is the right move for our company. There is a slight memory overhead but I think that by paying extra attention to it and with the help of other community members we are going to keep that to a very minimum. After evaluating the cost, I prefer to pay that short term penalty but have a solid architecture to build upon. I also really think that empowering the team and unifying the tech stack is going to make a big difference. We already saw that when we were able to “surge” UI development. Finally, the design bet is on more than a simple port but a redefinition of what a desktop will become. Having a powerful cross-platform service written in a modern language opens the door to a lot of opportunities.</p>
<p>Shameless plug: If that’s a challenge you’re interested in working on, our team would love to chat with you.</p>
]]></content>
		</item>
		
		<item>
			<title>Should a CTO keep on coding?</title>
			<link>https://matt.aimonetti.net/posts/2017-04-should-a-cto-keep-on-coding/</link>
			<pubDate>Wed, 12 Apr 2017 15:37:51 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2017-04-should-a-cto-keep-on-coding/</guid>
			<description>I’ve always been fascinated by systems, the way they work, the way you can put them apart and build them back up. Part of this fascination is my insatiable desire to always be learning but also a challenge I like I give myself: can we do better? This fascination is what drove me most of my career. But my focus has usually be on the technology side, not really the human side.</description>
			<content type="html"><![CDATA[<p>I’ve always been fascinated by systems, the way they work, the way you can put them apart and build them back up. Part of this fascination is my insatiable desire to always be learning but also a challenge I like I give myself: can we do better? This fascination is what drove me most of my career. But my focus has usually be on the technology side, not really the human side. As human beings, we are full of feelings and uncertainties, you can’t apply a binary vision to the people around you, which results in people being harder to manage than technology. I knew that becoming a founder and growing a team meant that I would have to face some very interesting challenges. One of them being how do I transition from one role to the other within my own company.</p>
<p>When you start as a technical founder, you are really a developer, quickly becoming a team lead. The team lead does leadership things but still codes and does very little management tasks. Then depending on how the company grows, usually you become a manager and now you have very little time to code. I tried to do both coding and management for a little while and I quickly realized I wasn’t doing the team or the company a favor. That’s why I opted to hire a great technical manager and focused on my <a href="https://medium.com/@mattetti/wtf-is-a-cto-24b9ad4d6e50">CTO role</a>.</p>
<blockquote>
<p><strong>“My role is to make sure we are making the right business decisions and we have a plan on how to implement them”.</strong>— Me, in <a href="https://medium.com/@mattetti/wtf-is-a-cto-24b9ad4d6e50">this blog post</a></p>
</blockquote>
<p>If my job is to identify technical opportunities, make and/or support business decisions, should I still code? If I do, is it because I like it or because I need to? Should all CTOs continue or stop to code? If I keep on coding, what should I be coding, how do I relate to the rest of the company?</p>
<p>The answers to those questions greatly depends on the business you are in and the kind of decisions that need to be made and the stage of the company. I’ll go even further and say that it probably also depends on the kind of CTO you are. But at the end of the day, you should look at this quote from <a href="https://medium.com/@skamille">Camille Fournier</a> and decide if coding is helping you with that or not:</p>
<blockquote>
<p><strong>“No matter what, the CTO must understand where the biggest technical opportunities and risks for the business are and focus on capitalizing on them.”</strong><em>— Camille Fournier,</em> <a href="https://amzn.to/2nEGTQN"><em>The manager’s path</em></a></p>
</blockquote>
<p>If you keep on coding, you should never stand on the critical path. Your code output shouldn’t be as important as your leadership role. Your coding should only be there to help you make the right business decisions. Hopefully you can delegate most of the coding, but in some cases, that’s not feasible or recommended. Let’s take a quick look at why you might still be coding as a CTO:</p>
<p><strong><em>My team is too small</em></strong></p>
<p>You are probably a technical cofounder or you were given a CTO title to make you feel good. Your job is to build the right foundation for your company and help make the right business decisions so you can grow the team. By the way, you probably should start looking for a good team lead and maybe a good manager for your team.</p>
<p><strong><em>I am the expert</em></strong></p>
<p>Time to share the knowledge or hire other experts. You are a single point of failure, that’s dangerous! (Note: that’s the situation I’m trying to get out of, I have a lot to say about this)</p>
<p><strong><em>I do a better job and deliver faster than the rest of the team</em></strong></p>
<p>Maybe you didn’t hire the right people and should correct that. Or maybe you don’t have the right process in place yet, or finally, maybe you aren’t doing the rest of your job well and should focus on that. (Other option: you need an ego check)</p>
<p><strong><em>I feel guilty to let the team struggle, they have so much on their plate</em></strong></p>
<p>If they have too much on their plate, maybe the workload isn’t adequate for the team size. It’s your job to help define the business objectives and have a plan in place to execute. If the team needs your help with code, the planning wasn’t done right. It might happen from time to time but it should be really exceptional.</p>
<p><strong><em>I need to prove to the company (or myself) that I still “got it”</em></strong></p>
<p>That’s an obvious one, but more common than you think. Especially when you have a very strong engineer becoming a CTO. As engineers we value ourselves based on their capacities at designing solutions and all a sudden their actual coding abilities aren’t needed. Jordan Hubbard once told me that key to be a happy great engineer manager when you’ve been a great developer is to focus on helping others getting as good and even better than you.</p>
<p><strong>So if coding helps you figure out the biggest technical opportunities and risks for the business, keep doing it but don’t stay on the shipping critical path!</strong> Otherwise, you probably shouldn’t code much anymore.</p>
]]></content>
		</item>
		
		<item>
			<title>I found compassion &amp; hope… in prison</title>
			<link>https://matt.aimonetti.net/posts/2017-02-i-found-compassion-hope-in-prison/</link>
			<pubDate>Mon, 27 Feb 2017 15:53:04 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2017-02-i-found-compassion-hope-in-prison/</guid>
			<description>Last Thursday I took a day off and jumped on a bus headed to California City Correctional Center. I was part of a group of investors and entrepreneurs participating in a business pitch competition and graduation ceremony for aspiring entrepreneurs — who also happened to be incarcerated. These ninety-four men had worked for months, taking classes, preparing business plans, and polishing pitches as participants in Defy Ventures’ entrepreneurship training program for incarcerated people.</description>
			<content type="html"><![CDATA[<p>Last Thursday I took a day off and jumped on a bus headed to California City Correctional Center. I was part of a group of investors and entrepreneurs participating in a business pitch competition and graduation ceremony for aspiring entrepreneurs — who also happened to be incarcerated. These ninety-four men had worked for months, taking classes, preparing business plans, and polishing pitches as participants in <a href="https://defyventures.org/">Defy Ventures</a>’ entrepreneurship training program for incarcerated people.</p>
<p><a href="https://en.wikipedia.org/wiki/Gil_Scott-Heron">Gil Scott-Heron</a> — The Bottle</p>
<p>I have to admit I was a bit anxious at the beginning of this journey. I was worried it might turn out to be a “feel good field trip” for privileged tech scene members. I didn’t want to experience a show put on to make me feel as though I was giving back. I was concerned things would quickly turn into sensationalism and objectification of black and brown people. To be very frank, for a good part of the program, I was still very skeptical.</p>
<p>But then I realized that while the event was as perfectly orchestrated as a well-choreographed TV show (timed segments, queued up music, MC routines), the men in front of me, their emotions and their experiences were very real. It suddenly hit me, the reason everything was “staged” was to facilitate human connections in a very short amount of time. Both the Entrepreneurs in Training (EITs) and the volunteers had their own preconceived ideas, expectations and anxieties about engaging with each other, and every aspect of the event was designed to break down those barriers and facilitate deeper connections.</p>
<p>As I got to know these guys, I realized there was something very special about them. Something beyond the way they looked, beyond their criminal past, beyond the fact that they were making themselves vulnerable and allowed themselves to cry. All these men had something in common, something a <strong>lot of us have struggled to hold on to since November 8th, 2016: hope</strong>. Most of them aren’t getting out anytime soon, yet they had toiled for months refining very well thought out business plans. They organized their thoughts and ideas, prepared their pitches and learned them by heart, even with the knowledge that, for most of them, the ability to bring those plans to life is at best a distant dream.</p>
<p>It’s their deep sense of hope that makes me sure that even <a href="https://www.netflix.com/title/80091741">the messed up society</a> we are living in won’t be able to stop them once they are out. These men are able to see beyond racism, classism, biased and the unfair judiciary system. They are able to see beyond their sentences, their regrets, the pain they caused and their underdog status. What they see is so great it gives, them a glance at peace and happiness.</p>
<blockquote>
<p>“What else do you have if you don’t have hope?” — Michelle Obama</p>
</blockquote>
<p>These men acknowledge their crimes and the consequences they bear. But as a society, are we sending our parents, brothers, sisters, friends and loved ones to prison to be punished or rehabilitated? The reality is that those in charge of the judiciary system don’t send their own family, friends or loved ones to prison. When those being processed in the system don’t look like your friends or family, it is probably easier to see punishment as an appropriate solution.</p>
<p>Nonetheless, the men I met managed to find hope. To me, that was a shock. And my shock made me wonder if maybe deep down, I had given up on them before even entering the prison. What they taught me is that I have no right to lose hope because of the political climate and the anger of people around me. <strong>If they can defy the odds and are able to dream again, we all can.</strong></p>
<p>In a day in age when fear is being leveraged to drive wedges between us and fuel hate, I was also reminded of how <strong>hope naturally leads to compassion and kindness</strong>. The prison is segregated by ethnicity: black, latino, white and others inmates are isolated. Yet the graduating group was mixed, and they were truly supportive of each other. When we shared difficult memories, you could feel, hear and see the support of people around you. Hugs, pats on the back and handshakes were given in multitude and in a non-discriminatory way.</p>
<p>During the pitch competition, as participants were eliminated from round to round, <strong>not a single person complained or had a frown on his face</strong>. To the contrary, they all cheered for the EITs who made it to the next round. I’ve honestly never experienced that. Take a group of founders, VCs, and engineers and make them go through the same process. I can guarantee that you’d see quite a bit of drama, and not nearly as much empathy and support.</p>
<p>As the graduation event wrapped up, the family of an exceptional EIT named Timothy was told that he would be released that night. The other EITs cheered so hard for him, without envy or jealousy. They wanted him to start living his dream. They believed in his success, and he was their ambassador. I thought to myself, “<strong>these are the kinds of leaders we need — people who lead by example and inspire others</strong>.”</p>
<p>That night, when Timothy passed the prison gate, he was accompanied by his mom and a friend. He also carried with him the hope and selfless encouragement of his fellow EITs and Defy team.</p>
<p>—</p>
<p><em>Acknowledgments: I can’t recall the first person who introduced me to Defy but thank you! I’m grateful for having been a part of this experience. Thanks</em> <a href="https://defyventures.org/"><em>Defy Ventures staff</em></a><em>,</em> <a href="https://medium.com/u/946f534320f7"><em>Mark Suster</em></a> <em>and</em> <a href="https://upfront.com/"><em>Upfront Ventures</em></a> <em>for putting this event together. Thank you also to</em> <a href="https://twitter.com/laura"><em>Laura Gómez</em></a><em>, Heidy Vega,</em> <a href="https://medium.com/u/2153967fdb59"><em>Hamet Watt</em></a><em>,</em> <a href="https://twitter.com/laurazax"><em>Laura Zax</em></a> <em>and</em> <a href="https://medium.com/@buritica"><em>Juan Pablo Buriticá</em></a> <em>for their reviews and advice.</em></p>
]]></content>
		</item>
		
		<item>
			<title>When to a hire a VP of engineering</title>
			<link>https://matt.aimonetti.net/posts/2016-09-when-to-a-hire-a-vp-of-engineering/</link>
			<pubDate>Tue, 27 Sep 2016 17:29:48 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2016-09-when-to-a-hire-a-vp-of-engineering/</guid>
			<description>In my previous post, I discussed the challenges of growing the engineering team and defining the roles of a CTO vs VP of engineering. A common question that came up is: when is a good time to start looking for a VP of engineering. I am afraid that there isn’t a simple answer but more a mix of a few things:
 Personality &amp;amp; skills of the engineering lead Business needs Team size Company finances  Should you do the job or hire someone?</description>
			<content type="html"><![CDATA[<p>In my previous post, I discussed the challenges of growing the engineering team and <a href="/posts/2016-09-13_wtf-is-a-cto/">defining the roles of a CTO vs VP of engineering</a>. A common question that came up is: when is a good time to start looking for a VP of engineering. I am afraid that there isn’t a simple answer but more a mix of a few things:</p>
<ul>
<li>Personality &amp; skills of the engineering lead</li>
<li>Business needs</li>
<li>Team size</li>
<li>Company finances</li>
</ul>
<h3 id="should-you-do-the-job-or-hire-someone">Should you do the job or hire someone?</h3>
<p>Assuming you are currently the tech lead at your company (tech founder / CTO / lead engineer), you first need to take a honest look at what you are good at and what you want to do. Many founders aren’t best suited to be CTOs, they often are less driven by engineering design, architecture and long term business strategies but are more inclined to find “smart hacks” to get quick returns on small investments. This is a very useful skill when you start and aren’t quite sure where the company is heading. But this skill might not help you be the best CTO. Some other founders or early developers are amazing at selling their vision and getting people to join their cause. They convince very talented people to quit their cushy jobs to take a risk with them and they make sure everyone is both happy and produces amazing results. They create amazing teams and great cultures, great signs of potentially brilliant VP of engineers.</p>
<p>I was recently chatting with someone and was asking how they see the difference between a VP of eng. and a CTO and they were telling me that they currently lack experience so they should first be a VP and will then want to “climb up the career ladder” to become a CTO. That didn’t quite sound right to me, it would be like if someone would tell me they first needed to be a mobile software engineer before becoming a backend engineer. VPs and a CTOs are almost 2 separate tracks that require different skills. That’s why I think it’s very important to realize that it’s totally OK for founders or early engineers to hire CTOs (or CEOs for that matter) and take a VP of eng or tech lead role. But probably <strong>more importantly, it’s critical to know when you need help!</strong> Startups are intense and early employees and founders take on a lot of roles and while nobody likes to complain, saying you need help is not a sign of weakness, it shows strength and humbleness. If you know you need help, now is the time to hire! (or to reduce the team size)</p>
<h3 id="understand-your-business-needs-and-capacity">Understand your business needs and capacity</h3>
<p>The second important point is to understand the <strong>business needs</strong>. In startup land, you are often pushed to hire as many engineers as possible, as fast as possible. You look more credible when you say you have a team of 30 than when you say you have a team of 5 engineers. Founders (and VCs) want to prove they can hire and if they were to be acquired, they know that the team size factors in their company valuation. I personally find these arguments very silly, but I that’s unfortunately how many people think. Unless you are aiming for a acqui-hiring exit, I’d suggest to try to avoid falling in this trap. During the early phases of a startup, it’s the role of a CTO to define the real engineering needs and discuss with the other execs what kind of budget can be allocated to wages. We know that there will be some churn and therefore waste. If you can keep the overhead, low, you can run leaner and extend the runway. Furthermore, by having a lower head count, you can afford to pay your awesome engineers better (and recruit more experienced devs). I personally believe in running smaller team until you find the inflection point. For most startups, throwing more developers won’t make a huge difference since they first need to figure out their market fit. Focus on hitting those milestones and when you know that <strong>have to scale the team soon</strong>: then you will know it’s time to hire a VP of engineering. Don’t wait too long otherwise you are going to set your future VP for failure.</p>
<p>The company size is an interesting measure, as mentioned earlier, it’s often believed that the more the better. It gives you legitimacy. When you are well organized, have clear business goals, objectives and a clean code base, that’s usually true. But it also comes with a huge overhead. I approximate this overhead to represent around 10–15% of manager time per direct report. When you reach 6–10 engineers, it becomes a full time job (if you want to do it decently well). Certainly some teams can operate manager-free for longer than others but it comes at a different cost. My recommendation if you start seeing your team grow fast is to do one of the following:</p>
<ul>
<li>keep the engineering team small until you can hire a VP of engineering and properly scale the team</li>
<li>act as a vp of engineering and let someone else be the lead engineer/CTO</li>
</ul>
<p><strong>Once you start seeing great traction and revenue,</strong> which can be via direct revenue or investment, that’s when you should start actively looking for the person that will be your team’s quarterback. Note that the time to get to that point might vary greatly from company to company and that’s totally normal. The hard part is what makes startups hard: timing. You don’t want to hire a VP too early, but you also don’t want to wait too long and bringing someone to “save” a team that’s falling apart.</p>
<p>So to summarize, you need to define how you will fit in the picture, pick the right team size once you reach the critical inflection point take the time you need to find the right person to help improve your process while scaling the team and keeping everyone happy and productive.</p>
]]></content>
		</item>
		
		<item>
			<title>WTF is a CTO?</title>
			<link>https://matt.aimonetti.net/posts/2016-09-wtf-is-a-cto/</link>
			<pubDate>Tue, 13 Sep 2016 14:04:41 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2016-09-wtf-is-a-cto/</guid>
			<description>Over the last 3 years I built our startup taking on multiple roles, engineer + VP of engineering + CTO, I’m finally transitioning to being a full time CTO. Funny enough, I kind of always disliked the CTO title. This is probably because this is one of the most poorly defined titles out there. It doesn’t seem to mean anything, or maybe it just means a lot of different things to a lot of different people.</description>
			<content type="html"><![CDATA[<p>Over the last 3 years I built our startup taking on multiple roles, engineer + VP of engineering + CTO, I’m finally transitioning to being a full time CTO. Funny enough, I kind of always disliked the CTO title. This is probably because this is <em>one of the most poorly defined titles</em> out there. It doesn’t seem to mean anything, or maybe it just means a lot of different things to a lot of different people. It also changes based on the company’s development phase and the personality of the CTO. But instead of spending time complaining about how misused/abused the term is, let’s see how this change will affect <a href="https://splice.com">Splice</a> and I.</p>
<p><strong>Splice</strong> now has its <strong>first VP of engineering:</strong> <a href="https://twitter.com/buritica"><strong>Juan Pablo Buriticá</strong></a>. There is often a lot of confusion between the roles of a VP of engineering and a CTO. So let me clarify, for me, what the VP should focus on:</p>
<ul>
<li>people</li>
<li>now</li>
<li>deliverables
while the CTO should focus on:</li>
<li>technology</li>
<li>the future</li>
<li>enabling business opportunities</li>
</ul>
<h4 id="investing-in-a-people-architecture">Investing in a “people architecture”</h4>
<p>These two sides of an engineering organization have always been a challenge for me. I invested a lot in our technology architecture (and it paid off) but I knew that we needed to invest the same energy in our “people architecture” if we wanted to scale. Having a good design and foundation is critical to good software. If you don’t have that and your company becomes successful, you will need to do a rewrite. Doing full rewrites is a dangerous, slow, expensive and scary thing. The same rule applies to building an engineering team. I won’t name any but I am sure you’ve seen your share of startups that hired a bunch of smart people, tried to keep everything flat and realized it wasn’t working out. Deliverables &amp; morale went down, they had to rethink their entire organization… in other words, they had to do a full rewrite and it came at a huge cost.</p>
<h4 id="head-or-gutbruce-willis">“Head or gut?” — Bruce Willis</h4>
<p>Doing day-to-day work as well as going deep in technical solutions &amp; making long term technical decisions is really hard. These things are in constant conflicts. But at the beginning of a startup, you don’t have a choice and it comes at a cost that will directly affect one of these 2 areas: your technology or your people. Not a great choice is it? But it is the sad truth and the more people you add, the harder it gets. Which is one of the reasons I kept the team relatively small even if we had so much to do.</p>
<h4 id="being-an-enabler">Being an enabler</h4>
<p>Juan Pablo brings his technical and managerial expertise as well as his deep care for building up and supporting an amazing engineering team. With him on board I really feel that we can scale the team without putting more strain on each individual. But more than that, I feel that I wasn’t the manager I wanted to be and I didn’t have enough time to go deep on really hard technical problems that could be extremely beneficial to the company. Not being a great manager has always been one of my flaws and something I wanted to improve on. I never had great managers and I wanted to break the cycle. I’m told that part of being a leader means <strong>finding better people than you and empower them to do their job the best they can</strong>. I can’t be more thrilled to have Juan Pablo join us, scale and make our team and each individual member even better.</p>
<p>So Juan Pablo is going to take over the day-to-day: one on ones, backlog grooming, delivery process, ownership and accountability… These things honestly take a lot of my time, so with those gone, what’s left for me?</p>
<blockquote>
<p>My mission is to discover and be responsible for the implementation of technical solutions that move the needle</p>
</blockquote>
<h4 id="defining-my-role">Defining my role</h4>
<p>To me, my #1 role is to leverage technology to serve our business. That sounds really vague so let me try to clarify what I mean:
<em>My mission is to discover and be responsible for the implementation of technical solutions that move the needle at a company level</em>. But be warned, there is a big distinction between this and <a href="https://en.wikipedia.org/wiki/Research_and_development">R&amp;D</a>. In R&amp;D, you are trying things that <em>might</em> move the needle (and you aren’t usually responsible for implementing them) when as a CTO, I place bets that have to be closely related to business goals and deliver them in the short/medium term. My failures or successes have a direct effect on the company.</p>
<h4 id="its-all-about-business">It’s all about business</h4>
<p>Being a CTO is a strategic role, it’s not about picking the absolute best programming language, container solution or cloud vendor. It’s not even about evangelizing my engineering vision or reading hundreds of white papers to become the most knowledgeable engineer in the team, it’s about making the right business decisions. My role is not to “make it happen”, this is what a VP of engineering is responsible for. <strong>My role is to make sure we are making the right business decisions and we have a plan on how to implement them.</strong> My role is also to find new opportunities by leveraging technology. But I can’t do that without a great CEO, a great VP and a great team and lots of trust going around.</p>
<p>This is why it’s such a hard job, you have to be able to understand and appreciate things from a business and technical perspective. <strong>You have to deconstruct and reconstruct the technical challenges and solutions linked to each possibility and quickly evaluate the risk/reward factor of each.</strong> You often need to say no and explain in simple terms why you think the risk is probably too great. You have to have a great relationship with the CEO so these discussions don’t turn in continuous battles and you need to have a strong trust relationship with the VP of engineering so your decisions can be backed by the team and value can be delivered promptly.</p>
<p>On one hand, you are representing the technology and the engineers, fighting for low tech debts, exciting solutions and utopic technical perfection while on the other, you are representing the business with its objectives, revenue goals and market opportunities. <strong>As far as I’m concerned, the CTO role might the most schizophrenic C-suite position out there and I’m looking forward to continue exploring the essence of my role as Splice and I evolve.</strong></p>
<blockquote>
<p><strong>Note:</strong> There is another entire discussion about knowing when your company should split these roles. What are the signs, how did it go for Splice/me. Let me know if you’d be interested in a follow up post. — Update: <a href="/posts/2016-09-27_when-to-a-hire-a-vp-of-engineering/">I posted a follow up post regarding timing</a>.</p>
</blockquote>
]]></content>
		</item>
		
		<item>
			<title>Go is for everyone</title>
			<link>https://matt.aimonetti.net/posts/2016-07-go-is-for-everyone/</link>
			<pubDate>Tue, 19 Jul 2016 12:31:01 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2016-07-go-is-for-everyone/</guid>
			<description>Go is a modern programming language created at Google. It’s designed to be a very rational (read non-fancy), simple, and fast programming language. It’s quickly becoming one of the key new programming languages due to its familiarity, simplicity, scalability, performance, and approach to concurrency. It’s the common language of modern systems solutions (Docker, Kubernetes, CoreOS, Hashicorp…), many of small and big startups use Go for some of their web APIs and plenty of other things.</description>
			<content type="html"><![CDATA[<p><a href="https://golang.org/">Go</a> is a modern programming language created at Google. It’s designed to be a very rational (read non-fancy), simple, and fast programming language. It’s quickly becoming one of the key new programming languages due to its familiarity, simplicity, scalability, performance, and approach to concurrency. It’s the common language of modern systems solutions (<a href="https://www.docker.com/">Docker</a>, <a href="https://kubernetes.io/">Kubernetes</a>, <a href="https://coreos.com/">CoreOS</a>, <a href="https://www.hashicorp.com/">Hashicorp</a>…), many of small <a href="https://netflix.com">and</a> <a href="https://eng.uber.com/go-geofence/">big</a> <a href="https://blog.twitch.tv/gos-march-to-low-latency-gc-a6fa96f06eb7#.dzpuxtw4z">startups</a> use Go for some of their web APIs and plenty of other things. But this post isn’t about how awesome Go is, it’s about making it more accessible to developers with little to no experience.</p>
<h4 id="the-go-community-can-feel-out-of-reach">The Go community can feel out of reach</h4>
<p>Go was written and is developed by a group of very experienced people, in the context of a very mature tech company (Google). Because of that, the early community reflects its creators. Most are experienced developers, computer science focused and interested in specific technical problems. Compared to many other programming communities, our community can sometimes feel drier in the sense that we focus a lot on low level details and tooling and aren’t focusing much on carving out a path for newcomers.</p>
<h4 id="we-want-go-to-be-more-accessible">We want Go to be more accessible</h4>
<p>As a CTO and Co-Founder of a <a href="https://splice.com">tech startup</a>, I bet a lot on Go. It has been serving us great and to be honest, I love our community. But I have also heard many times that Go is an advanced language that is only for experienced developers. Or that the Go community is full of experts making it very hard for new developers to “break-in”. All communities need new people to challenge the “old-guard”, push new ideas and become tomorrow’s leaders. Without new members, communities end up aging, and eventually go away. We need to embrace new users and make sure we don’t leave less experienced developers high and dry due to minor things we didn’t think about.</p>
<h4 id="go-isnt-for-me-i-just-started-learning-how-to-code">Go isn’t for me, I just started learning how to code</h4>
<p>This is something I’ve heard many times. You have a new developer who’s just starting to discover the wonderful world of programming and they are being told they should start with JavaScript (JS), Ruby or Python because the other languages such as Go are too complicated for them and a novice can’t and should not try to learn an “advanced” language.</p>
<p>I couldn’t disagree more. Sure, with these languages you will get your first running code experience faster, but you may also struggle very quickly with other things such as syntax and other errors that are reported only when your code runs. You will discover behaviors considered weird because you don’t understand them (yet). I wrote about that <a href="https://splice.com/blog/golang-improved-simplicity-reduced-maintenance/">before and to me, this is similar to getting a credit line with bad terms</a>. I do think JS, Ruby, Python etc. are great languages and should be learned, but I think a lot of developers, if not all, would benefit greatly from learning Go first.</p>
<p>Go isn’t revolutionary in itself; it does have a few paradigms that are somewhat unique, but its syntax and concepts are very similar to most programming languages. As a matter of fact, if you know Go fairly well, you can probably learn Ruby, Java, Python, JS, C# decently quickly since you already have the mental mapping of all the core concepts. Because Go is a small language (the language itself has a limited set of features), most of these other languages have similar programming concepts as Go (except for concurrency) but add a few extra layers on top. One can therefore easily argue that learning Go is easier and can be used as a foundation to explore other languages. Go isn’t the solution to all problems and many developers learning Go will end up preferring to move on to frontend languages such as JS/TypeScript, some will prefer a more classical Object Oriented approach, some will want more flexibility in the type language, some won’t have a choice and will write the programming language used at their job. This is totally fine! But learn Go so you can have a solid foundation and then you can move on to something else you might like better or better suit your needs.</p>
<h4 id="not-enough-content-for-beginners">Not enough content for beginners</h4>
<p>It saddens me but it’s true: we have very little content for true beginners. Because our community was started by developers with a lot of experience, we created a lot of content for existing developers, not total newbies. On the other hand, communities such as Ruby and JS are larger and always had a big influx of totally new developers attracted by the promise of creating web applications quickly (at the cost of learning the fundamentals which sooner or later comes to bite you in the 🍑).</p>
<p>Swift came in as a replacement of Objective-C, but Apple and the community are doing an <a href="https://www.apple.com/swift/playgrounds/">amazing job</a> attracting new developers. Granted it’s a little bit easier for Apple to capture new developers since they are usually motivated to build something tangible as quickly as possible and Apple really wants revenue generating native apps on their platforms.</p>
<h4 id="improve-the-educational-materials-and-new-user-experience">Improve the educational materials and new user experience</h4>
<p>I don’t see any reasons why we can’t aim to do the same and be much much better at teaching the basics, sharing knowledge and welcoming new developers. After all, we brag that our language is simple; it’s time to show new developers that investing in Go early on is the right move for them. Let’s fix the gap in documentation and make onboarding exciting.</p>
<p>The great news is that we all started as newbies and we all learned something. If you’ve learned something, you should be able to explain it simply. Start writing small blog posts or give local talks on basic Go concepts. Maybe explain how to use the <em>printf</em> functions, how to <a href="https://go-talks.appspot.com/github.com/benbjohnson/structuring-applications-for-growth/main.slide">organize your code in packages</a>, or show how to use <em>godoc</em> or a feature of your favorite IDE. Our language is simple and the questions new developers are facing are finite; let’s make sure we create awesome content for new Gophers in the quest for knowledge!!</p>
<p><em>Thanks to</em> <a href="https://twitter.com/carlisia"><em>Carlisia Campos</em></a><em>,</em> <a href="https://twitter.com/tiffanyfayj"><em>Tiffany Jernigan</em></a><em>,</em> <a href="https://twitter.com/enneff"><em>Andrew Gerrand</em></a> <em>and</em> <a href="https://twitter.com/francesc"><em>Francesc Campoy Flores</em></a> <em>for reading drafts of this and providing feedback.</em></p>
]]></content>
		</item>
		
		<item>
			<title>dockercon 2016 keynote</title>
			<link>https://matt.aimonetti.net/posts/2016-06-dockercon-2016-keynote/</link>
			<pubDate>Mon, 27 Jun 2016 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2016-06-dockercon-2016-keynote/</guid>
			<description>I was invited to take part in this year&amp;rsquo;s Docker keynote to discuss how we use Docker at Splice and how our two companies share the same philosophy. I wrote a summary blog post of my talk. And you can read the official Docker blog post about the keynote
Video  </description>
			<content type="html"><![CDATA[<p>I was invited to take part in this year&rsquo;s Docker keynote to discuss how we use Docker at Splice
and how our two companies share the same philosophy. I wrote <a href="https://blog.docker.com/2016/06/docker-for-mac-splice/">a summary blog post</a> of my talk.
And you can read the official <a href="https://blog.docker.com/2016/06/dockercon-general-session-video/">Docker blog post about the keynote</a></p>
<h2 id="video">Video</h2>
<iframe width="720" height="480" src="https://www.youtube.com/embed/vE1iDPx6-Ok?start=2770" frameborder="0" allowfullscreen></iframe>
]]></content>
		</item>
		
		<item>
			<title>how to manage slack constant interruptions eod emails</title>
			<link>https://matt.aimonetti.net/posts/2016-01-how-to-manage-slack-constant-interruptions-eod-emails/</link>
			<pubDate>Mon, 18 Jan 2016 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2016-01-how-to-manage-slack-constant-interruptions-eod-emails/</guid>
			<description>Ever since I started Splice, I&amp;rsquo;ve been really eager to experiment and adapt our process to be able to be as efficient as possible while still pleasant. Setting up a process that works is hard because it depends on the size of your company, the team members and the leadership style. We tried many things as we grew and lots of these things didn&amp;rsquo;t stick, however a few did. One of those is our End of Day email aka EOD email.</description>
			<content type="html"><![CDATA[<p>Ever since I started <a href="https://splice.com">Splice</a>, I&rsquo;ve been really eager to experiment and adapt our process
to be able to be as efficient as possible while still pleasant.
Setting up a process that works is hard because it depends on the size of your company, the team members
and the leadership style. We tried many things as we grew and lots of these things
didn&rsquo;t stick, however a few did. One of those is our End of Day email aka EOD email.</p>
<p>In this <a href="https://splice.com/blog/managing-slack-interruptions/">blog post about team communication</a> at Splice,
I go into more details about synchronous vs asynchronous communication, the pros and cons and the process we explicitly defined.</p>
<p>I don&rsquo;t know other companies using the EOD email approach yet but unless you&rsquo;re a one man show, I can&rsquo;t think of a reason not to do it.
I also can&rsquo;t stress enough that you need be mindful of others focus when using communication tools such as <a href="https://slack.com/">Slack</a>.</p>
<p><a href="https://splice.com/blog/managing-slack-interruptions/"><img src="https://splice.com/blog/wp-content/uploads/2016/01/You_Waste_A_Lot_Of_Time_At_Work-298x300.png" alt="Interruptions" style="
    display: block;
    margin: auto;
"></a></p>
]]></content>
		</item>
		
		<item>
			<title>audio dsp demystified sampling</title>
			<link>https://matt.aimonetti.net/posts/2015-12-audio-dsp-demystified-sampling/</link>
			<pubDate>Tue, 15 Dec 2015 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2015-12-audio-dsp-demystified-sampling/</guid>
			<description>Through this post and the following ones, I will do my best to provide you with the basic knowledge you need to understand and implement digital audio signal processing. The idea came from a conversation with my friend Chad Fowler who&amp;rsquo;s a well-known software developer, leader but also a well accomplished musician. Chad was interested in learning the basics of DSP and I can only assume he doesn&amp;rsquo;t have time to 42 books on the topic, white papers, PHD thesis and try to decipher complex math equations.</description>
			<content type="html"><![CDATA[<p>Through this post and the following ones, I will do my best to provide you with the basic knowledge you need to
understand and implement digital audio signal processing.
The idea came from a conversation with my friend <a href="https://chadfowler.com/">Chad Fowler</a> who&rsquo;s a well-known software developer,
leader but also a well accomplished musician. Chad was interested in learning the basics of DSP and I can only
assume he doesn&rsquo;t have time to 42 books on the topic, white papers, PHD thesis and try to decipher complex math equations.
Most DSP code out there is written in C, Assembly or C++ due to the fact that latency is really problematic for real-time audio processing
applications (<a href="https://en.wikipedia.org/wiki/Field-programmable_gate_array">FPGAs</a> &amp; chipsets with DSP specific instructions are also used).
There are also a lot of great/old libraries already available for those languages.
But my goal here isn&rsquo;t to teach how to use existing libraries, but to teach how they work so you can implement your own or make educated choices.
I should note that I&rsquo;m not an expert in the matter, I have never implemented complex real-time DSP and this series is only meant
as an introduction to the topic.</p>
<p>TL;DR intro series teaching programmers the basic audio DSP concepts in a practical manner. No DSP knowledge is expected.</p>
<h2 id="analog-to-digital-conversion">Analog to Digital conversion</h2>
<p>To be able to access and manipulate audio data via our code, an audio signal needs to be converted from analog to digital.
This is not something you usually implement yourself, in most cases it is done at the sound card level. Sound cards do the job of converting the
signal, in other words, they are <a href="https://en.wikipedia.org/wiki/Analog-to-digital_converter">analog to digital converters (ADC)</a>.</p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/f/f0/ADC_Symbol.svg" alt="ADC"></p>
<p>It&rsquo;s very important to understand how the conversion is done because it has direct repercussions on what we will do.</p>
<p>We have a <a href="https://en.wikipedia.org/wiki/Continuous_signal">continuous signal</a> (the audio signal) and we need to convert it into numerical values.
The numerical values needs to represent the sampled analog signal as closely as possible.
To do that, a <a href="https://en.wikipedia.org/wiki/Discrete-time_signal">discrete signal</a> needs to be created. A discrete signal
is a fancy name for a time series representing the sampled signal. In other words, we measure the signal at a certain frequency
(let&rsquo;s say 44,100 times a second) and each value (an integer or a floating-point we call a sample) is added to our series. (This article assumes
we are using <a href="https://en.wikipedia.org/wiki/Pulse-code_modulation">PCM</a> representation).</p>
<p><img src="https://www.radio-electronics.com/info/rf-technology-design/digital-signal-processing/waveform_sampling.gif" alt="waveform sampling illustration from https://www.radio-electronics.com/info/rf-technology-design/digital-signal-processing/dsp-basics-tutorial.php"></p>
<h3 id="sampling-rate">Sampling rate</h3>
<p>The amount of time per second we take a sample from our analog signal is called the <a href="https://en.wikipedia.org/wiki/Sampling_(signal_processing)#Sampling_rate">sampling rate</a>.
Common audio sampling rates are 44.1kHz, 48kHz and sometimes 96kHz.</p>
<p>There is a very important explanation about why we need to sample at a value greater than 40kHz.</p>
<p>The human hearing range falls into a frequency range of 20Hz to 20,000 H (that said you probably don&rsquo;t hear very much above 17kHz).
A requirement for our analog to digital conversion is that we can capture and then later on recreate an analog signal that will cover
the entire frequency range we are interested in.</p>
<p>The reason we need to sample at a rate greater than 40kHz is due to the findings of <a href="https://en.wikipedia.org/wiki/Harry_Nyquist">Harry Nyquist</a>.
Nyquist, studied and wrote about <a href="https://en.wikipedia.org/wiki/Harry_Nyquist">conversion of continuous to discrete signals</a>.
One of the discoveries he made is called the <a href="https://en.wikipedia.org/wiki/Nyquist_rate">Nyquist rate</a> and simply put it says
that you need to sample at at a greater frequency than twice the bandwidth you want. Since we are trying to sample a range of 20,000Hz
we need to sample at <code>2x20000 = 40000</code> to cover the entire frequency range.</p>
<p>Fun fact, the default 44.1kHZ sampling rate comes Sony setting the standard by recording audio content on video equipment
and wanting to have a system that was PAL/NTSC compatible (PAL runs at 25fps, NTSC at 30fps). They were able to store
the exact same amount of 44,100 samples per seconds using different amounts of lines/frames.</p>
<h3 id="bit-rate">Bit rate</h3>
<p>The precision of the numerical value we use to store the sample is called the <a href="https://en.wikipedia.org/wiki/Audio_bit_depth">bit depth</a>.
The bit depth will change the range of values we capture, take for instance the sampling example below.</p>
<p><img src="https://upload.wikimedia.org/wikipedia/commons/b/bf/Pcm.svg" alt="4 bit sampling"></p>
<p>The analog signal in red is being sampled at a 4-bit bit depth meaning that each sample is represented by an integer taking 4 bits in memory.
4 bits give us a maximum range of 16 integer values <code>(4*4)</code> Our sample value will be between 0 and 15. 4-bit precision really isn&rsquo;t enough
to properly represent the reach dynamic range of audio signals.
Most audio content is sampled at 16 or 24 bit (8, 20 and 32 bit depths are also sometime used). A 16-bit integer resolution
offers a dynamic range of 96 dB (which can be improved using <a href="https://en.wikipedia.org/wiki/Dither">dithering</a> but that&rsquo;s outside of the scope of this article).</p>
<p>Too low of a resolution and you are missing auditive information (and getting extra noise), too high of a resolution and it&rsquo;s a waste.
32 floating-point bit depth is often used later on in the audio chain when doing complex audio processing.
This process allows for greater precision when
manipulating audio data and rounding can have a negative effect on the output (<a href="https://en.wikipedia.org/wiki/Digital_audio_workstation">DAWs</a>,
synthesizers, effects&hellip;).
The data is usually converted back to the source bit depth making things easier/transparent to the caller.</p>
<p>Fun fact: The famous TR-909 drum machine only used a bit depth of 6-bit!</p>
<p><img src="https://www.amazona.de/wp-content/uploads/2010/01/1_TR-909_Total.jpg" alt="TR-909"></p>
<h2 id="file-formats-wav--aiff">File formats: WAV &amp; AIFF</h2>
<p>Now that we learned how the audio signal is being converted to a digital stream, it&rsquo;s interesting to see how it&rsquo;s being stored.
The 2 main uncompressed <a href="https://en.wikipedia.org/wiki/Pulse-code_modulation">PCM</a> formats are <a href="https://en.wikipedia.org/wiki/WAV">WAV</a> and <a href="https://en.wikipedia.org/wiki/Audio_Interchange_File_Format">AIFF</a>.
These formats store the same data slightly differently and provides valuable information of the stream content via file headers and
data chunks. To be able to do any kind of offline processing, we need to be able to read and write such formats.
In a future post, we will write a coder/decoder that explains how these file formats work (and get a sneak peek into lossy compression formats such as MP3).</p>
]]></content>
		</item>
		
		<item>
			<title>dotgo applied concurrency in go</title>
			<link>https://matt.aimonetti.net/posts/2015-12-dotgo-applied-concurrency-in-go/</link>
			<pubDate>Wed, 02 Dec 2015 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2015-12-dotgo-applied-concurrency-in-go/</guid>
			<description>Back in November I was in Paris for dotGo, one of my favorite Golang conferences. I was invited to speak and wanted to share something concrete with the audience, something based on my experience with Go at Splice. Go is designed for simplicity with only one way of doing one thing. That makes preparing talks pretty challenging since a lot has already been said and there is not much more to add.</description>
			<content type="html"><![CDATA[<img src="https://farm6.staticflickr.com/5688/22350810834_20caad1e11_k_d.jpg" class="">
<p>Back in November I was in Paris for <a href="https://www.dotgo.eu/">dotGo</a>, one of my favorite Golang conferences.
I was invited to speak and wanted to share something concrete with the audience, something based on my
experience with <a href="https://golang.org">Go</a> at <a href="https://splice.com">Splice</a>. Go is designed for simplicity
with only one way of doing one thing. That makes preparing talks pretty challenging since a lot has already been said
and there is not much more to add. A lot of us pick Go because it&rsquo;s has concurrency built-in, but it doesn&rsquo;t mean that
writing efficient concurrent code is instinctive or obvious.</p>
<p>I walked the audience through the parallelization of code execution and all the mistakes we usually make.
Using an Arduino and a set of LEDs, I show how goroutines operate and how to write working Go code.</p>
<p><a href="https://www.thedotpost.com/2015/11/matt-aimonetti-applied-concurrency-in-go">Official post about the talk</a></p>
<h2 id="video">Video</h2>
<iframe width="720" height="480" src="https://www.youtube.com/embed/TI8OW22WZvQ" frameborder="0" allowfullscreen></iframe>
<h2 id="slides">Slides</h2>
<script async class="speakerdeck-embed" data-id="c55aca1f604545abbbc143ca65171ec7" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>
]]></content>
		</item>
		
		<item>
			<title>10 years of ruby</title>
			<link>https://matt.aimonetti.net/posts/2015-10-10-years-of-ruby/</link>
			<pubDate>Sat, 17 Oct 2015 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2015-10-10-years-of-ruby/</guid>
			<description>I chose the beautiful city of Medellin, Colombia to say my final goodbye to the awesome Ruby community. 10 years of being part of a community isn&amp;rsquo;t nothing and I took time to reflect on my personal experience and discuss the future of the language and its community.
Video  Slides  </description>
			<content type="html"><![CDATA[<img src="https://www.evernote.com/shard/s2/sh/cf6c5b2f-bc44-48ec-a9f5-9ccb8b6b1e42/ae4139a8a1a09bc2/res/b99812f5-7c62-422d-81d2-dd1012aa41f8/skitch.jpg?resizeSmall&width=832" class="">
<p>I chose the beautiful city of Medellin, Colombia to say my final goodbye to the awesome Ruby community.
10 years of being part of a community isn&rsquo;t nothing and I took time to reflect on my personal
experience and discuss the future of the language and its community.</p>
<h2 id="video">Video</h2>
<iframe width="720" height="480" src="https://www.youtube.com/embed/IWIPLzjIhTI" frameborder="0" allowfullscreen></iframe>
<h2 id="slides">Slides</h2>
<iframe src="https://docs.google.com/presentation/d/1BsFx5Hop8WlATQWIEoYLmlaOfCTsa65ZR9o94Lzz9Jw/embed?start=false&loop=false&delayms=3000" frameborder="0" width="960" height="569" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"></iframe>
]]></content>
		</item>
		
		<item>
			<title>automate itunes with js</title>
			<link>https://matt.aimonetti.net/posts/2015-09-automate-itunes-with-js/</link>
			<pubDate>Wed, 02 Sep 2015 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2015-09-automate-itunes-with-js/</guid>
			<description>Last week, my daughter started Kindergarten. I&amp;rsquo;m very happy for her, especially because she&amp;rsquo;s going to an awesome public school. As someone who didn&amp;rsquo;t grow up in the US, I heard a lot of stories about the American school system but one thing I didn&amp;rsquo;t know is that kids start so early. My daughter starts at 8:10am! We had to find a way to turn our sleeping-in family members into morning people.</description>
			<content type="html"><![CDATA[<p>Last week, my daughter started Kindergarten. I&rsquo;m very happy for her,
especially because she&rsquo;s going to an <a href="https://www.edison.smmusd.org/">awesome public school</a>.
As someone who didn&rsquo;t grow up in the US, I heard a lot of stories about the American school
system but one thing I didn&rsquo;t know is that kids start so early. My
daughter starts at 8:10am! We had to find a way to turn our
sleeping-in family members into morning people.</p>
<p>I found a solution to help us: coding and music!</p>
<p>My goal: to wake up my daughter with a custom music playlist starting a
few minutes before I go see her.</p>
<p>We have an old Mac Mini at home that I recently upgraded it to run Yosemite.
This recent version of OS X added JavaScript as an alternative to <a href="https://en.wikipedia.org/wiki/AppleScript">AppleScript</a>.
My goal is to write a little script that will play a given playlist and
then I want to schedule this script to play every school morning. The
Mac Mini is connected to an Airport Express with usb speakers located in
my daughter&rsquo;s bedroom.</p>
<h2 id="javascript-for-automation">JavaScript for Automation</h2>
<p>Apple has some <a href="https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/">documentation</a> about how to use JS to automate different tasks. To be honest the documentation isn&rsquo;t really good in comparison to their usual doc.
Also, the technical implementation is pretty hacky/buggy but that won&rsquo;t
prevent us to have a bit of fun.</p>
<p>The code to start iTunes and play our playlist if very straight forward:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript"><span style="color:#a6e22e">app</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">Application</span>(<span style="color:#e6db74">&#39;iTunes&#39;</span>)
<span style="color:#a6e22e">app</span>.<span style="color:#a6e22e">activate</span>()
<span style="color:#a6e22e">app</span>.<span style="color:#a6e22e">stop</span>()
<span style="color:#a6e22e">playlist</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">app</span>.<span style="color:#a6e22e">sources</span>[<span style="color:#e6db74">&#34;Library&#34;</span>].<span style="color:#a6e22e">userPlaylists</span>[<span style="color:#e6db74">&#34;morning&#34;</span>]
<span style="color:#66d9ef">try</span> {
	<span style="color:#a6e22e">playlist</span>.<span style="color:#a6e22e">play</span>()
}
<span style="color:#66d9ef">catch</span>(<span style="color:#a6e22e">err</span>) {
	<span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#e6db74">&#34;The playlist probably doesn&#39;t exist&#34;</span>, <span style="color:#a6e22e">err</span>)
}
</code></pre></div><p>As you probably guessed, this script loads iTunes and then uses its
scripting API to load the main library and look for a playlist called
&ldquo;morning&rdquo;.
I&rsquo;m not proud of the ugly try/catch, but playlist is an instance of
<code>ObjectSpecifier</code> which isn&rsquo;t evaluated until a method is called on it.
You can think of it as a lazy container. The problem is that if we try
to call <code>play()</code> on a playlist we didn&rsquo;t find, then an error is thrown.
I didn&rsquo;t find a way to check if the underlying value is null so I had to
catch the error.</p>
<p>Once we have the above code, we have two options, put it in a script or
convert it into an app. When developing your automation, it&rsquo;s highly
recommended to use <code>Script Editor.app</code> which ships with the OS.
From within the app, you can run your script and test / &ldquo;debug&rdquo; it.
Script Editor also allows you to export your script as script, script
bundle and app. The easiest way is to export our code as an app:</p>
<p><img src="/images/jxa_app.jpg" alt="Export JS as an app"></p>
<p>Note that you can also write a script and create a <code>osascript</code> shebang,
or even evalute your automation JS in the terminal:</p>
<pre><code>$ say &quot;you are listening to&quot; `osascript -l JavaScript -e 'Application(&quot;iTunes&quot;).currentTrack.name()'`
</code></pre><p>So we have a script to start iTunes if needed and play our morning
playlist. Now we need to schedule our app to start every school day:</p>
<h2 id="launchctl">Launchctl</h2>
<p>OS X has a builtin scheduling system called <a href="https://launchd.info/">launchd</a>. It&rsquo;s kind of like a cron scheduler but with more options.
Unfortunately figuring something as simple as scheduling a recurring
script is much harder than it should. So here is my plist file:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-xml" data-lang="xml"><span style="color:#75715e">&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;</span>
<span style="color:#75715e">&lt;!DOCTYPE plist PUBLIC &#34;-//Apple//DTD PLIST 1.0//EN&#34; &#34;https://www.apple.com/DTDs/PropertyList-1.0.dtd&#34;&gt;</span>
<span style="color:#f92672">&lt;plist</span> <span style="color:#a6e22e">version=</span><span style="color:#e6db74">&#34;1.0&#34;</span><span style="color:#f92672">&gt;</span>
<span style="color:#f92672">&lt;dict&gt;</span>
	<span style="color:#f92672">&lt;key&gt;</span>Label<span style="color:#f92672">&lt;/key&gt;</span>
	<span style="color:#f92672">&lt;string&gt;</span>morning.playlist.itunes<span style="color:#f92672">&lt;/string&gt;</span>
	<span style="color:#f92672">&lt;key&gt;</span>ProgramArguments<span style="color:#f92672">&lt;/key&gt;</span>
	<span style="color:#f92672">&lt;array&gt;</span>
		<span style="color:#f92672">&lt;string&gt;</span>/usr/bin/open<span style="color:#f92672">&lt;/string&gt;</span>
		<span style="color:#f92672">&lt;string&gt;</span>-a<span style="color:#f92672">&lt;/string&gt;</span>
		<span style="color:#f92672">&lt;string&gt;</span>wakeup.app<span style="color:#f92672">&lt;/string&gt;</span>
	<span style="color:#f92672">&lt;/array&gt;</span>
	<span style="color:#f92672">&lt;key&gt;</span>RunAtLoad<span style="color:#f92672">&lt;/key&gt;</span>
	<span style="color:#f92672">&lt;false/&gt;</span>
	<span style="color:#f92672">&lt;key&gt;</span>StandardErrorPath<span style="color:#f92672">&lt;/key&gt;</span>
	<span style="color:#f92672">&lt;string&gt;</span>/tmp/morning.playlist.itunes.stderr<span style="color:#f92672">&lt;/string&gt;</span>
	<span style="color:#f92672">&lt;key&gt;</span>StandardOutPath<span style="color:#f92672">&lt;/key&gt;</span>
	<span style="color:#f92672">&lt;string&gt;</span>/tmp/morning.playlist.itunes.stdout<span style="color:#f92672">&lt;/string&gt;</span>
	<span style="color:#f92672">&lt;key&gt;</span>StartCalendarInterval<span style="color:#f92672">&lt;/key&gt;</span>
	<span style="color:#f92672">&lt;array&gt;</span>
		<span style="color:#f92672">&lt;dict&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Hour<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>6<span style="color:#f92672">&lt;/integer&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Minute<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>55<span style="color:#f92672">&lt;/integer&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Weekday<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>1<span style="color:#f92672">&lt;/integer&gt;</span>
		<span style="color:#f92672">&lt;/dict&gt;</span>
		<span style="color:#f92672">&lt;dict&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Hour<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>6<span style="color:#f92672">&lt;/integer&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Minute<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>55<span style="color:#f92672">&lt;/integer&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Weekday<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>2<span style="color:#f92672">&lt;/integer&gt;</span>
		<span style="color:#f92672">&lt;/dict&gt;</span>
		<span style="color:#f92672">&lt;dict&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Hour<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>6<span style="color:#f92672">&lt;/integer&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Minute<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>55<span style="color:#f92672">&lt;/integer&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Weekday<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>3<span style="color:#f92672">&lt;/integer&gt;</span>
		<span style="color:#f92672">&lt;/dict&gt;</span>
		<span style="color:#f92672">&lt;dict&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Hour<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>6<span style="color:#f92672">&lt;/integer&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Minute<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>55<span style="color:#f92672">&lt;/integer&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Weekday<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>4<span style="color:#f92672">&lt;/integer&gt;</span>
		<span style="color:#f92672">&lt;/dict&gt;</span>
		<span style="color:#f92672">&lt;dict&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Hour<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>6<span style="color:#f92672">&lt;/integer&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Minute<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>55<span style="color:#f92672">&lt;/integer&gt;</span>
			<span style="color:#f92672">&lt;key&gt;</span>Weekday<span style="color:#f92672">&lt;/key&gt;</span>
			<span style="color:#f92672">&lt;integer&gt;</span>5<span style="color:#f92672">&lt;/integer&gt;</span>
		<span style="color:#f92672">&lt;/dict&gt;</span>
	<span style="color:#f92672">&lt;/array&gt;</span>
<span style="color:#f92672">&lt;/dict&gt;</span>
<span style="color:#f92672">&lt;/plist&gt;</span>
</code></pre></div><p><a href="https://gist.github.com/mattetti/75fd52c653b9144f303e">Gist</a></p>
<p>Note that I called my app <code>wakeup.app</code> and I put it in my Applications
folder. My launch agent starts the app when it&rsquo;s called, but it doesn&rsquo;t
do that when the system loads the service (<code>RunAtLoad</code> is set to false).
I&rsquo;m also logging out stdout and stderr to tmp files so I can debug if
something goes wrong. Finally the schedule is defined in the <code>StartCalendarInterval</code>
key with a daily entry Monday to Friday at 6:55am.</p>
<p>Save the plist file as <code>wakeup.playlist.itunes.plist</code> and drop it in <code>~/Library/LaunchAgents/</code>
and load it via <code>launchctl</code>:</p>
<pre><code>$ launchctl load -w ~/Library/LaunchAgents/wakeup.playlist.itunes.plist
</code></pre><p>That&rsquo;s it, everything should work fine, however if you want to make sure
it will, you might want to unload the plist, edit it so <code>RunAtLoad</code> is
set to true and reload it. At this point, your playlist should play. If
it doesn&rsquo;t, then check the log files to see what happened.
When everything is good, unload, go back to the original version and
reload.</p>
<p>There is plenty more you can do with JS Automation for Mac, if like me
you are listening to a lot of music while coding, you might be
interested in knowing that <strong>Spotify</strong> and <strong>VLC</strong> are scriptable (and
so are most browsers).</p>
]]></content>
		</item>
		
		<item>
			<title>first go challenge binary decoding</title>
			<link>https://matt.aimonetti.net/posts/2015-03-first-go-challenge-binary-decoding/</link>
			<pubDate>Tue, 03 Mar 2015 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2015-03-first-go-challenge-binary-decoding/</guid>
			<description>I&amp;rsquo;m very glad to have had the chance to be involved with the very first Go challenge. My challenge is related to something we do at Splice: binary decoding.
Read more on the Go Challenge website
pattern_1.splice Saved with HW Version: 0.808-alpha Tempo: 120 (0) kick |x---|x---|x---|x---| (1) snare |----|x---|----|x---| (2) clap |----|x-x-|----|----| (3) hh-open |--x-|--x-|x-x-|--x-| (4) hh-close |x---|x---|----|x--x| (5) cowbell |----|----|--x-|----| The challenge is going on for 2 weeks until March 15, a new challenge will be posted on April first.</description>
			<content type="html"><![CDATA[<p>I&rsquo;m very glad to have had the chance to be involved with the very first
<a href="https://golang.org">Go</a> challenge. My challenge is related to something we do at <a href="https://splice.com">Splice</a>: binary decoding.</p>
<p>Read more on the <a href="https://golang-challenge.com/go-challenge1/">Go Challenge website</a></p>
<pre><code>pattern_1.splice
Saved with HW Version: 0.808-alpha
Tempo: 120
(0) kick     |x---|x---|x---|x---|
(1) snare    |----|x---|----|x---|
(2) clap     |----|x-x-|----|----|
(3) hh-open  |--x-|--x-|x-x-|--x-|
(4) hh-close |x---|x---|----|x--x|
(5) cowbell  |----|----|--x-|----|
</code></pre><p><img src="/images/hex.png" alt="Splice challenge hex"></p>
<p>The challenge is going on for 2 weeks until March 15, a new challenge
will be posted on April first. Prizes and conditions available on the
website. Comments and discussions available on
<a href="https://news.ycombinator.com/item?id=9125480">HackerNews</a></p>
<p>Note that I also wrote <a href="https://github.com/splicers/sm-808">another challenge</a> that we usually give our
frontend candidates. If you&rsquo;re not into Go and prefer JS, you might like
this challenge better.</p>
]]></content>
		</item>
		
		<item>
			<title>understanding and sharing rails sessions</title>
			<link>https://matt.aimonetti.net/posts/2014-09-understanding-and-sharing-rails-sessions/</link>
			<pubDate>Sat, 13 Sep 2014 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2014-09-understanding-and-sharing-rails-sessions/</guid>
			<description>In September 2014, I gave this talk at Baruco in Barcelona, Spain. The talk focuses on:
 how session authentication works in Ruby on Rails, the crypto used to protect the data, the security implications and how to share the session with applications written in other languages than Ruby (with an example in Go).  To illustrate this pretty dry topic, I told the story of Alice and Bob, two entrepreneurs building a succesful web application and facing some serious challenges.</description>
			<content type="html"><![CDATA[<p>In September 2014, I gave this talk at <a href="https://www.baruco.org/">Baruco</a>
in Barcelona, Spain. The talk focuses on:</p>
<ul>
<li>how session authentication works in Ruby on Rails,</li>
<li>the crypto used to protect the data,</li>
<li>the security implications and</li>
<li>how to share the session with applications written in other languages than Ruby (with an example in <a href="https://golang.org">Go</a>).</li>
</ul>
<p>To illustrate this pretty dry topic, I told the story of Alice and Bob,
two entrepreneurs building a succesful web application and facing some serious challenges.</p>
<h2 id="video">Video</h2>
<iframe width="640" height="480" src="//www.youtube.com/embed/vC5xR5CgThM" frameborder="0" allowfullscreen></iframe>
<h2 id="slides">Slides</h2>
<script async class="speakerdeck-embed" data-slide="5" data-id="9260300033980132573d121bd1ded631" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
]]></content>
		</item>
		
		<item>
			<title>go at splice google i slash o 2014</title>
			<link>https://matt.aimonetti.net/posts/2014-06-go-at-splice-google-i-slash-o-2014/</link>
			<pubDate>Mon, 23 Jun 2014 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2014-06-go-at-splice-google-i-slash-o-2014/</guid>
			<description>The week of June 23rd was a good week for gophers in San Francisco. Go was a big part of Google I/O on Wednesday and Thursday, and on Monday Google run a Go SummerFest, a special instance of the GoSF meetup.
I gave a talk at Go SummerFest and then later on another one during I/O. For more information about the events, see this blog post from the Go team.</description>
			<content type="html"><![CDATA[<p>The week of June 23rd was a good week for gophers in San Francisco. Go was a big part of Google I/O on Wednesday and Thursday, and on Monday Google run a Go SummerFest, a special instance of the GoSF meetup.</p>
<p>I gave a talk at Go SummerFest and then later on another one during I/O. For more
information about the events, see <a href="https://blog.golang.org/io2014">this blog post from the Go team</a>.</p>
<h2 id="slides">Slides</h2>
<script async class="speakerdeck-embed" data-id="fb7887b033aa0132ef480af01cce597a" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
<p><a href="https://docs.google.com/a/golang.org/file/d/0B-nws9GU_6qVZklnNnJITlhSbXc/edit">Full screen slides</a></p>
<h2 id="video">Video</h2>
<p>My talk was recorded but it is not yet online.</p>
]]></content>
		</item>
		
		<item>
			<title>refactoring go code</title>
			<link>https://matt.aimonetti.net/posts/2014-04-refactoring-go-code/</link>
			<pubDate>Mon, 28 Apr 2014 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2014-04-refactoring-go-code/</guid>
			<description>Go aka golang is an amazing language but also a language that is really easy to learn due to its small scope. If you have some coding experience, you will be able to have fully working code in a matter of minutes otherwise you might want to read my free book (WIP).
  Very much like with many other programming languages, a challenging part of Go is to learn how to write idiomatic code.</description>
			<content type="html"><![CDATA[<p><a href="https://golang.org/">Go</a> aka golang is an amazing language but also a language that
is really easy to learn due to its small scope.
If you have some coding experience, you will be able to have fully working code
in a matter of minutes otherwise you might want to read <a href="https://www.golangbootcamp.com/">my free book</a> (WIP).</p>
<div style="text-align:center; padding:2em 0">
  <a href="https://www.golangbootcamp.com/"><img src="/images/matt_aimonetti-go_bootcamp.png" alt="Go Bootcamp free book (golang)"></a>
</div>
<p>Very much like with many other programming languages, a challenging part
of Go is to learn how to write idiomatic code.
The good news is that Go makes refactoring easy (and already has a lot
of conventions).
I strongly recommend <a href="https://peter.bourgon.org/go-in-production/">this post</a> from Peter Bourgon about Go at SoundCloud and
the extra conventions they follow (<a href="https://splice.com">Splice</a> also
follows the same conventions).</p>
<p>One of my favorite Go projects is the <a href="https://gobot.io">gobot</a> project
by <a href="https://hybridgroup.com/">HybridGroup</a>.</p>
<div style="text-align:center; padding:2em 0">
<a href="https://gobot.io/"><img src="/images/gobotio.png" alt="Gobot"></a>
</div>
<p>The Gobot project is pretty young and I noticed a few things that
could be improved so I offered my help to <a href="https://twitter.com/deadprogram">Ron</a>,
<a href="https://twitter.com/adzankich">Adrian</a> and the rest of the team.
Our discussion quickly turned into a fun group refactoring
session (featuring <a href="https://twitter.com/kytrinyx">@kytrinyx</a>,
<a href="https://twitter.com/deadprogram">@deadprogram</a>,
<a href="https://twitter.com/codegangsta">@codegangsta</a>,
<a href="https://twitter.com/jnbeck">@jnbeck</a>,
<a href="https://twitter.com/adzankich">@adzankich</a> )</p>
<div style="text-align:center; padding:2em 0">
  <img src="/images/matt_aimonetti-go_refactoring.jpg" alt="Go refactoring at GopherCon">
</div>
<h2 id="packages">Packages</h2>
<p>Gobot is split into multiple packages, a core and a few other packages.
The gobot team, out of habit chose to put a package per repo.
After further discussions, we chose to bring all official packages
inside the same repo to keep things easier and to keep the import paths
clean and logical.</p>
<p>So instead of having:</p>
<pre><code>github.com/hybridgroup/gobot
github.com/hybridgroup/gobot-sphero
github.com/hybridgroup/gobot-...
</code></pre><p>All the none-core packages are moved to subdirectories:</p>
<pre><code>github.com/hybridgroup/gobot
github.com/hybridgroup/gobot/sphero
github.com/hybridgroup/gobot/...
</code></pre><p>This also allowed us to fix the package names
<code>gobot-sphero</code> is now simply <code>sphero</code></p>
<p>Which also allowed us to simplify the following code:</p>
<p>From:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">SpheroAdaptor</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">gobot</span>.<span style="color:#a6e22e">Adaptor</span>
	<span style="color:#a6e22e">sp</span> <span style="color:#a6e22e">io</span>.<span style="color:#a6e22e">ReadWriteCloser</span>
}
</code></pre></div><p>To</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Adaptor</span> <span style="color:#66d9ef">struct</span> {
  <span style="color:#a6e22e">gobot</span>.<span style="color:#a6e22e">Adaptor</span>
  <span style="color:#a6e22e">sp</span> <span style="color:#a6e22e">io</span>.<span style="color:#a6e22e">ReadWriteCloser</span>
}
</code></pre></div><p>We did that with a few other types and methods all over the packages.</p>
<p>We had a discussion about what lead to the multiple repos vs
one repo. There are legitimate cases for both approaches but in this
situation, the decision was based on a misunderstanding. The author
thought that by importing the top package, all sub packages would
also be somewhat included in the build, making the binary bigger than
needed. Since Go only compiles and links packages imported, moving all
packages within the same repo wouldn&rsquo;t change the binary output.
Note that this is not because in this specific case we have all packages
in the same repo that this is the right thing to do every single time.</p>
<h2 id="docgo">doc.go</h2>
<p>By conventions, package should contain a <code>doc.go</code> file that contains
an overview of the package and often some information so the developer
trying to use the library can find the right entry points.</p>
<p>As usual, the standard libraries are a good example,
<a href="https://golang.org/src/pkg/net/http/doc.go">here is the net/http <code>doc.go</code> file</a>.</p>
<h2 id="using-a-constructor">Using a constructor</h2>
<p>We spent some time refactoring <code>master.go</code> which is the file implementing
the code handling one or multiple robots (which can each have multiple devices).</p>
<p>The original function code looked like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">GobotMaster</span>() <span style="color:#f92672">*</span><span style="color:#a6e22e">Master</span> {
  <span style="color:#a6e22e">m</span> <span style="color:#f92672">:=</span> new(<span style="color:#a6e22e">Master</span>)
  <span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">NumCPU</span> = <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">NumCPU</span>()
  <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">m</span>
}
</code></pre></div><p>There are a few things that aren&rsquo;t really idiomatic in this code.
The first thing is that by convention, constructors are usually called <code>New&lt;Type&gt;</code>.
Secondly, the <a href="https://peter.bourgon.org/go-in-production/">community seems to follow</a> the following stylistic choice:
only use <code>new</code> and <code>make</code> when you need to set the capacity (<code>make([]string,3)</code>)
Finally we don&rsquo;t need to allocate a variable. Here is the refactored code:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">NewMaster</span>() <span style="color:#f92672">*</span><span style="color:#a6e22e">Master</span> {
  <span style="color:#66d9ef">return</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Master</span>{<span style="color:#a6e22e">NumCPU</span>: <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">NumCPU</span>()}
}
</code></pre></div><h2 id="cleanup-package-vars">Cleanup package vars</h2>
<p>In the original code, we had a variable called <code>trap</code> which was
a function living at the top level of the package:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">trap</span> = <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">c</span> <span style="color:#66d9ef">chan</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Signal</span>) {
  <span style="color:#a6e22e">signal</span>.<span style="color:#a6e22e">Notify</span>(<span style="color:#a6e22e">c</span>, <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Interrupt</span>)
}
</code></pre></div><p>The func was then used to handle signals. The author
chose to use a variable so he could mutate it in the test suite and
avoid sending an interrupt when testing.
We realized we could avoid having this function variable at the top of the package by moving
it as a field on the <code>Master</code> type and setting the default func in the constructor.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">NewMaster</span>() <span style="color:#f92672">*</span><span style="color:#a6e22e">Master</span> {
	<span style="color:#66d9ef">return</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">Master</span>{
		<span style="color:#a6e22e">NumCPU</span>: <span style="color:#a6e22e">runtime</span>.<span style="color:#a6e22e">NumCPU</span>(),
		<span style="color:#a6e22e">trap</span>: <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">c</span> <span style="color:#66d9ef">chan</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Signal</span>) {
			<span style="color:#a6e22e">signal</span>.<span style="color:#a6e22e">Notify</span>(<span style="color:#a6e22e">c</span>, <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Interrupt</span>)
		},
	}
}
</code></pre></div><p>The code still behaves the same and we can still overwrite the trap function in our tests
(since the tests are part of the same packge, the non exported field is available)
but we got rid of a top level var.</p>
<h2 id="reading-from-a-channel">Reading from a channel</h2>
<p>The following code was ranging over a predefined channel (<code>c</code>) of signals.
and when a signal would arrive, all robots belonging to the master
would be halted and disconnected.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span> = <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">c</span> {
  <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">Robots</span> {
  	<span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">Robots</span>[<span style="color:#a6e22e">r</span>].<span style="color:#a6e22e">haltDevices</span>()
  	<span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">Robots</span>[<span style="color:#a6e22e">r</span>].<span style="color:#a6e22e">finalizeConnections</span>()
  }
  <span style="color:#66d9ef">break</span>
}
</code></pre></div><p>The code above works well but could be cleaned up a little:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#75715e">// waiting on something coming on the channel
</span><span style="color:#75715e"></span><span style="color:#f92672">&lt;-</span> <span style="color:#a6e22e">c</span>
<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">Robots</span> {
	<span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">haltDevices</span>()
	<span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">finalizeConnections</span>()
}
</code></pre></div><p>This code does the same thing but simpler.
We are trying to read from the channel which will block
(we don&rsquo;t care about the result so we don&rsquo;t capture or could have used an underscore).
Then we loop through each robot and stop them.
We managed to remove a for loop on the channel (with an odd break)
and made the code intent clearer.</p>
<h2 id="chainable-functions-and-typed-nils">Chainable functions and typed nils</h2>
<p>Next, we tackled the following method:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">m</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Master</span>) <span style="color:#a6e22e">FindRobotDevice</span>(<span style="color:#a6e22e">name</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">device</span> <span style="color:#66d9ef">string</span>) <span style="color:#f92672">*</span><span style="color:#a6e22e">device</span> {
	<span style="color:#a6e22e">robot</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">FindRobot</span>(<span style="color:#a6e22e">name</span>)
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">robot</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">robot</span>.<span style="color:#a6e22e">GetDevice</span>(<span style="color:#a6e22e">device</span>)
	}
	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
}
</code></pre></div><p>The funny thing about this method is that it&rsquo;s not needed.
We could get the same result by calling:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">FindRobot</span>(<span style="color:#e6db74">&#34;bot name&#34;</span>).<span style="color:#a6e22e">GetDevice</span>(<span style="color:#e6db74">&#34;laser&#34;</span>)
</code></pre></div><p>When I said that, someone suggested that it might be a bad idea
since <code>FindRobot()</code> might return <code>nil</code> and now we would be calling
<code>GetDevice()</code> on <code>nil</code> and bad things would happen.
Looking at the code, it was actually easy to fix.</p>
<p>Here is the original code:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Robot</span>) <span style="color:#a6e22e">GetDevice</span>(<span style="color:#a6e22e">name</span> <span style="color:#66d9ef">string</span>) <span style="color:#f92672">*</span><span style="color:#a6e22e">device</span> {
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">device</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">devices</span> {
		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">device</span>.<span style="color:#a6e22e">Name</span> <span style="color:#f92672">==</span> <span style="color:#a6e22e">name</span> {
			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">device</span>
		}
	}
	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
}
</code></pre></div><p>Here is the refactored version:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Robot</span>) <span style="color:#a6e22e">GetDevice</span>(<span style="color:#a6e22e">name</span> <span style="color:#66d9ef">string</span>) <span style="color:#f92672">*</span><span style="color:#a6e22e">device</span> {
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">r</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
	}
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">device</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">devices</span> {
		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">device</span>.<span style="color:#a6e22e">Name</span> <span style="color:#f92672">==</span> <span style="color:#a6e22e">name</span> {
			<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">device</span>
		}
	}
	<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
}
</code></pre></div><p>Did you spot the difference? We just added a check to see if the pointer (<code>r</code>)
was nil, if it is, we just return <code>nil</code>.
When I added the code above, the person who was worried
about calling <code>GetDevice()</code> on <code>nil</code> was scratching his head.</p>
<p>Golang does something very interesting (and a bit surprising if you come
from a dynamic language),
it returns a nil pointer of the type we defined as return type.
Let&rsquo;s walk through the code by rewriting it slightly differently:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">var</span> <span style="color:#a6e22e">bot</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Robot</span>
<span style="color:#a6e22e">bot</span> = <span style="color:#a6e22e">m</span>.<span style="color:#a6e22e">FindRobot</span>(<span style="color:#e6db74">&#34;unknown name&#34;</span>)
</code></pre></div><p>At this point if <code>FindRobot()</code> didn&rsquo;t find a robot, <code>bot</code> is still
of type <code>*Robot</code> but the pointer is nil.
Because we defined a method <code>GetDevice()</code> on <code>*Robot</code>, we
can call:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">bot</span>.<span style="color:#a6e22e">GetDevice</span>(<span style="color:#e6db74">&#34;x-ray&#34;</span>)
</code></pre></div><p>The <code>GetDevice()</code> method will execute and will return <code>nil</code> right
away because we check if the pointer is <code>nil</code>.</p>
<p>The fact that nil pointers have types has 2 important implications,
the first one is that you can nicely chain methods without
checking at the caller site if the returned value is <code>nil</code>.
The second is that your methods should expect to be potentially
called on a nil pointer and should properly handle such cases.</p>
<p><strong>Note</strong>: Go team member <a href="https://twitter.com/enneff">Andrew Gerrand</a>
suggested on <a href="https://news.ycombinator.com/item?id=7667554">Hacker News</a>
to name the method <code>Device</code> instead of <code>GetDevice</code>. The word <code>Get</code> is almost always redundant.
In the same chain of thoughts, maybe we should rename <code>FindRobot</code> just <code>Robot</code>.</p>
<h2 id="collection-types--type-aliasing">Collection types / type aliasing</h2>
<p>I&rsquo;m writing this post on my way back from GopherCon and there
was one more thing I wanted to clean up and share with you.
This is a nice pattern I use often to simplify my code.</p>
<p>Our <code>Robot</code> type has a <code>connections</code> field and a <code>devices</code> field:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Robot</span> <span style="color:#66d9ef">struct</span> {
  <span style="color:#75715e">// .. fields removed to simplify the example
</span><span style="color:#75715e"></span>	<span style="color:#a6e22e">devices</span>       []<span style="color:#f92672">*</span><span style="color:#a6e22e">device</span>
}
</code></pre></div><p>To avoid always having to manually loop through the slice, a method is defined on
pointers to <code>Robot</code>. This method iterates over
the devices and halts them:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">r</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">Robot</span>) <span style="color:#a6e22e">haltDevices</span>() {
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">device</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">devices</span> {
		<span style="color:#a6e22e">device</span>.<span style="color:#a6e22e">Halt</span>()
	}
}
</code></pre></div><p>This code is totally fine but from an API design perspective, wouldn&rsquo;t it be nicer
to use?:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">devices</span>().<span style="color:#a6e22e">Halt</span>()
</code></pre></div><p>One of the nice things with this approach is that the concept of halting, which
really belongs to the devices, doesn&rsquo;t need to leak into the <code>Robot</code> world.</p>
<p>To implement the suggested API change, we need to define a <a href="https://www.golangbootcamp.com/book/methods_and_interfaces#uid90">type alias</a>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">DeviceCollection</span> []<span style="color:#f92672">*</span><span style="color:#a6e22e">device</span>
</code></pre></div><p>We can now define methods on our new type:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">DeviceCollection</span>) <span style="color:#a6e22e">Halt</span>() {
  <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">device</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">c</span> {
    <span style="color:#a6e22e">device</span>.<span style="color:#a6e22e">Halt</span>()
  }
}
</code></pre></div><p>We then need to update our <code>Robot</code> type:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">Robot</span> <span style="color:#66d9ef">struct</span> {
  <span style="color:#75715e">// .. fields removed to simplify the example
</span><span style="color:#75715e"></span>  <span style="color:#a6e22e">devices</span>       <span style="color:#a6e22e">DeviceCollection</span>
}
</code></pre></div><p>And we are done with our refactoring.</p>
<p>One last note, since we might need to call different methods on our collection
we could create an iterator method.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> (<span style="color:#a6e22e">c</span> <span style="color:#a6e22e">DeviceCollection</span>) <span style="color:#a6e22e">Each</span>(<span style="color:#a6e22e">f</span> <span style="color:#66d9ef">func</span>(<span style="color:#f92672">*</span><span style="color:#a6e22e">device</span>)) {
  <span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">d</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">c</span> {
    <span style="color:#a6e22e">f</span>(<span style="color:#a6e22e">d</span>)
  }
}

<span style="color:#75715e">// which can be called like so
</span><span style="color:#75715e"></span><span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">devices</span>.<span style="color:#a6e22e">Each</span>(<span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">d</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">device</span>){
  <span style="color:#a6e22e">d</span>.<span style="color:#a6e22e">Halt</span>()
})
</code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>Needless to say that we had fun. The refactoring went much further
and we removed the use of reflections, some sleeps and much more.
The code is going through a nice cleanup before reaching 1.0 and
I can only encourage everybody to play with <a href="https://gobot.io">Gobot</a>,
there are very few things as fun as Go and Robots!
(The code is open sourced, look at it, add new drivers, send PRs!)</p>
<p>I&rsquo;d like to thank <a href="https://twitter.com/deadprogram">Ron Evans</a> and the <a href="https://hybridgroup.com/">Hybrid Group</a>
for  open sourcing their code and sharing the fun with all of us.
I can&rsquo;t wait for the next LA Go + Robot hack night.</p>
<p>Finally, <a href="https://splice.com">Splice</a> is hiring, our stack uses a lot of
different technologies but our backend is all in Go and we are always
looking for talented engineers. Drop me a line if interested.</p>
]]></content>
		</item>
		
		<item>
			<title>books to read in 2014</title>
			<link>https://matt.aimonetti.net/posts/2013-12-books-to-read-in-2014/</link>
			<pubDate>Tue, 31 Dec 2013 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2013-12-books-to-read-in-2014/</guid>
			<description>I like to read and I have a great community on Twitter so I asked them what they think others and myself should read in 2014. Here is the compiled list of the recommended books. The good news is that most of these books are under $10, so why not picking a couple for the new year?
A big thanks to all the people who recommended these books, I&amp;rsquo;m looking forward to 2014!</description>
			<content type="html"><![CDATA[<p>I like to read and I have a great community on Twitter so I asked them
what they think others and myself should read in 2014.
Here is the compiled list of the recommended books.
The good news is that most of these books are under $10, so why not
picking a couple for the new year?</p>
<p>A big thanks to all the people who recommended these books, I&rsquo;m looking
forward to 2014!</p>
<table>
  <thead>
  <tr>
    <th style="width:20%; text-align:center"> Cover  </th>
    <th style="width:30%; text-align:center"> Title </th>
    <th style="width:20%; text-align:center"> Type </th>
    <th style="width:30%; text-align:center"> Recommended by</th>
  </tr>
  </thead>
  <tbody>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B008U4HH54/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B008U4HH54&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/51rwkxlzOQL._SL160_.jpg" alt="The Interestings" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B008U4HH54/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B008U4HH54&linkCode=as2&tag=merbist-20" target="_blank">The Interestings</a></td>
    <td>Novel</td>
    <td><a title="@aweissman" href="https://twitter.com/aweissman" target="_blank"> <img src='https://pbs.twimg.com/profile_images/344513261581924513/b3735cda4529be5530c9d29b6f8e148e_bigger.jpeg' ><br /> Andrew Weissman<br />@aweissman</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B00AEBETMK/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B00AEBETMK&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/51mquDqvXDL._SL160_.jpg" alt="Lexicon" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B00AEBETMK/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B00AEBETMK&linkCode=as2&tag=merbist-20" target="_blank">Lexicon</a></td>
    <td>Novel</td>
    <td><a title="@Adkron" href="https://twitter.com/Adkron" target="_blank"> <img src='https://pbs.twimg.com/profile_images/3485440049/a0f1a8fd26883c905443be6b17091a43_bigger.jpeg' ><br /> Amos King<br />@Adkron</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/dp/B004X6PRO6?tag=merbist-20&camp=0&creative=0&linkCode=as4&creativeASIN=B004X6PRO6&adid=040WG8W6HCZ9D7GW6FCZ&"><img src="https://images-na.ssl-images-amazon.com/images/I/416VaBI-AnL._SL160_.jpg" alt="The Orphan Master's Son (Pulitzer Prize for Fiction)" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/dp/B004X6PRO6?tag=merbist-20&camp=0&creative=0&linkCode=as4&creativeASIN=B004X6PRO6&adid=040WG8W6HCZ9D7GW6FCZ&" target="_blank">The Orphan Master's Son (Pulitzer Prize for Fiction)</a></td>
    <td>Novel</td>
    <td><a title="@bryanwoods" href="https://twitter.com/bryanwoods" target="_blank"> <img src='https://pbs.twimg.com/profile_images/378800000586125380/e28de02be744272035a9b5509d5ab576_bigger.jpeg' ><br /> Bryan Woods<br />@bryanwoods</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B008J4NBHI/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B008J4NBHI&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/510e7pW7-YL._SL160_.jpg" alt="The Flamethrowers" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B008J4NBHI/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B008J4NBHI&linkCode=as2&tag=merbist-20" target="_blank">The Flamethrowers</a></td>
    <td>Novel</td>
    <td><a title="@aweissman" href="https://twitter.com/aweissman" target="_blank"> <img src='https://pbs.twimg.com/profile_images/344513261581924513/b3735cda4529be5530c9d29b6f8e148e_bigger.jpeg' ><br /> Andrew Weissman<br />@aweissman</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B008FPOIT6/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B008FPOIT6&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/51uYnHtUXLL._SL160_.jpg" alt="Mr. Penumbra's 24-Hour Bookstore" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B008FPOIT6/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B008FPOIT6&linkCode=as2&tag=merbist-20" target="_blank">Mr. Penumbra's 24-Hour Bookstore</a></td>
    <td>Novel</td>
    <td><a title="@conrey" href="https://twitter.com/conrey" target="_blank"> <img src='https://pbs.twimg.com/profile_images/378800000197700668/7625b773ea917bcd87aa8c2a0be8588f_bigger.jpeg' ><br /> Chris Conrey<br />@conrey</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B000FBJF8C/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B000FBJF8C&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/41HZER4774L._SL160_.jpg" alt="Lying Awake" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B000FBJF8C/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B000FBJF8C&linkCode=as2&tag=merbist-20" target="_blank">Lying Awake</a></td>
    <td>Novel</td>
    <td><a title="@aweissman" href="https://twitter.com/aweissman" target="_blank"> <img src='https://pbs.twimg.com/profile_images/344513261581924513/b3735cda4529be5530c9d29b6f8e148e_bigger.jpeg' ><br /> Andrew Weissman<br />@aweissman</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B000FBFO8C/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B000FBFO8C&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/31kDOO-T2lL._SL160_.jpg" alt="Perdido Street Station" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B000FBFO8C/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B000FBFO8C&linkCode=as2&tag=merbist-20" target="_blank">Perdido Street Station</a></td>
    <td>Novel</td>
    <td><a title="@olg" href="https://twitter.com/olg" target="_blank"> <img src='https://pbs.twimg.com/profile_images/204337634/935afae3375820ecc0bfbe5288d9b411-2_bigger.jpeg' ><br /> Olivier Gutknecht<br />@olg</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B004CFA91Y/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B004CFA91Y&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/51MCnQRKCyL._SL160_.jpg" alt="The Sisters Brothers" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B004CFA91Y/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B004CFA91Y&linkCode=as2&tag=merbist-20" target="_blank">The Sisters Brothers</a></td>
    <td>Novel</td>
    <td><a title="@aweissman" href="https://twitter.com/aweissman" target="_blank"> <img src='https://pbs.twimg.com/profile_images/344513261581924513/b3735cda4529be5530c9d29b6f8e148e_bigger.jpeg' ><br /> Andrew Weissman<br />@aweissman</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B000OZ0NXA/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B000OZ0NXA&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/51zzGBqKVPL._SL160_.jpg" alt="Killing Floor (Jack Reacher, No. 1)" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B000OZ0NXA/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B000OZ0NXA&linkCode=as2&tag=merbist-20" target="_blank">Killing Floor (Jack Reacher, No. 1)</a></td>
    <td>Novel</td>
    <td><a title="@drnic" href="https://twitter.com/drnic" target="_blank"> <img src='https://pbs.twimg.com/profile_images/2243751587/drnic_by_jeff_casimir_at_railsconf2010_-_thumbnail_bigger.png' ><br /> Dr Nic<br />@drnic</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B003RRXXMA/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B003RRXXMA&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/51KOAfltTRL._SL160_.jpg" alt="Jonathan Strange and Mr Norrell" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B003RRXXMA/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B003RRXXMA&linkCode=as2&tag=merbist-20" target="_blank">Jonathan Strange and Mr Norrell</a></td>
    <td>Novel</td>
    <td><a title="@olg" href="https://twitter.com/olg" target="_blank"> <img src='https://pbs.twimg.com/profile_images/204337634/935afae3375820ecc0bfbe5288d9b411-2_bigger.jpeg' ><br /> Olivier Gutknecht<br />@olg</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/dp/B00555X8OA?tag=merbist-20&camp=0&creative=0&linkCode=as4&creativeASIN=B00555X8OA&adid=0PMMZTW1D2GZ2JYSBZ7S&"><img src="https://images-na.ssl-images-amazon.com/images/I/41shZGS-G%2BL._SL160_.jpg" alt="Thinking, Fast and Slow" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/dp/B00555X8OA?tag=merbist-20&camp=0&creative=0&linkCode=as4&creativeASIN=B00555X8OA&adid=0PMMZTW1D2GZ2JYSBZ7S&" target="_blank">Thinking, Fast and Slow</a></td>
    <td>Psychology / Business Decision-Making</td>
    <td><a title="@atduskgreg" href="https://twitter.com/atduskgreg" target="_blank"> <img src='https://pbs.twimg.com/profile_images/413083183471538176/pxJfy0v1_bigger.png' ><br /> Greg Borenstein<br />@atduskgreg</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B007V65R54/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B007V65R54&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/51ag2JxaFxL._SL160_.jpg" alt="The Signal and the Noise: Why So Many Predictions Fail-but Some Don't" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B007V65R54/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B007V65R54&linkCode=as2&tag=merbist-20" target="_blank">The Signal and the Noise: Why So Many Predictions Fail-but Some Don't</a></td>
    <td>Business Planning & Forecasting</td>
    <td><a title="@roidrage" href="https://twitter.com/roidrage" target="_blank"> <img src='https://pbs.twimg.com/profile_images/2938540224/9ffc554b0eabb077a915cfe0d56f3c1f_bigger.jpeg' ><br /> Mathias Meyer<br />@roidrage</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B001S59CP0/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B001S59CP0&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/41ukeeK16zL._SL160_.jpg" alt="The Life You Can Save: Acting Now to End World Poverty" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B001S59CP0/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B001S59CP0&linkCode=as2&tag=merbist-20" target="_blank">The Life You Can Save: Acting Now to End World Poverty</a></td>
    <td>Philanthropy & Charity</td>
    <td><a title="@tpdubs2" href="https://twitter.com/tpdubs2" target="_blank"> <img src='https://pbs.twimg.com/profile_images/1875371426/IMG_1963_bigger.jpg' ><br /> Theresa Preston-Werner<br />@tpdubs2</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B005VSRFEA/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B005VSRFEA&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/51LhBKtrCZL._SL160_.jpg" alt="Thinking in Systems: A Primer" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B005VSRFEA/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B005VSRFEA&linkCode=as2&tag=merbist-20" target="_blank">Thinking in Systems: A Primer</a></td>
    <td>Problem Solving</td>
    <td><a title="@roidrage" href="https://twitter.com/roidrage" target="_blank"> <img src='https://pbs.twimg.com/profile_images/2938540224/9ffc554b0eabb077a915cfe0d56f3c1f_bigger.jpeg' ><br /> Mathias Meyer<br />@roidrage</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/dp/B00FM0OC4S?tag=merbist-20&amp;camp=0&amp;creative=0&amp;linkCode=as4&amp;creativeASIN=B00FM0OC4S&amp;adid=01GQ5KB9AGZ9M02BFA7B&amp;"><img src="https://images-na.ssl-images-amazon.com/images/I/51S0zRDsbtL._SL160_.jpg" alt="High Performance Browser Networking" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/dp/B00FM0OC4S?tag=merbist-20&amp;camp=0&amp;creative=0&amp;linkCode=as4&amp;creativeASIN=B00FM0OC4S&amp;adid=01GQ5KB9AGZ9M02BFA7B&amp;" target="_blank">High Performance Browser Networking</a></td>
    <td>Technical</td>
    <td><a title="@kstewart" href="https://twitter.com/kstewart" target="_blank"> <img src='https://pbs.twimg.com/profile_images/411994393231372288/fiPif7_Q_bigger.jpeg' ><br /> Kevin Stewart<br />@kstewart</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B009NF6Z2K/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B009NF6Z2K&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/51KxC4wQCsL._SL160_.jpg" alt="NOS4A2" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B009NF6Z2K/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=B009NF6Z2K&linkCode=as2&tag=merbist-20" target="_blank">NOS4A2</a></td>
    <td>Novel</td>
    <td><a title="@diminish7" href="https://twitter.com/diminish7" target="_blank"> <img src='https://pbs.twimg.com/profile_images/1434299830/jason_on_grays_and_torreys_climb_bigger.jpg' ><br /> Jason Rush<br />@diminish7</a></a></td>
  </tr>
  <tr>
    <td><a href="https://www.amazon.com/gp/product/B0047T86CO/ref=as_li_ss_il?ie=UTF8&camp=1789&creative=390957&creativeASIN=B0047T86CO&linkCode=as2&tag=merbist-20"><img src="https://images-na.ssl-images-amazon.com/images/I/31c63zBdD6L._SL160_.jpg" alt="Basic Economics: A Common Sense Guide to the Economy, 4th Edition" border="0" style="padding-top:10px"></a></td>
    <td><a href="https://www.amazon.com/gp/product/B0047T86CO/ref=as_li_ss_il?ie=UTF8&camp=1789&creative=390957&creativeASIN=B0047T86CO&linkCode=as2&tag=merbist-20" target="_blank">Basic Economics: A Common Sense Guide to the Economy, 4th Edition</a></td>
    <td>Economics</td>
    <td><a title="@rubiety" href="https://twitter.com/rubiety" target="_blank"> <img src='https://pbs.twimg.com/profile_images/2909781099/17f882cfce30ac2a938d072c85251d55_bigger.png' ><br /> Ben Hughes<br />@rubiety</a></a></td>
  </tr>
  </tbody>
</table>
<p>If you want more, you can check the <a href="https://merbist.com/2011/12/30/books-to-read-in-2012-recommended-to-me-by-twitter/">previous book recommendation list</a></p>
]]></content>
		</item>
		
		<item>
			<title>sharing rails sessions with non ruby apps</title>
			<link>https://matt.aimonetti.net/posts/2013-11-sharing-rails-sessions-with-non-ruby-apps/</link>
			<pubDate>Sat, 30 Nov 2013 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2013-11-sharing-rails-sessions-with-non-ruby-apps/</guid>
			<description>I wanted to share sessions between my Rails and Go applications. I wanted to let an authenticated Rails user make JavaScript API calls to an endpoint written in Go. How hard could it be?
Since I own both apps, I thought it would be as simple as sharing the secret session key and re-implementing Rails crypto process in Go. It turned out to be a lot more interesting.
In a nutshell, here is what I discovered:</description>
			<content type="html"><![CDATA[<p>I wanted to share sessions between my Rails and Go applications. I wanted to let an authenticated Rails user make JavaScript API calls to an endpoint written in Go. How hard could it be?</p>
<p>Since I own both apps, I thought it would be as simple as sharing the secret session key and re-implementing Rails crypto process in Go. It turned out to be a lot more interesting.</p>
<p>In a nutshell, here is what I discovered:</p>
<ul>
<li>It&rsquo;s totally doable! Here is my <a href="https://godoc.org/github.com/mattetti/goRailsYourself/crypto">Go package</a>.</li>
<li>If you are using a version of Rails older than 4.0, you’d better upgrade ASAP!</li>
<li>Rails has been criticized for security issues, but the current solution has been vetted by many experts.</li>
<li>Rails serializes session data using Ruby Marshal which means that someone with the secret key can <em>inject arbitrary code in the session</em> and it will execute server side. Switch to JSON, MessagePack or other safe serialization formats.</li>
<li>Security is (still) hard.</li>
</ul>
<h2 id="rails-cookies-are-dangerous">Rails Cookies are Dangerous</h2>
<p>Because Rails serializes and deserializes the session and any encrypted/signed cookies using Ruby&rsquo;s Marshal library, someone with the app secret can wreak havoc. They can embed arbitrary Ruby code into the cookie, submit it with a request, and the server-side deserialization will execute that code without you noticing. Granted, this requires the attacker to have the app secret, but since 99% of the apps out there have the shared secret in their source code, anyone with access to the source code has this data. It’s not data you can easily rotate when employees leave or when you are done working with contractors. Anybody with the shared secret is a potential attacker. Start by moving this data out of the code base and into an environment variable.</p>
<p>Rails doesn’t let you change the default serializer directly. But Rails relies on ActiveSupport for its crypto work and AS supports swapping the serializer. Some people in the community are aware of this issue and monkey patch Rails to serialize their sessions using JSON or another alternative. Here is an <a href="https://nerds.airbnb.com/upgrading-from-ree-187-to-ruby-193/">Airbnb article</a> and
<a href="https://gist.github.com/jeffyip/4091166">Rails 3 patch</a>. <a href="https://gist.github.com/mattetti/7624413">Here is my Rails 4 monkey patch</a> to switch the serialization to JSON. I&rsquo;m using it in production with Rails 4, but it&rsquo;s untested on Rails 3.</p>
<p>You can modify either solution to use <a href="https://msgpack.org/">MessagePack</a> instead of JSON if you want to fit more data in the 4K cookie size.</p>
<h2 id="understanding-rails-session-encryption">Understanding Rails Session Encryption</h2>
<p>Once I addressed the serialization issue, I had to reimplement the crypto work done by Rails to encode and/or sign the data.</p>
<p>Most of us just rely on our frameworks/libraries to do the right thing, but we rarely look under the hood. I ported the logic to Golang which has an amazing support for crypto (albeit lower level than Ruby). My <a href="https://godoc.org/github.com/mattetti/goRailsYourself/crypto">Go package</a> contains an explanation of the code logic and <a href="https://godoc.org/github.com/mattetti/goRailsYourself/crypto#pkg-examples">the examples</a> needed to decode/verify as well as encode/sign sessions that are compatible with Rails.</p>
<p>Here is a high level summary of what Rails does when it encodes and signs your session data:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">key_generator <span style="color:#f92672">=</span> <span style="color:#66d9ef">ActiveSupport</span><span style="color:#f92672">::</span><span style="color:#66d9ef">CachingKeyGenerator</span><span style="color:#f92672">.</span>new(<span style="color:#66d9ef">ActiveSupport</span><span style="color:#f92672">::</span><span style="color:#66d9ef">KeyGenerator</span><span style="color:#f92672">.</span>new(app_secret_key, <span style="color:#e6db74">iterations</span>: <span style="color:#ae81ff">1000</span>))
derived_secret <span style="color:#f92672">=</span> key_generator<span style="color:#f92672">.</span>generate_key(<span style="color:#e6db74">&#34;encrypted cookie&#34;</span>)
sign_secret <span style="color:#f92672">=</span> key_generator<span style="color:#f92672">.</span>generate_key(<span style="color:#e6db74">&#34;signed encrypted cookie&#34;</span>)

encryptor <span style="color:#f92672">=</span> <span style="color:#66d9ef">ActiveSupport</span><span style="color:#f92672">::</span><span style="color:#66d9ef">MessageEncryptor</span><span style="color:#f92672">.</span>new(secret, sign_secret)
session_content <span style="color:#f92672">=</span> encryptor<span style="color:#f92672">.</span>encrypt_and_sign({<span style="color:#e6db74">hello</span>: <span style="color:#e6db74">&#34;world&#34;</span>})
</code></pre></div><p>The <code>session_content</code> string is then set as the session cookie value.
Note that you could do that in any Ruby app using <code>ActiveSupport</code>, making it easy to share sessions between Ruby applications (like Rails &amp; Sinatra).</p>
<p>Technically, there are a lot of things going on. To avoid using the same secret to sign and encode data, Rails relies on derived keys using <a href="https://en.wikipedia.org/wiki/PBKDF2">PBKDF2</a> (password based key derivation function).
It treats the app secret as a password and applies a pseudorandom function 1000 times (Rails default) using a default salt. The result is a derived key so the original password isn’t shared. The derived key can be regenerated identically if the salt and secret are known (because the function is pseudorandom).</p>
<p>The two derived keys are then passed to the <a href="https://github.com/rails/rails/blob/master/activesupport/lib/active_support/message_encryptor.rb"><code>MessageEncryptor</code></a> class which uses <a href="https://github.com/rails/rails/blob/master/activesupport/lib/active_support/message_verifier.rb"><code>MessageVerifier</code></a> to do the signing. The generated keys are 64 bytes long. One key goes to the encryptor while the other goes to the verifier.</p>
<p>The verification is done via <a href="https://en.wikipedia.org/wiki/Hash-based_message_authentication_code">HMAC (SHA1)</a> and it uses the full 64 byte key.
The encoding is done via <a href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard">AES 256 CBC</a> only using the first 32 bytes of the encryption derived key. Rails will only generate a 32-byte key since that&rsquo;s the expected key length.</p>
<p>The session data is serialized (using Marshal by default) then encoded via AES. Both the encoded string and the <a href="https://en.wikipedia.org/wiki/Initialization_vector">IV</a> are encoded using base64 and joined in a string using a predefined format.</p>
<p>At this point, the session is encoded but it could be tampered with. To avoid that, Rails signs the encoded data using the verifier (HMAC) and appends the base 64 encoded signature to the encoded data.</p>
<p>To decode and verify the data, Rails repeats the process in reverse using the serializer to deserialize the data.</p>
<p>Note that you can also rely on the the same crypto process to safely encode/sign <em>any</em> data you want to share. If you&rsquo;re ok with the data being user-readable, sign it to make sure it isn&rsquo;t tampered with along the way. If you don&rsquo;t want it to be user-readable, encrypt it first then sign the encrypted data.</p>
<h2 id="sharing-the-session-with-non-ruby-apps">Sharing the Session with Non-Ruby Apps</h2>
<p>Many apps are moving to an SOA approach. That often means multiple languages living together in production. Sharing a web session can be very useful, especially until you switch to a SSO solution.</p>
<p>The key is to start by having the session data serialized in a format that is available in all your relevent languages. JSON, XML MessagePack, and protobuf are good examples.</p>
<p>The second step is to reimplement the crypto dance I just explained above. The good news is that I’ve already done it for Go. Using that example, you should be able to port it to other languages (Node, Scala/Clojure/Java, Rust, Elixir, Python or whatever you fancy).</p>
<p><a href="https://github.com/mattetti/goRailsYourself/tree/master/crypto">https://github.com/mattetti/goRailsYourself/tree/master/crypto</a></p>
<p>Even though the test suite isn’t perfect (yet), it should greatly help you through the porting process. To be honest the hardest part was understanding the process, not writing the code. Most languages have decent crypto libraries to do the hard parts for you. But for Go I had to implement lower level pieces like the PKCS7 padding for the AES CBC encryption/decryption.</p>
<p>Hopefully this article was helpful and you now better understand how Rails does its session encryption. Once you understand the process Rails uses, you can implement it in any language.</p>
<p>** Finally, if you interested in working on interesting and challenging
problems like these ones, consider joining the <a href="https://splice.com">Splice</a> team! **</p>
]]></content>
		</item>
		
		<item>
			<title>bad code doesnt exist</title>
			<link>https://matt.aimonetti.net/posts/2013-10-bad-code-doesnt-exist/</link>
			<pubDate>Mon, 14 Oct 2013 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2013-10-bad-code-doesnt-exist/</guid>
			<description>I just give a talk at Wicked Good Ruby Conf in Boston. I&amp;rsquo;m sure the talk will be online soon, but I figured it would be interesting to discuss it a bit further in a blog post.
The format was a bit different than usual, I had a 40 minute slot and divided in 2, I made my points for 20 minutes and invited two special guests on stage to discuss the topic.</description>
			<content type="html"><![CDATA[<p>I just give a talk at <a href="https://wickedgoodruby.com/">Wicked Good Ruby Conf</a> in Boston. I&rsquo;m sure the talk will be online soon, but I figured it would be interesting to discuss it a bit further in a blog post.</p>
<p>The format was a bit different than usual, I had a 40 minute slot and
divided in 2, I made my points for 20 minutes and invited two special
guests on stage to discuss the topic. The reason for this format is
because I think we all learn better by looking at things from different
perspectives. I can&rsquo;t thank enough <a href="https://www.sandimetz.com/">Sandi Metz</a> and <a href="https://kytrinyx.com/">Katrina Owen</a> for their contributions.</p>
<p>Here are a few points that I think are interesting and
that we discussed during the talk.</p>
<h2 id="there-isnt-such-thing-as-bad-code">There isn&rsquo;t such thing as bad code</h2>
<p>Bad code doesn&rsquo;t exist, you have code that can be interpreted/compiled and code that doesn&rsquo;t.
&ldquo;Good&rdquo; and &ldquo;bad&rdquo; are moralistic designations, not scientific ones.
Let&rsquo;s try to stop using these terms to refer to talk. Let&rsquo;s be more
precise when arguing about code, &ldquo;what do you mean by bad?&rdquo; Is it
hard to maintain, hard to understand, slow etc.. ?
Always refer to the context in which the code was written. Don&rsquo;t use it
as an excuse to defend anybody&rsquo;s potentially hurt ego, but instead to
explain why the code was written caring about certain values instead of
others. Most code turns emo after a little while, being able to
understand the context, helps a lot the devision process when facing
such code.</p>
<p><img src="/images/matt_aimonetti-code_apology.jpg" alt="Bad code"></p>
<h2 id="its-all-about-expected-outcome-and-context">It&rsquo;s all about expected outcome and context</h2>
<p>As developers, we aren&rsquo;t paid to write code, we are paid to build
products, to convert ideas into something &ldquo;concrete&rdquo;. When I use my
favorite app, I don&rsquo;t care that the code is beautiful, I care that it
works, that it&rsquo;s stable and provides me with what I need. If the code is
written in Go, Pascal, Erlang, VB or Ruby doesn&rsquo;t matter at all. That the
code has full test coverage and was written in an agile manner using
weekly scrums and TDD is probably as important as knowing the Pantone
color of a company&rsquo;s logo: it only matters to the people deeply
involved.</p>
<p>Don&rsquo;t focus on how to build, focus on why you build things. Then the how
will come as you learn from others, experiment and discover &ldquo;how&rdquo; to build
the &ldquo;why&rdquo;. The &ldquo;why&rdquo; is often the constant, the &ldquo;how&rdquo; keeps on changing
as we collect more information.</p>
<h2 id="we-love-rules">We love rules</h2>
<p>When you learn, rules are easier. Katrina made a very good point during
our discussion. When she teaches, she needs to have very strong rules
that she can justify. That said, her rules can change, and as you become
better, you can start challenging the rules. Rules are somewhere between
training wheels and a guard-rail. They are very useful but shouldn&rsquo;t be
used to attack other people.</p>
<p>Ruby has a language doesn&rsquo;t enforce many rules, as a matter of fact,
Matz designed a language so you can set your own rules, or barely have
any rules.
This fact probably explains why so many people are after solid rules
they can rely on. Rules are easy to follow and are a good reference.
The Ruby language doesn&rsquo;t have enough rules to some, so the community is
helping by coming together to define them.
This is by the way, the biggest difference with Python and Go where
these 2 languages explicitly want to only have 1 way of doing one thing.</p>
<h2 id="communication-and-team-work">Communication and team work</h2>
<p>The key to building a good product (which is what we are paid to do) is
communication. Unfortunately, us developers, are on average, pretty
terrible at that.
We need to do a better job communicating with the rest of the
organization (i.e: anybody who&rsquo;s not an engineer). It usually starts by
the designers. The expected outcome of the product should be clear, well
understood by all and easily evaluable.
Within the engineering team, coding values should be set explicitly.
Not everyone will agree but when we write code, we should all care about
the same overall values so our work is consistent. When something
happens and we have a disagreement, it&rsquo;s easier to refer to our values
to decide what solution to pick.</p>
<h2 id="slides">Slides</h2>
<script async class="speakerdeck-embed" data-id="f325aee016620131a63906e09cf22df5" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
<h2 id="video">Video</h2>
<iframe width="640" height="480" src="//www.youtube.com/embed/VO-NvnZfMA4" frameborder="0" allowfullscreen></iframe>
]]></content>
		</item>
		
		<item>
			<title>what technology should my startup use</title>
			<link>https://matt.aimonetti.net/posts/2013-08-what-technology-should-my-startup-use/</link>
			<pubDate>Tue, 27 Aug 2013 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2013-08-what-technology-should-my-startup-use/</guid>
			<description>Over the years many people have asked me the same question:
 I&amp;rsquo;m starting this new project, what technology do you think I should use?
 Categories = [] +++ 
Update: Speaking of HN, here is the thread for this post</description>
			<content type="html"><![CDATA[<p>Over the years many people have asked me the same question:</p>
<blockquote>
<p>I&rsquo;m starting this new project, what technology do you think I should use?</p>
</blockquote>
<p>Categories = []
+++
<br/></p>
<p><em>Update</em>: Speaking of HN, <a href="https://news.ycombinator.com/item?id=6285129">here is the thread for this post</a></p>
]]></content>
		</item>
		
		<item>
			<title>golang multipart file upload example</title>
			<link>https://matt.aimonetti.net/posts/2013-07-golang-multipart-file-upload-example/</link>
			<pubDate>Mon, 01 Jul 2013 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2013-07-golang-multipart-file-upload-example/</guid>
			<description>The Go language is one of my favorite programming languages. However, sometimes doing simple things can seem a bit harder than it should. However, most of the time, the problem is just to find out how to do things the easy way. While Go&amp;rsquo;s documention isn&amp;rsquo;t bad, the real key to finding out how to do things is often to look at the source code and the test suite.
I&amp;rsquo;m not yet super familiar with all the std lib packages, so when I wanted to test my Go web services, I wrote a few lines of code to create a multipart file upload function that was building the body from scratch.</description>
			<content type="html"><![CDATA[<p>The Go language is one of my favorite programming languages. However,
sometimes doing simple things can seem a bit harder than it should.
However, most of the time, the problem is just to find out how to
do things the easy way. While Go&rsquo;s documention isn&rsquo;t bad, the real key
to finding out how to do things is often to look at the <a href="https://golang.org/src/pkg/mime/multipart/">source code</a> and
the <a href="https://golang.org/src/pkg/mime/multipart/multipart_test.go">test suite</a>.</p>
<p>I&rsquo;m not yet super familiar with all the std lib packages, so when I
wanted to test my Go web services, I wrote a few lines of code to create
a multipart file upload function that was building the body from scratch.
Once I was done messing with the various headers, boundary protocol etc..
I started testing some edge cases, I found some bugs in my code.
Looking at Go&rsquo;s packages, I realized that all the tools were already
available for me to use. I was just lacking a good example. Walking
through the test suite I finally figured out how to write a simple
multipart file upload example with some extra query params.</p>
<p>Hopefully this example will be helpful to some of you.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;bytes&#34;</span>
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;io&#34;</span>
	<span style="color:#e6db74">&#34;log&#34;</span>
	<span style="color:#e6db74">&#34;mime/multipart&#34;</span>
	<span style="color:#e6db74">&#34;net/http&#34;</span>
	<span style="color:#e6db74">&#34;os&#34;</span>
	<span style="color:#e6db74">&#34;path/filepath&#34;</span>
)

<span style="color:#75715e">// Creates a new file upload http request with optional extra params
</span><span style="color:#75715e"></span><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">newfileUploadRequest</span>(<span style="color:#a6e22e">uri</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">params</span> <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">paramName</span>, <span style="color:#a6e22e">path</span> <span style="color:#66d9ef">string</span>) (<span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Request</span>, <span style="color:#66d9ef">error</span>) {
	<span style="color:#a6e22e">file</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Open</span>(<span style="color:#a6e22e">path</span>)
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">err</span>
	}
	<span style="color:#66d9ef">defer</span> <span style="color:#a6e22e">file</span>.<span style="color:#a6e22e">Close</span>()

	<span style="color:#a6e22e">body</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">bytes</span>.<span style="color:#a6e22e">Buffer</span>{}
	<span style="color:#a6e22e">writer</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">multipart</span>.<span style="color:#a6e22e">NewWriter</span>(<span style="color:#a6e22e">body</span>)
	<span style="color:#a6e22e">part</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">writer</span>.<span style="color:#a6e22e">CreateFormFile</span>(<span style="color:#a6e22e">paramName</span>, <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Base</span>(<span style="color:#a6e22e">path</span>))
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">err</span>
	}
	<span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">io</span>.<span style="color:#a6e22e">Copy</span>(<span style="color:#a6e22e">part</span>, <span style="color:#a6e22e">file</span>)

	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">key</span>, <span style="color:#a6e22e">val</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">params</span> {
		<span style="color:#a6e22e">_</span> = <span style="color:#a6e22e">writer</span>.<span style="color:#a6e22e">WriteField</span>(<span style="color:#a6e22e">key</span>, <span style="color:#a6e22e">val</span>)
	}
	<span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">writer</span>.<span style="color:#a6e22e">Close</span>()
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>, <span style="color:#a6e22e">err</span>
	}

	<span style="color:#a6e22e">req</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">NewRequest</span>(<span style="color:#e6db74">&#34;POST&#34;</span>, <span style="color:#a6e22e">uri</span>, <span style="color:#a6e22e">body</span>)
	<span style="color:#a6e22e">req</span>.<span style="color:#a6e22e">Header</span>.<span style="color:#a6e22e">Set</span>(<span style="color:#e6db74">&#34;Content-Type&#34;</span>, <span style="color:#a6e22e">writer</span>.<span style="color:#a6e22e">FormDataContentType</span>())
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">req</span>, <span style="color:#a6e22e">err</span>
}

<span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">path</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Getwd</span>()
	<span style="color:#a6e22e">path</span> <span style="color:#f92672">+=</span> <span style="color:#e6db74">&#34;/test.pdf&#34;</span>
	<span style="color:#a6e22e">extraParams</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">map</span>[<span style="color:#66d9ef">string</span>]<span style="color:#66d9ef">string</span>{
		<span style="color:#e6db74">&#34;title&#34;</span>:       <span style="color:#e6db74">&#34;My Document&#34;</span>,
		<span style="color:#e6db74">&#34;author&#34;</span>:      <span style="color:#e6db74">&#34;Matt Aimonetti&#34;</span>,
		<span style="color:#e6db74">&#34;description&#34;</span>: <span style="color:#e6db74">&#34;A document with all the Go programming language secrets&#34;</span>,
	}
	<span style="color:#a6e22e">request</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">newfileUploadRequest</span>(<span style="color:#e6db74">&#34;https://google.com/upload&#34;</span>, <span style="color:#a6e22e">extraParams</span>, <span style="color:#e6db74">&#34;file&#34;</span>, <span style="color:#e6db74">&#34;/tmp/doc.pdf&#34;</span>)
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>)
	}
	<span style="color:#a6e22e">client</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Client</span>{}
	<span style="color:#a6e22e">resp</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">client</span>.<span style="color:#a6e22e">Do</span>(<span style="color:#a6e22e">request</span>)
	<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
		<span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>)
	} <span style="color:#66d9ef">else</span> {
		<span style="color:#a6e22e">body</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">bytes</span>.<span style="color:#a6e22e">Buffer</span>{}
		<span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">body</span>.<span style="color:#a6e22e">ReadFrom</span>(<span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">Body</span>)
    <span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
			<span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>)
		}
    <span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">Body</span>.<span style="color:#a6e22e">Close</span>()
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">StatusCode</span>)
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">Header</span>)
		<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">body</span>)
	}
}
</code></pre></div><p><a href="https://gist.github.com/mattetti/5914158">Example&rsquo;s source code on GitHub</a></p>
<p>All the work is done in the <code>newfileUploadRequest</code> function and
really, the <code>mime/multipart</code> package hides all the complexity of
creating a multipart request.</p>
<p>The key is to set a new <code>multipart.Writer</code>:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">writer</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">multipart</span>.<span style="color:#a6e22e">NewWriter</span>(<span style="color:#a6e22e">body</span>)
</code></pre></div><p>The writer will do all the work and will write directly to our body (which itself is a buffer of bytes).</p>
<p>We then create a part for the file form entry with the name of the file
param and the name of the file (that we extracted using the <code>path/filepath</code>
package).
We need to add the content of the file to the file part, we use the
<code>io.Copy()</code> to do so. In the first version of this article, I had used
<code>io/ioutil</code> <code>Readall</code> to read the content of the file (see code <a href="https://gist.github.com/mattetti/5914158/f4d1393d83ebedc682a3c8e7bdc6b49670083b84">here</a>).
However a few readers rightfully mentioned that I should instead copy
content from the file to the part instead of temporarily loading the content of
the file in memory. <a href="https://play.golang.org/p/eEFBMGMNTW">Here</a> is an
even more optimized version using goroutine to stream the data, and
<a href="https://github.com/gebi/go-fileupload-example/blob/master/main.go">here</a> is the full example using a pipe.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">part</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">writer</span>.<span style="color:#a6e22e">CreateFormFile</span>(<span style="color:#a6e22e">paramName</span>, <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Base</span>(<span style="color:#a6e22e">path</span>))
<span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">err</span> = <span style="color:#a6e22e">io</span>.<span style="color:#a6e22e">Copy</span>(<span style="color:#a6e22e">part</span>, <span style="color:#a6e22e">file</span>)
</code></pre></div><p>The <code>multipart.Writer</code> takes care of setting the boundary and formating
the form data for us, nice isn&rsquo;t it?!</p>
<p>Then for any extra params passed as a map of string keys to string
value, we use another function of the <code>multipart.Writer</code> type:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">writer</span>.<span style="color:#a6e22e">WriteField</span>(<span style="color:#a6e22e">key</span>, <span style="color:#a6e22e">val</span>)
</code></pre></div><p>Once again, the writer takes care of creating the right headers, and to
add the passed value.</p>
<p>At this point, we just need to close our writer and use our body to
create a new request.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">writer</span>.<span style="color:#a6e22e">Close</span>()
<span style="color:#a6e22e">req</span>, <span style="color:#a6e22e">_</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">NewRequest</span>(<span style="color:#e6db74">&#34;POST&#34;</span>, <span style="color:#a6e22e">uri</span>, <span style="color:#a6e22e">body</span>)
</code></pre></div><p>One last thing before triggering our request, we need to set the header
that contains the content type including the boundary being used.
Once again, the Go lib has us covered:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#a6e22e">req</span>.<span style="color:#a6e22e">Header</span>.<span style="color:#a6e22e">Add</span>(<span style="color:#e6db74">&#34;Content-Type&#34;</span>, <span style="color:#a6e22e">writer</span>.<span style="color:#a6e22e">FormDataContentType</span>())
</code></pre></div><p>As a reference, here is the generated body:</p>
<pre><code>--0d940a1e725445cd9192c14c5a3f3d30ea9c90f1f5fb9c08813b3fc2adee
Content-Disposition: form-data; name=&quot;file&quot;; filename=&quot;doc.pdf&quot;
Content-Type: application/octet-stream

%PDF-1.4
%????
4 0 obj
&lt;&lt;/Type /Catalog
// removed for example
trailer
&lt;&lt;/Size 18
/Root 4 0 R
&gt;&gt;
startxref
45054
%%EOF
--0d940a1e725445cd9192c14c5a3f3d30ea9c90f1f5fb9c08813b3fc2adee
Content-Disposition: form-data; name=&quot;title&quot;

My Document
--0d940a1e725445cd9192c14c5a3f3d30ea9c90f1f5fb9c08813b3fc2adee
Content-Disposition: form-data; name=&quot;author&quot;

Matt Aimonetti
--0d940a1e725445cd9192c14c5a3f3d30ea9c90f1f5fb9c08813b3fc2adee
Content-Disposition: form-data; name=&quot;description&quot;

A document with all the Go programming language secrets
--0d940a1e725445cd9192c14c5a3f3d30ea9c90f1f5fb9c08813b3fc2adee--

</code></pre><p>Golang might not be as high level as Ruby or Python, but it&rsquo;s not too
far off and it certainly comes with some great std libs.
I know I recently caught myself writing a lot of small scripts in Go,
something I used to do in Ruby. I think this is mainly due to the
fact that Go is compiled, designed for concurrency, has great std libs and
is quite easy to write.</p>
<p><em>Hopefully this code sample illustrates how easy Go can be and can also
serve as a reference point if you are looking for a way to do multipart
upload.</em></p>
]]></content>
		</item>
		
		<item>
			<title>practical guide to graphite monitoring</title>
			<link>https://matt.aimonetti.net/posts/2013-06-practical-guide-to-graphite-monitoring/</link>
			<pubDate>Wed, 26 Jun 2013 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2013-06-practical-guide-to-graphite-monitoring/</guid>
			<description>Engineers love to improve things. Refactoring and optimizations drive us. There is just a slight problem: we often do that in a vacuum.
Before optimizing, we need to measure.
Without a solid baseline, how can you say that the time you invested in making things better wasn&amp;rsquo;t a total waste?
True refactoring is done with a solid test suite in place. Developers know that their code behavior didn&amp;rsquo;t change while they cleaned things up.</description>
			<content type="html"><![CDATA[<p>Engineers love to improve things. Refactoring and optimizations
drive us. There is just a slight problem: we often do that in a vacuum.</p>
<p>Before optimizing, we need to <strong>measure</strong>.</p>
<p>Without a solid baseline, how can you say that the time you invested in making things better wasn&rsquo;t a total waste?</p>
<p>True refactoring is done with a solid test suite in place. Developers know that their code behavior didn&rsquo;t change while they cleaned things up. Performance optimization is the same thing: we need a good set of metrics before changing anything.</p>
<p>There are plenty of monitoring tools out there, each with its own pros
and cons. The point of this article isn&rsquo;t to argue about which one <strong>you</strong> should use,
but instead to give you the some practical knowledge about <a href="https://graphite.readthedocs.org/en/latest/overview.html">Graphite</a>.</p>
<p><img src="/images/graphite_fullscreen_800.png" alt="Screenshot of the Graphite UI"></p>
<p>Graphite is used to store and render time-series data. In other words,
you collect metrics and Graphite allows you to create pretty graphs easily.</p>
<p>During my time at LivingSocial, I relied on Graphite to
understand trends, issues and optimize performance. As my coworkers
and I were discussing my recently announced departure, I asked them how I
could help them during the transition period. Someone mentioned creating a
Graphite cheatsheet. The cheatsheet turned into something much bigger than I expected
and LivingSocial was nice enough to let me publicly publish this
short guide.</p>
<p><em>For a more in depth dive into the statsd/graphite features, look at
<a href="https://blog.pkhamre.com/2012/07/24/understanding-statsd-and-graphite/">this blog post</a></em></p>
<h2 id="organizing-metrics">Organizing metrics</h2>
<p>There are <a href="https://graphite.readthedocs.org/en/latest/tools.html">many ways</a> to feed Graphite,
I personally used <a href="https://github.com/etsy/statsd/">Etsy&rsquo;s statsd</a> (node.js daemon) which was being fed
via the <a href="https://github.com/reinh/statsd">statsd RubyGem</a>.
The gem allows developers to push recorded metrics to a statsd server
via UDP. Using UDP instead of TCP makes the metrics collection operation
non blocking which means that while you might theoretically lose a few samples, your
instrumented code performance shouldn&rsquo;t be affected. (Read <a href="https://codeascraft.com/2011/02/15/measure-anything-measure-everything/">Etsy&rsquo;s
blog post</a> to know more about
why they chose UDP).</p>
<p>** Tip **: Doing DNS resolution on each call can be a bit expensive (a
few ms), target your statsd server using its ip or use Ruby&rsquo;s <a href="https://www.ruby-doc.org/stdlib-2.0/libdoc/resolv/rdoc/Resolv/DNS.html#method-i-getaddress">resolv</a>
standard library to only do the lookup once at initialization.</p>
<p><strong>Note</strong>: <em>I&rsquo;m skipping the config settings about storage retention, resolution etc.. see the
<a href="https://graphite.readthedocs.org/en/latest/overview.html">manual</a> for more info.</em></p>
<h3 id="namespacing">Namespacing</h3>
<p>Always namespace your collected data, even if you only have one app for
now. If your app does two things at the same time like serving HTML and
providing an API, you might want to create two clients which you would namespace
differently.</p>
<h3 id="naming-metrics">Naming metrics</h3>
<p>Properly naming your metrics is critical to avoid conflicts,
confusing data and potentially wrong interpretation later on.
I like to organize metrics using the following schema:</p>
<pre><code> &lt;namespace&gt;.&lt;instrumented section&gt;.&lt;target (noun)&gt;.&lt;action (past tense verb)&gt;
</code></pre><p>Example:</p>
<pre><code>accounts.authentication.password.attempted
accounts.authentication.password.succeeded
accounts.authentication.password.failed
</code></pre><p>I use nouns to define the target and past tense verbs to define
the action. This becomes a useful convention when you need to nest
metrics. In the above example, let&rsquo;s say I want to monitor the reasons for
the failed password authentications. Here is how I would organize the
extra stats:</p>
<pre><code>accounts.authentication.password.failure.no_email_found
accounts.authentication.password.failure.password_check_failed
accounts.authentication.password.failure.password_reset_required
</code></pre><p>As you can see, I used <code>failure</code> instead of <code>failed</code> in the stat name.
The main reason is to avoid conflicting data. <code>failed</code> is an action and
already has a data series allocated, if I were to add nested data using
<code>failed</code>, the data would be collected but the result would be confusing.
The other reason is because when we will graph the data, we will often
want to use a wildcard <code>*</code> to collect all nested data in a series.</p>
<p>Graphite wild card usage example on counters:</p>
<pre><code>accounts.authentication.password.failure.*
</code></pre><p>This should give us the same value as <code>accounts.authentication.password.failed</code>,
so really, we should just collect the more detailed version and get rid
of <code>accounts.authentication.password.failed</code>.</p>
<p>Following this naming convention should really help your data stay clean and
easy to manage.</p>
<h2 id="counters-and-metrics">Counters and metrics</h2>
<p>StatsD lets you record different types of metrics <a href="https://github.com/etsy/statsd/blob/master/docs/metric_types.md">as illustrated here</a>.</p>
<p>This article will focus on the 2 main types:</p>
<ul>
<li>counters</li>
<li>timers</li>
</ul>
<p>Use counters for metrics when you don&rsquo;t care about how long the code
your are instrumenting takes to run. Usually counters are used for data
that have more of a direct business value. Examples include sales,
authentication, signups, etc.</p>
<p>Timers are more powerful because they can be used to analyze the time
spent in a piece of code but also be used as a counters. Most of my work
involves timers because I want to detect system anomalies including performance
changes and trends in the way code is being used.</p>
<p>I usually use timers in a nested manner, starting when a request
comes into the system, through each of the various
datastores, and ending with the response.</p>
<h2 id="monitoring-response-time">Monitoring response time</h2>
<p>It&rsquo;s a well known fact that the response time of your application will
both affect the user&rsquo;s emotional experience and their likelihood of completing a transactin.
However understanding where time is being spent within a request is
hard, especially when the problems aren&rsquo;t obvious. Tools like
<a href="https://newrelic.com/">NewRelic</a> will often get you a good overview of
how your system behave but they also lack the granularity you might
need. For instance NewRelic aggregates and averageses the data client side
before sending it to their servers. While this is fine in a lot of cases,
if you care about more than averages and want more detailed metrics, you probably need
to run your own solution such as statsd + graphite.</p>
<p>I build most of my web-based APIs on <a href="https://github.com/mattetti/wd-sinatra">wd_sinatra</a> which
has a <code>pre_dispatch_hook</code> method which method is executed before a
request is dispatched.</p>
<p>I use this hook to both set the &ldquo;Stats context&rdquo; in the current thread and extract the client name based on HTTP headers.
If you don&rsquo;t use WD, I&rsquo;ll show how to do the same thing in a
Rack middleware.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">pre_dispatch_hook</span>
  api_client <span style="color:#f92672">=</span> extract_api_client_name(env)
  <span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:stats_context</span><span style="color:#f92672">]</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">#{</span>api_client<span style="color:#e6db74">}</span><span style="color:#e6db74">.http.</span><span style="color:#e6db74">#{</span>env<span style="color:#f92672">[</span><span style="color:#e6db74">&#39;wd.service&#39;</span><span style="color:#f92672">].</span>verb<span style="color:#e6db74">}</span><span style="color:#e6db74">.</span><span style="color:#e6db74">#{</span>env<span style="color:#f92672">[</span><span style="color:#e6db74">&#39;wd.service&#39;</span><span style="color:#f92672">].</span>url<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span><span style="color:#f92672">.</span>gsub(<span style="color:#e6db74">&#39;/&#39;</span>, <span style="color:#e6db74">&#39;.&#39;</span>)
  <span style="color:#75715e"># [...]</span>
<span style="color:#66d9ef">end</span>
</code></pre></div><p>Then using Sinatra&rsquo;s global before/after filters, we set a unique
request id and start a timer that we stop and report in the after filter. If we were using Rails we&rsquo;d get the unique identifier generated automatically.</p>
<p>Before filter:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">require <span style="color:#e6db74">&#39;securerandom&#39;</span>

before <span style="color:#66d9ef">do</span>
  <span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:request_id</span><span style="color:#f92672">]</span> <span style="color:#f92672">=</span> request<span style="color:#f92672">.</span>env<span style="color:#f92672">[</span><span style="color:#e6db74">&#39;HTTP_X_REQUEST_ID&#39;</span><span style="color:#f92672">]</span> <span style="color:#f92672">||</span> <span style="color:#66d9ef">SecureRandom</span><span style="color:#f92672">.</span>hex(<span style="color:#ae81ff">16</span>)
  response<span style="color:#f92672">[</span><span style="color:#e6db74">&#39;X-Request-Id&#39;</span><span style="color:#f92672">]</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:request_id</span><span style="color:#f92672">]</span>
  @instrumentation_start <span style="color:#f92672">=</span> <span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>now
<span style="color:#66d9ef">end</span>
</code></pre></div><p>After filter:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">after <span style="color:#66d9ef">do</span>
  stat <span style="color:#f92672">=</span> (<span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:stats_context</span><span style="color:#f92672">]</span> <span style="color:#f92672">||</span> <span style="color:#e6db74">&#34;http.skipped.</span><span style="color:#e6db74">#{</span>env<span style="color:#f92672">[</span><span style="color:#e6db74">&#34;REQUEST_METHOD&#34;</span><span style="color:#f92672">]</span><span style="color:#e6db74">}</span><span style="color:#e6db74">.</span><span style="color:#e6db74">#{</span>request<span style="color:#f92672">.</span>path_info<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>) <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;.response_time&#34;</span>
  $statsd<span style="color:#f92672">.</span>timing(stat, ((<span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>now <span style="color:#f92672">-</span> @instrumentation_start) <span style="color:#f92672">*</span> <span style="color:#ae81ff">1000</span>)<span style="color:#f92672">.</span>round, <span style="color:#ae81ff">1</span>) <span style="color:#66d9ef">if</span> @instrumentation_start
<span style="color:#66d9ef">end</span>
</code></pre></div><p>Note that this could, and probably <strong>should</strong>, be done in a Rack middleware like this (untested, YMMV):</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#75715e"># require whatever is needed and set statsd</span>

<span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Stats</span>
  <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Middleware</span>

    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">initialize</span>(app)
      @app <span style="color:#f92672">=</span> app
    <span style="color:#66d9ef">end</span>

    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">call</span>(env)
      request <span style="color:#f92672">=</span> <span style="color:#66d9ef">Rack</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Request</span><span style="color:#f92672">.</span>new(env)
      <span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:request_id</span><span style="color:#f92672">]</span> <span style="color:#f92672">=</span> request<span style="color:#f92672">.</span>env<span style="color:#f92672">[</span><span style="color:#e6db74">&#39;HTTP_X_REQUEST_ID&#39;</span><span style="color:#f92672">]</span> <span style="color:#f92672">||</span> <span style="color:#66d9ef">SecureRandom</span><span style="color:#f92672">.</span>hex(<span style="color:#ae81ff">16</span>)
      response<span style="color:#f92672">[</span><span style="color:#e6db74">&#39;X-Request-Id&#39;</span><span style="color:#f92672">]</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:request_id</span><span style="color:#f92672">]</span>
      api_client <span style="color:#f92672">=</span> extract_api_client_name(env)
      <span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:stats_context</span><span style="color:#f92672">]</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">#{</span>api_client<span style="color:#e6db74">}</span><span style="color:#e6db74">.http.</span><span style="color:#e6db74">#{</span>request<span style="color:#f92672">.</span>request_method<span style="color:#e6db74">}</span><span style="color:#e6db74">.</span><span style="color:#e6db74">#{</span>request<span style="color:#f92672">.</span>path_info<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span><span style="color:#f92672">.</span>gsub(<span style="color:#e6db74">&#39;/&#39;</span>, <span style="color:#e6db74">&#39;.&#39;</span>)
      @instrumentation_start <span style="color:#f92672">=</span> <span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>now

      response <span style="color:#f92672">=</span> @app<span style="color:#f92672">.</span>call(env)

      stat <span style="color:#f92672">=</span> (<span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:stats_context</span><span style="color:#f92672">]</span> <span style="color:#f92672">||</span> <span style="color:#e6db74">&#34;http.skipped.</span><span style="color:#e6db74">#{</span>env<span style="color:#f92672">[</span><span style="color:#e6db74">&#34;REQUEST_METHOD&#34;</span><span style="color:#f92672">]</span><span style="color:#e6db74">}</span><span style="color:#e6db74">.</span><span style="color:#e6db74">#{</span>request<span style="color:#f92672">.</span>path_info<span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>) <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;.response_time&#34;</span>
      $statsd<span style="color:#f92672">.</span>timing(stat, ((<span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>now <span style="color:#f92672">-</span> @instrumentation_start) <span style="color:#f92672">*</span> <span style="color:#ae81ff">1000</span>)<span style="color:#f92672">.</span>round, <span style="color:#ae81ff">1</span>) <span style="color:#66d9ef">if</span> @instrumentation_start
      response
    <span style="color:#66d9ef">end</span>

  <span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">end</span>
</code></pre></div><p>Note that the stats are organized slightly differently and will read
like that:</p>
<pre><code>&lt;namespace&gt;.&lt;client name&gt;.http.&lt;http verb&gt;.&lt;path&gt;.&lt;segments&gt;.response_time
</code></pre><p>The dots in the stats name will be used to create subfolders in graphite.
By using such a segmented stats name, we will be able to use <code>*</code>
wildcards to analyze how an old version of an API compares against a
newer one, which clients still talk to the old APIs, compare response
times, etc.</p>
<h2 id="monitor-time-spent-within-a-response">Monitor time spent within a response</h2>
<p>We&rsquo;re collecting stats on every request so
we can see request counts and median average response times.
But wouldn&rsquo;t be better if we could measure the time spent in specific
parts of our code base and compare that to the overall time spent in the
request?</p>
<p>We could, for instance, compare the time spent in the DB vs Redis
vs Memcached vs the framework. And what&rsquo;s nice is that we could do that
per API endpoint and per API client. In a simpler case, you might decide to monitor mobile vs desktop. The principle is the same.</p>
<p>Let&rsquo;s hook into ActiveRecord&rsquo;s query generation to track the time spent
in AR within each request:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">module</span> MysqlStats
  <span style="color:#66d9ef">module</span> Instrumentation
    <span style="color:#66d9ef">SQL_INSERT_DELETE_PARSER_REGEXP</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">/^(\w+)\s(\w+)\s\W*(\w+)/</span>
    <span style="color:#66d9ef">SQL_SELECT_REGEXP</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">/select .*? FROM \W*(\w+)/i</span>
    <span style="color:#66d9ef">SQL_UPDATE_REGEXP</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">/update \W*(\w+)/i</span>

    <span style="color:#75715e"># Returns the table and query type</span>
    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">self</span><span style="color:#f92672">.</span><span style="color:#a6e22e">extract_from_sql_inserts_deletes</span>(query)
      query <span style="color:#f92672">=~</span> <span style="color:#66d9ef">SQL_INSERT_DELETE_PARSER_REGEXP</span>
      <span style="color:#f92672">[</span>$3, $1<span style="color:#f92672">]</span>
    <span style="color:#66d9ef">end</span>

    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">self</span><span style="color:#f92672">.</span><span style="color:#a6e22e">extract_sql_selects</span>(query)
      query <span style="color:#f92672">=~</span> <span style="color:#66d9ef">SQL_SELECT_REGEXP</span>
      <span style="color:#f92672">[</span>$1, <span style="color:#e6db74">&#39;SELECT&#39;</span><span style="color:#f92672">]</span>
    <span style="color:#66d9ef">end</span>

    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">self</span><span style="color:#f92672">.</span><span style="color:#a6e22e">guess_sql_content</span>(query)
      <span style="color:#66d9ef">if</span> query <span style="color:#f92672">=~</span> <span style="color:#66d9ef">SQL_UPDATE_REGEXP</span>
        <span style="color:#f92672">[</span>$1, <span style="color:#e6db74">&#39;UPDATE&#39;</span><span style="color:#f92672">]</span>
      <span style="color:#66d9ef">elsif</span> query <span style="color:#f92672">=~</span> <span style="color:#66d9ef">SQL_SELECT_REGEXP</span>
        extract_sql_selects(query)
      <span style="color:#66d9ef">end</span>
    <span style="color:#66d9ef">end</span>
  <span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">end</span>

<span style="color:#66d9ef">ActiveSupport</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Notifications</span><span style="color:#f92672">.</span>subscribe <span style="color:#e6db74">&#34;sql.active_record&#34;</span> <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>name, start, finish, id, payload<span style="color:#f92672">|</span>
  <span style="color:#66d9ef">if</span> payload<span style="color:#f92672">[</span><span style="color:#e6db74">:name</span><span style="color:#f92672">]</span> <span style="color:#f92672">==</span> <span style="color:#e6db74">&#34;SQL&#34;</span>
    table, action <span style="color:#f92672">=</span> <span style="color:#66d9ef">MysqlStats</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Instrumentation</span><span style="color:#f92672">.</span>extract_from_sql_inserts_deletes(payload<span style="color:#f92672">[</span><span style="color:#e6db74">:sql</span><span style="color:#f92672">]</span>)
  <span style="color:#66d9ef">elsif</span> payload<span style="color:#f92672">[</span><span style="color:#e6db74">:name</span><span style="color:#f92672">]</span> <span style="color:#f92672">=~</span> <span style="color:#e6db74">/.* Load$/</span>
    table, action <span style="color:#f92672">=</span> <span style="color:#66d9ef">MysqlStats</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Instrumentation</span><span style="color:#f92672">.</span>extract_sql_selects(payload<span style="color:#f92672">[</span><span style="color:#e6db74">:sql</span><span style="color:#f92672">]</span>)
  <span style="color:#66d9ef">elsif</span> <span style="color:#f92672">!</span>payload<span style="color:#f92672">[</span><span style="color:#e6db74">:name</span><span style="color:#f92672">]</span>
    table, action <span style="color:#f92672">=</span> <span style="color:#66d9ef">MysqlStats</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Instrumentation</span><span style="color:#f92672">.</span>guess_sql_content(payload<span style="color:#f92672">[</span><span style="color:#e6db74">:sql</span><span style="color:#f92672">]</span>)
  <span style="color:#66d9ef">end</span>

  <span style="color:#66d9ef">if</span> table
    $statsd<span style="color:#f92672">.</span>timing(<span style="color:#e6db74">&#34;</span><span style="color:#e6db74">#{</span><span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:stats_context</span><span style="color:#f92672">]</span> <span style="color:#f92672">||</span> <span style="color:#e6db74">&#39;wild&#39;</span><span style="color:#e6db74">}</span><span style="color:#e6db74">.sql.</span><span style="color:#e6db74">#{</span>table<span style="color:#e6db74">}</span><span style="color:#e6db74">.</span><span style="color:#e6db74">#{</span>action<span style="color:#e6db74">}</span><span style="color:#e6db74">.query_time&#34;</span>,
                        (finish <span style="color:#f92672">-</span> start) <span style="color:#f92672">*</span> <span style="color:#ae81ff">1000</span>, <span style="color:#ae81ff">1</span>)

  <span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">end</span>
</code></pre></div><p>This code might not be pretty but it works (<em>or should work</em>).
We subscribe to <code>ActiveSupport::Notifications</code> for <code>sql.active_record</code>
and we extract the info we need. Then we use the stats context set in
the thread and report the stats by appending
<code>.sql.#{table}.#{action}.query_time</code></p>
<p>The final stats entry could look like this:
<code>auth_api.ios.http.post.v1.accounts.sql.users.SELECT.query_time</code></p>
<ul>
<li><strong>auth_api</strong>: the name of the monitored app</li>
<li><strong>ios</strong>: the client name</li>
<li><strong>http</strong>: the protocol used (you might want to monitor thrift, spdy etc..</li>
<li><strong>post</strong>: HTTP verb</li>
<li><strong>v1.accounts</strong>: the converted uri: /v1/accounts</li>
<li><strong>sql</strong>: the key for the SQL metrics</li>
<li><strong>users</strong>: the table being queried</li>
<li><strong>SELECT</strong>: the SQL query type</li>
<li><strong>query_time</strong>: the kind of data being collected.</li>
</ul>
<p>As you can see, we are getting granular data. Depending on how you setup
statsd/graphite, you could have access to the following timer data for
each stat (and more):</p>
<ul>
<li>count</li>
<li>lower</li>
<li>mean</li>
<li>mean_5</li>
<li>mean_10</li>
<li>mean_90</li>
<li>mean_95</li>
<li>median</li>
<li>sum</li>
<li>upper</li>
<li>upper_5</li>
<li>upper_10</li>
<li>upper_90</li>
<li>upper_95</li>
</ul>
<p>Instrumenting Redis is easy too:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#f92672">::</span><span style="color:#66d9ef">Redis</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Client</span><span style="color:#f92672">.</span>class_eval <span style="color:#66d9ef">do</span>

  <span style="color:#75715e"># Support older versions of Redis::Client that used the method</span>
  <span style="color:#75715e"># +raw_call_command+.</span>
  call_method <span style="color:#f92672">=</span> <span style="color:#f92672">::</span><span style="color:#66d9ef">Redis</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Client</span><span style="color:#f92672">.</span>new<span style="color:#f92672">.</span>respond_to?(<span style="color:#e6db74">:call</span>) ? <span style="color:#e6db74">:call</span> : <span style="color:#e6db74">:raw_call_command</span>

  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">call_with_stats_trace</span>(<span style="color:#f92672">*</span>args, <span style="color:#f92672">&amp;</span>blk)
    method_name <span style="color:#f92672">=</span> args<span style="color:#f92672">[</span><span style="color:#ae81ff">0</span><span style="color:#f92672">].</span>is_a?(Array) ? args<span style="color:#f92672">[</span><span style="color:#ae81ff">0</span><span style="color:#f92672">][</span><span style="color:#ae81ff">0</span><span style="color:#f92672">]</span> : args<span style="color:#f92672">[</span><span style="color:#ae81ff">0</span><span style="color:#f92672">]</span>
    start <span style="color:#f92672">=</span> <span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>now
    <span style="color:#66d9ef">begin</span>
      call_without_stats_trace(<span style="color:#f92672">*</span>args, <span style="color:#f92672">&amp;</span>blk)
    <span style="color:#66d9ef">ensure</span>
      <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:stats_context</span><span style="color:#f92672">]</span>
        $statsd<span style="color:#f92672">.</span>timing(<span style="color:#e6db74">&#34;</span><span style="color:#e6db74">#{</span><span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:stats_context</span><span style="color:#f92672">]</span><span style="color:#e6db74">}</span><span style="color:#e6db74">.redis.</span><span style="color:#e6db74">#{</span>method_name<span style="color:#f92672">.</span>to_s<span style="color:#f92672">.</span>upcase<span style="color:#e6db74">}</span><span style="color:#e6db74">.query_time&#34;</span>,
                         ((<span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>now <span style="color:#f92672">-</span> start) <span style="color:#f92672">*</span> <span style="color:#ae81ff">1000</span>)<span style="color:#f92672">.</span>round, <span style="color:#ae81ff">1</span>) <span style="color:#66d9ef">rescue</span> <span style="color:#66d9ef">nil</span>
      <span style="color:#66d9ef">end</span>
    <span style="color:#66d9ef">end</span>
  <span style="color:#66d9ef">end</span>

  alias_method <span style="color:#e6db74">:call_without_stats_trace</span>, call_method
  alias_method call_method, <span style="color:#e6db74">:call_with_stats_trace</span>

<span style="color:#66d9ef">end</span> <span style="color:#66d9ef">if</span> defined?(<span style="color:#f92672">::</span><span style="color:#66d9ef">Redis</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Client</span>)
</code></pre></div><p>Using Ruby&rsquo;s alias method chain, we inject
our instrumentation into the Redis client so we can track the time spent
there.</p>
<p>Applying the same approach, we can instrument the Ruby <strong>memcached</strong> gem:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#f92672">::</span><span style="color:#66d9ef">Memcached</span><span style="color:#f92672">.</span>class_eval <span style="color:#66d9ef">do</span>

  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">get_with_stats_trace</span>(keys, marshal<span style="color:#f92672">=</span><span style="color:#66d9ef">true</span>)
    start <span style="color:#f92672">=</span> <span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>now
    <span style="color:#66d9ef">begin</span>
      get_without_stats_trace(keys, marshal)
    <span style="color:#66d9ef">ensure</span>
      <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:stats_context</span><span style="color:#f92672">]</span>
        type <span style="color:#f92672">=</span> keys<span style="color:#f92672">.</span>is_a?(Array) ? <span style="color:#e6db74">&#34;multi_get&#34;</span> : <span style="color:#e6db74">&#34;get&#34;</span>
        $statsd<span style="color:#f92672">.</span>timing(<span style="color:#e6db74">&#34;</span><span style="color:#e6db74">#{</span><span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>current<span style="color:#f92672">[</span><span style="color:#e6db74">:stats_context</span><span style="color:#f92672">]</span><span style="color:#e6db74">}</span><span style="color:#e6db74">.memcached.</span><span style="color:#e6db74">#{</span>type<span style="color:#e6db74">}</span><span style="color:#e6db74">.query_time&#34;</span>,
                         ((<span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>now <span style="color:#f92672">-</span> start) <span style="color:#f92672">*</span> <span style="color:#ae81ff">1000</span>)<span style="color:#f92672">.</span>round, <span style="color:#ae81ff">1</span>) <span style="color:#66d9ef">rescue</span> <span style="color:#66d9ef">nil</span>
      <span style="color:#66d9ef">end</span>
    <span style="color:#66d9ef">end</span>
  <span style="color:#66d9ef">end</span>

  alias_method <span style="color:#e6db74">:get_without_stats_trace</span>, <span style="color:#e6db74">:get</span>
  alias_method <span style="color:#e6db74">:get</span>, <span style="color:#e6db74">:get_with_stats_trace</span>

<span style="color:#66d9ef">end</span> <span style="color:#66d9ef">if</span> defined?(<span style="color:#f92672">::</span><span style="color:#66d9ef">Memcached</span>)
</code></pre></div><h2 id="dashboards">Dashboards</h2>
<p>We now have collected and organized our stats. Let&rsquo;s talk about how to
use Graphite to display all this data in a valuable way.</p>
<p>When looking at timer data series, the first thing we want to do is create an overall represention. Your first inclination is probably an <em>average</em>.</p>
<p>The problem with the mean is that it&rsquo;s the sum of all data
points divided by the number of data points. It can thus be significantly affected by a small number of outliers.</p>
<p>The median value is the number found in the center of the sorted list of
collected data points. The problem in this case is that based on your
data set, the median value might not well represent the real overall
experience.</p>
<p>Neither <strong>median</strong> nor <strong>mean</strong> can summarize the whole story of your system&rsquo;s behavior.
Instead I prefer to use a <strong>5-95 span</strong> (thanks <a href="https://steveakers.com/">Steve
Akers</a> for showing me this metric and most of what I
know about Graphite).
A 5-95 span means that we cut off the extreme outliers above 95% and below 5%.</p>
<h3 id="span">Span</h3>
<p>Here is a comparison showing how the graphs can be different for the same
data based on what metric you use:</p>
<p><img src="/images/graphite/graphite-median_vs_mean_vs_span.png" alt="Graphite comparing median vs mean vs span"></p>
<p>Of course the span graph looks much worse than the other two, but it&rsquo;s
also more representative of the real user experience and thus more
valuable. Here is how you would write the graphite function to get this data.</p>
<p>Given that we are tracking the following data-series:</p>
<pre><code>stats.timers.accounts.ios.http.post.authenticate.response_time
</code></pre><p>The function would be:</p>
<pre><code>diffSeries(stats.timers.accounts.ios.http.post.authenticate.response_time.upper_95,
           stats.timers.accounts.ios.http.post.authenticate.response_time.upper_5)
</code></pre><h3 id="alias">Alias</h3>
<p>If you try that function, the graph legend will show the entire
function, which really doesn&rsquo;t look great. To simplify things, you can use an
alias like I did in the graph above:</p>
<pre><code>alias(diffSeries(stats.timers.accounts.ios.http.post.authenticate.response_time.upper_95,
                 stats.timers.accounts.ios.http.post.authenticate.response_time.upper_5),
      &quot;iOS authentication response time (span)&quot;)
</code></pre><p>Aliases are very useful, especially when you share your dashboards with
others.</p>
<h3 id="threshold">Threshold</h3>
<p>Another neat feature you might add to your graph is a <strong>threshold</strong>.
A threshold is a visual representation of expectations. Say, for example, that your web service shouldn&rsquo;t be slower than 60ms server side. Let&rsquo;s add a threshold for that:</p>
<pre><code>alias(threshold(60), &quot;60ms threshold&quot;)
</code></pre><p>and here&rsquo;s how it would look in a graph:</p>
<p><img src="/images/graphite/graphite-median_vs_mean_vs_span-with-threshold.png" alt="Graphite with a threshold"></p>
<h3 id="draw-null-as-zero">Draw Null as Zero</h3>
<p>Another useful trick is to change the render options of a
graph to draw null values as zero.
Open the graph panel, click on <code>Render Options</code>, then <code>Line Mode</code> and check
the <code>Draw Null as Zero</code> box.</p>
<p>Here is a graph tracking a webservice that isn&rsquo;t getting a lot of
traffic:</p>
<p><img src="/images/graphite/nulls_not_drawn_as_zero.png" alt="graphite example"></p>
<p>You can see that the line is discontinued, that&rsquo;s because the API
doesn&rsquo;t constantly receive traffic. If your data series gets only very
few entries, you might not even see a line. This is why you want to
enable the <code>Draw Null as Zero</code>.</p>
<h3 id="sumseries--summarize-or-how-to-get-rpms">SumSeries &amp; Summarize or how to get RPMs</h3>
<p>By default graphite shows data at a 10 second interval. But often
you want to see less granular data, like the quantity of requests
per second.</p>
<p>Let&rsquo;s say we didn&rsquo;t use a counter for the amount of requests, but
because we used the middleware I described earlier, we are timing all
responses. Graphite keeps a count of the timers we used, so we can use
this count value with a wildcard:</p>
<pre><code>stats.timers.accounts.*.http.post.authenticate.response_time.count
</code></pre><p>If we were to render a graph for this stat we would see a graph per
client. Right now we only care about showing the total amount of requests.
To do that, we&rsquo;ll use the <code>sumSeries</code> function:</p>
<pre><code>sumSeries(stats.timers.accounts.*.http.post.authenticate.response_time.count)
</code></pre><p><img src="/images/graphite/graphite-not-summarized.png" alt="RPMs not summarized"></p>
<p>The graph looks pretty but it&rsquo;s hard to understand what kind of request
volume we are getting. We can summarize this data to show 1 min
summaries instead:</p>
<pre><code>summarize(sumSeries(stats.timers.accounts.*.http.post.authenticate.response_time.count), &quot;1min&quot;)
</code></pre><p><img src="/images/graphite/graphite-summarize.png" alt="RPMs summarize"></p>
<p>We can now see the quantity of requests per minute. You could do the same to resolve by hour, day, etc.</p>
<h3 id="timeshift">Timeshift</h3>
<p>Graphite has the ability to compare a given metric across two different time spans. For instance, let&rsquo;s compare
today&rsquo;s quantity of logins vs those from last weeks.</p>
<p>To generate today&rsquo;s graph:</p>
<pre><code>alias(summarize(sumSeries(stats.timers.accounts.*.http.post.authenticate.response_time.count),&quot;1min&quot;), &quot;today&quot;)
</code></pre><p>Then we use the <code>timeShift</code> function to get last week&rsquo;s data:</p>
<pre><code>alias(timeShift(summarize(sumSeries(stats.timers.accounts.*.http.post.authenticate.response_time.count), &quot;1min&quot;),&quot;1w&quot;), &quot;last week&quot;)
</code></pre><p>Graphing both series in the same graph will give us that:</p>
<p><img src="/images/graphite/graphite-timeshift.png" alt="graphite timeshift example"></p>
<p>Wow, it looks like last week we had an authentication peek for a few
hours. Why? It would be interesting to graph our promos and sales in the same
graph to see if we can find any correlations.</p>
<p>Depending on your domain, you might want to compare against different
time slices. Just change the second <code>timeShift</code> argument.</p>
<h3 id="as-percent">As percent</h3>
<p>Another technique is to compare the percentage growth since last week.
Let&rsquo;s imagine we are looking at sales or signup numbers.
We could graph today&rsquo;s sales per minute vs those from last week.</p>
<p>To do that, Graphite has the <code>asPercent</code> function. This function
takes a series representing <em>100%</em> and second to compare against.
The function call looks a bit scary so let me try to break it down over
multiple lines:</p>
<pre><code>asPercent(
  summarize(sumSeries(stats.timers.accounts.*.http.post.accounts.response_time.count),&quot;1min&quot;)
  ,timeShift(summarize(sumSeries(stats.timers.accounts.*.http.post.accounts.response_time.count), &quot;1min&quot;),&quot;1w&quot;)
)
</code></pre><p>The first argument is the summarized RPMs (requests per minute) and the
second is last week&rsquo;s summarized RPMs.</p>
<p>Here is how the graph looks:</p>
<p><img src="/images/graphite/graphite-compare-as-percent.png" alt="graphite as percent"></p>
<p>Based on all the data we collect, we can now graph something like that:</p>
<p><img src="/images/graphite/graphite-as-percent.png" alt="graphite as percent with multiple series"></p>
<p>This graph is basically the same as the one above, but we used the
overall response time as the 100% value and we graphed all the different
monitored sections of our code base.</p>
<p>You can now build some really advanced tools that look at trends,
check pre- and post-deployment measurements, trigger alerts, and help you refactor your
code.</p>
<p>Maybe you suspect that your app has a chokepoint at the database level.
You can track the query types and the targeted tables per API
endpoint. You can see where you spend most of the time and which code path
is responsible for it. You can quickly see if adding indicies or other database-level techniques actually make a difference.</p>
<h2 id="other-tips">Other tips</h2>
<h3 id="share-a-url-into-campfireirc-and-see-a-preview">Share a url into campfire/irc and see a preview</h3>
<p>Campfire and many other chat tools offer image preview as long as they
detect that the url has an image extension. Unfortunately, Graphite&rsquo;s
graph urls look more like this:</p>
<pre><code>https://graphite.awesome.graphs.com/render?width=400&amp;from=-4hours&amp;until=-&amp;height=400&amp;target=summarize(sumSeries(stats.timers.accounts.*.http.post.accounts.response_time.count))&amp;drawNullAsZero=true&amp;title=Example&amp;_uniq=0.11944825737737119
</code></pre><p>To get a preview, just append the with: <code>&amp;.jpg</code></p>
<h3 id="get-the-graph-data-in-json-format">Get the graph data in JSON format</h3>
<p>You might want to do something fancy with the data like
create alerts. For that you can ask Graphite for a json representation
of the data by adding <code>&amp;format=json</code> to the URL.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-json" data-lang="json">[
 {<span style="color:#f92672">&#34;target&#34;</span>:
  <span style="color:#e6db74">&#34;summarize(sumSeries(stats.timers.accounts.*.http.post.accounts.response_time.count))&#34;</span>,
  <span style="color:#f92672">&#34;datapoints&#34;</span>: [
    [<span style="color:#ae81ff">20260.0</span>, <span style="color:#ae81ff">137256960</span>],[<span style="color:#ae81ff">19513</span>, <span style="color:#ae81ff">1372357020</span>] <span style="color:#960050;background-color:#1e0010">//</span>[<span style="color:#960050;background-color:#1e0010">...</span>]
   ]
  }
]
</code></pre></div><p>The data points are the timestamped value of each graphed point.
Note that you can also ask for the CSV version of the data then pass it on to some poor bastard using Excel.</p>
<h3 id="only-show-top-graphs">Only show top graphs</h3>
<p>Let say that you are graphing the response time of all your APIs. The
amount of displayed graphs can be overwhelming.</p>
<p>To limit the displayed graphs, use one of the filters. For instance the <code>currentAbove</code> or
<code>averageAbove</code> filters that can help you only display web services with
more than X RPMs for instance. Using filters can be very useful to find
outliers.</p>
<h2 id="get-going-with-graphite">Get going with Graphite!</h2>
<p>Hopefully this guide will help and inspire you to start using Graphite to easily collect and analyze your metrics.
I&rsquo;m sure there are great tricks I forgot to mention, please add your favorites in the comments.</p>
<p><em>Thanks to <a href="https://twitter.com/j3">Jeff Casimir</a> for reviewing this post
before its publication!</em></p>
]]></content>
		</item>
		
		<item>
			<title>using go vs ruby for web apis</title>
			<link>https://matt.aimonetti.net/posts/2013-06-using-go-vs-ruby-for-web-apis/</link>
			<pubDate>Sun, 23 Jun 2013 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2013-06-using-go-vs-ruby-for-web-apis/</guid>
			<description>A few days ago, I was wondering if using Go would be worth it when developing new web APIs. I obviously knew that Go would be faster than Ruby, but I wasn&amp;rsquo;t sure how much faster. I also wondering about the amount of work required to write get a full API implemented.
I therefore wrote the same web API in Ruby (using Rails) and in Go (at first using Revel and then rewriting it without a framework since Go&amp;rsquo;s std lib have everything one might need).</description>
			<content type="html"><![CDATA[<p>A few days ago, I was wondering if using <a href="https://golang.org/">Go</a> would be worth it when developing new web APIs.
I obviously knew that Go would be faster than Ruby, but I wasn&rsquo;t sure
how much faster. I also wondering about the amount of work required to
write get a full API implemented.</p>
<p>I therefore wrote the same web API in Ruby (using Rails) and in Go (at
first using Revel and then rewriting it without a framework since Go&rsquo;s
std lib have everything one might need).
The API spec was simple:</p>
<ul>
<li>extract an authorization token contained in the request header</li>
<li>use the token to query a MySQL database</li>
<li>respond by sending back the MySQL row in json format</li>
<li>return 401 if the token isn&rsquo;t value</li>
</ul>
<p>I didn&rsquo;t try to optimize the Ruby code, nor the Go code. The idea wasn&rsquo;t
to get precise benchmark results, the goal was to get an idea of how
much faster Go was in a real life situation. The other goal was to
evaluate the amount of work needed to write web APIs in Go for someone
who already knows the language.</p>
<p>At the end of the day the API implemented in Go is more than 50x faster than
the Ruby version. Interesting enough, writing the code and tests for the
Go API was pretty close to the Ruby experience (more on that later).
50X performance gain, including high concurrency support might be a very
good argument to start using some Go when it makes sense.</p>
<p>I documented my experiment on <a href="https://plus.google.com/101114877505962271216/posts/PeZk8FY3PWY">Google+</a>, click the following screenshot to read more.</p>
<p><a href="https://plus.google.com/101114877505962271216/posts/PeZk8FY3PWY"><img src="/images/matt_aimonetti-golang_vs_ruby_api_exp.png" alt="Matt Aimonetti&rsquo;s Go vs Ruby post on Google+"></a></p>
]]></content>
		</item>
		
		<item>
			<title>inspecting rails 4 request dispatch using ruby 2 dot 0</title>
			<link>https://matt.aimonetti.net/posts/2013-03-inspecting-rails-4-request-dispatch-using-ruby-2-dot-0/</link>
			<pubDate>Tue, 05 Mar 2013 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2013-03-inspecting-rails-4-request-dispatch-using-ruby-2-dot-0/</guid>
			<description>Ruby 2.0 has a cool new feature that many people talk about: TracePoint.
TracePoint essentially allows you to hook into Ruby&amp;rsquo;s events and listen for events.
Being curious and since I just started a brand new Rails 4/Ruby 2 app, I decided to write a little middleware and see what Rails is up to when handling incoming requests.
Here is my TracePoint Rack Middleware.
class TracePoint class Middleware def initialize(app) @app = app end def call(env) stats = {} trace = TracePoint.</description>
			<content type="html"><![CDATA[<p>Ruby 2.0 has a cool new feature that many people talk about:
<a href="https://ruby-doc.org/core-2.0/TracePoint.html">TracePoint</a>.</p>
<p><code>TracePoint</code> essentially allows you to hook into Ruby&rsquo;s events and
listen for events.</p>
<p>Being curious and since I just started a brand new Rails 4/Ruby 2 app, I
decided to write a little middleware and see what Rails is up to when
handling incoming requests.</p>
<p>Here is my <a href="https://gist.github.com/mattetti/5097206">TracePoint Rack Middleware</a>.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">TracePoint</span>
  <span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Middleware</span>

    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">initialize</span>(app)
      @app <span style="color:#f92672">=</span> app
    <span style="color:#66d9ef">end</span>

    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">call</span>(env)
      stats <span style="color:#f92672">=</span> {}
      trace <span style="color:#f92672">=</span> <span style="color:#66d9ef">TracePoint</span><span style="color:#f92672">.</span>new(<span style="color:#e6db74">:call</span>) <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>tp<span style="color:#f92672">|</span>
        stats<span style="color:#f92672">[</span>tp<span style="color:#f92672">.</span>defined_class<span style="color:#f92672">]</span> <span style="color:#f92672">||=</span> {}
        stats<span style="color:#f92672">[</span>tp<span style="color:#f92672">.</span>defined_class<span style="color:#f92672">][</span>tp<span style="color:#f92672">.</span>method_id<span style="color:#f92672">]</span> <span style="color:#f92672">||=</span> <span style="color:#ae81ff">0</span>
        stats<span style="color:#f92672">[</span>tp<span style="color:#f92672">.</span>defined_class<span style="color:#f92672">][</span>tp<span style="color:#f92672">.</span>method_id<span style="color:#f92672">]</span> <span style="color:#f92672">+=</span> <span style="color:#ae81ff">1</span>
      <span style="color:#66d9ef">end</span>
      trace<span style="color:#f92672">.</span>enable
      response <span style="color:#f92672">=</span> @app<span style="color:#f92672">.</span>call(env)
      trace<span style="color:#f92672">.</span>disable

      puts <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">#{</span>stats<span style="color:#f92672">.</span>keys<span style="color:#f92672">.</span>size<span style="color:#e6db74">}</span><span style="color:#e6db74"> classes used&#34;</span>
      puts <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">#{</span>stats<span style="color:#f92672">.</span>map<span style="color:#e6db74">{</span><span style="color:#f92672">|</span>k,v<span style="color:#f92672">|</span> v<span style="color:#f92672">.</span>keys<span style="color:#e6db74">}</span><span style="color:#f92672">.</span>flatten<span style="color:#f92672">.</span>size<span style="color:#e6db74">}</span><span style="color:#e6db74"> methods used&#34;</span>
      puts <span style="color:#e6db74">&#34;</span><span style="color:#e6db74">#{</span>stats<span style="color:#f92672">.</span>map<span style="color:#e6db74">{</span><span style="color:#f92672">|</span>k,v<span style="color:#f92672">|</span> v<span style="color:#f92672">.</span>values<span style="color:#e6db74">}</span><span style="color:#f92672">.</span>flatten<span style="color:#f92672">.</span>sum<span style="color:#e6db74">}</span><span style="color:#e6db74"> methods dispatched&#34;</span>
      response
    <span style="color:#66d9ef">end</span>

  <span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">end</span>
</code></pre></div><p>(the gist shows a modified version so I could dump to disk the json
representation of the calls)</p>
<p>I then inserted the middleware in Rails:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#75715e"># in application.rb</span>
config<span style="color:#f92672">.</span>middleware<span style="color:#f92672">.</span>insert_before(<span style="color:#66d9ef">ActionDispatch</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Static</span>, <span style="color:#66d9ef">TracePoint</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Middleware</span>)
</code></pre></div><p>I saved the output in json format for the curious: <a href="https://gist.github.com/mattetti/5097178">click here</a></p>
<p>On average, in production mode, using Ruby 2.0 and Puma on my laptop, my hello world index page takes 5ms.</p>
<p>To render my page, Rails uses (more or less):</p>
<ul>
<li>250 classes</li>
<li>750 methods (not including C functions)</li>
<li>and dispatches 2704 methods (not including calls to C functions)</li>
</ul>
<p>Here is a small selection of some of the methods dispatched:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-json" data-lang="json"><span style="color:#e6db74">&#34;String&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> {
    <span style="color:#f92672">&#34;underscore&#34;</span>: <span style="color:#ae81ff">1</span>,
    <span style="color:#f92672">&#34;blank?&#34;</span>: <span style="color:#ae81ff">14</span>,
    <span style="color:#f92672">&#34;html_safe&#34;</span>: <span style="color:#ae81ff">78</span>
  }<span style="color:#960050;background-color:#1e0010">,</span>
<span style="color:#e6db74">&#34;ActiveSupport::Inflector&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> {
  <span style="color:#f92672">&#34;underscore&#34;</span>: <span style="color:#ae81ff">2</span>,
  <span style="color:#f92672">&#34;inflections&#34;</span>: <span style="color:#ae81ff">2</span>
}<span style="color:#960050;background-color:#1e0010">,</span>
<span style="color:#e6db74">&#34;Hash&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> {
  <span style="color:#f92672">&#34;with_indifferent_access&#34;</span>: <span style="color:#ae81ff">2</span>,
  <span style="color:#f92672">&#34;except&#34;</span>: <span style="color:#ae81ff">1</span>,
  <span style="color:#f92672">&#34;except!&#34;</span>: <span style="color:#ae81ff">1</span>,
  <span style="color:#f92672">&#34;stringify_keys&#34;</span>: <span style="color:#ae81ff">5</span>,
  <span style="color:#f92672">&#34;transform_keys&#34;</span>: <span style="color:#ae81ff">13</span>,
  <span style="color:#f92672">&#34;stringify_keys!&#34;</span>: <span style="color:#ae81ff">1</span>,
  <span style="color:#f92672">&#34;transform_keys!&#34;</span>: <span style="color:#ae81ff">3</span>,
  <span style="color:#f92672">&#34;extractable_options?&#34;</span>: <span style="color:#ae81ff">4</span>,
  <span style="color:#f92672">&#34;extract!&#34;</span>: <span style="color:#ae81ff">2</span>,
  <span style="color:#f92672">&#34;symbolize_keys&#34;</span>: <span style="color:#ae81ff">8</span>,
  <span style="color:#f92672">&#34;reverse_merge&#34;</span>: <span style="color:#ae81ff">1</span>,
  <span style="color:#f92672">&#34;slice&#34;</span>: <span style="color:#ae81ff">2</span>,
  <span style="color:#f92672">&#34;symbolize_keys!&#34;</span>: <span style="color:#ae81ff">2</span>
}<span style="color:#960050;background-color:#1e0010">,</span>
<span style="color:#e6db74">&#34;ActionView::CompiledTemplates&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> {
  <span style="color:#f92672">&#34;_app_views_welcome_index_html_erb__4177595130715791755_70209827438920&#34;</span>: <span style="color:#ae81ff">1</span>,
  <span style="color:#f92672">&#34;_app_views_layouts_application_html_erb___652124533295419796_70209827456500&#34;</span>: <span style="color:#ae81ff">1</span>
}<span style="color:#960050;background-color:#1e0010">,</span>
<span style="color:#e6db74">&#34;ActiveSupport::Notifications::Fanout&#34;</span><span style="color:#960050;background-color:#1e0010">:</span> {
  <span style="color:#f92672">&#34;start&#34;</span>: <span style="color:#ae81ff">4</span>,
  <span style="color:#f92672">&#34;listeners_for&#34;</span>: <span style="color:#ae81ff">12</span>,
  <span style="color:#f92672">&#34;listening?&#34;</span>: <span style="color:#ae81ff">5</span>,
  <span style="color:#f92672">&#34;finish&#34;</span>: <span style="color:#ae81ff">3</span>
}
</code></pre></div><p><code>TracePoint</code> is a great new addition and I hope to see some new crazy
tools being developed (production dead-code analyzer, deprecation code path
finder anyone?)</p>
<p>To end, this short post, here is an interesting quote from <a href="https://chadfowler.com/">Chad
Fowler</a> Berliner by adoption:</p>
<blockquote>
<p>Abstractions are expensive. The cost increases exponentially as you add them to a codebase.
<a href="https://twitter.com/chadfowler/status/308959527217270786">Chad Fowler</a></p>
</blockquote>
]]></content>
		</item>
		
		<item>
			<title>omniauth and google apps</title>
			<link>https://matt.aimonetti.net/posts/2013-01-omniauth-and-google-apps/</link>
			<pubDate>Wed, 30 Jan 2013 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2013-01-omniauth-and-google-apps/</guid>
			<description>Today I struggled to get OmniAuth and Google apps to work properly together. I just wanted to add authentication to my application and restrict access to only my Google Apps domain users. I was hoping it would be straight forward since I could use Google&amp;rsquo;s OpenID service.
Turns out it wasn&amp;rsquo;t that hard, but the lack of documentation made me lost a couple hours. I therefore updated OmniAuth&amp;rsquo;s wiki and wrote this quick post so hopefully you won&amp;rsquo;t waste time looking for simple details.</description>
			<content type="html"><![CDATA[<p>Today I struggled to get <a href="https://github.com/intridea/omniauth">OmniAuth</a> and <a href="https://developers.google.com/accounts/docs/OpenID">Google apps</a> to work properly together.
I just wanted to add authentication to my application and restrict access to only my Google Apps domain users.
I was hoping it would be straight forward since I could use Google&rsquo;s OpenID service.</p>
<p>Turns out it wasn&rsquo;t that hard, but the lack of documentation made me
lost a couple hours.
I therefore updated <a href="https://github.com/intridea/omniauth/wiki">OmniAuth&rsquo;s wiki</a> and wrote this quick post so hopefully you won&rsquo;t waste time looking for simple details.</p>
<h2 id="requirements">Requirements</h2>
<p>You actually only need to add 2 gems to your Gemfile:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">gem <span style="color:#e6db74">&#39;omniauth-openid&#39;</span>
gem <span style="color:#e6db74">&#39;ruby-openid-apps-discovery&#39;</span>
</code></pre></div><p>Now, the second gem is the one I didn&rsquo;t know about.
The gem is actually provided by <a href="https://github.com/google/ruby-openid-apps-discovery">Google itself</a>. It turns out, Google Apps use a custom discovery protocol.
They monkey patched the popular OpenID Ruby libraries so you can just drop in
their gem and their discovery system will magically work.</p>
<h2 id="setup">Setup</h2>
<p>You need to require 4 files to get everything setup properly:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">require <span style="color:#e6db74">&#39;omniauth-openid&#39;</span>
require <span style="color:#e6db74">&#39;openid&#39;</span>
require <span style="color:#e6db74">&#39;openid/store/filesystem&#39;</span>
require <span style="color:#e6db74">&#39;gapps_openid&#39;</span>
</code></pre></div><p>The first one is the omniauth extension for OpenID, the second one is
the main Ruby OpenID library (needed so we can set our SSL cert).
The third one allows us to store temporary data on disk instead of
keeping it in memory (optional).
And finally, the last one is Google&rsquo;s magical gem to get their discovery
system working.</p>
<p>Because we are going to communicate via SSL, we want to make sure that
the OpenID library uses our certs to verify the SSL communications:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">OpenID</span><span style="color:#f92672">.</span>fetcher<span style="color:#f92672">.</span>ca_file <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;/absolute/path/to/ssl_cacert.pem&#34;</span>
</code></pre></div><p>(Obviously, you need to change the path to your own cert)</p>
<p>We are almost done with the setup, we just need two more things:</p>
<ul>
<li>make sure you are using a session.</li>
<li>setup OmniAuth</li>
</ul>
<p>I&rsquo;m using Sinatra, so I&rsquo;ll load the <code>Rack::Session</code> middleware before I
set Omniauth:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">use <span style="color:#66d9ef">Rack</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Session</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Cookie</span>, <span style="color:#e6db74">:secret</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;supers3cr3t&#39;</span>
</code></pre></div><p>(Rails turns that option by default, so you don&rsquo;t need to worry about
it)</p>
<p>Then I can finally setup OmniAuth:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">use <span style="color:#66d9ef">OmniAuth</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Builder</span> <span style="color:#66d9ef">do</span>
  provider <span style="color:#e6db74">:open_id</span>,  <span style="color:#e6db74">:name</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;admin&#39;</span>,
                      <span style="color:#e6db74">:identifier</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;https://www.google.com/accounts/o8/site-xrds?hd=aimonetti.net&#39;</span>,
                      <span style="color:#e6db74">:store</span> <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">OpenID</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Store</span><span style="color:#f92672">::</span><span style="color:#66d9ef">Filesystem</span><span style="color:#f92672">.</span>new(<span style="color:#e6db74">&#39;/tmp&#39;</span>)
<span style="color:#66d9ef">end</span>
</code></pre></div><p>There are two important things to notice. First, because I set the
provider&rsquo;s name to be &lsquo;admin&rsquo;, the magical paths provided by OmiAuth
will use that name (<code>/auth/admin</code>). Secondly, and more importantly, notice how I added
the name of my Google Apps domain at the end of the identifier:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#e6db74">&#39;https://www.google.com/accounts/o8/site-xrds?hd=&#39;</span> <span style="color:#f92672">+</span> your_domain_name
</code></pre></div><h2 id="sinatra">Sinatra</h2>
<p>In Sinatra, your just need to define the routes OmniAuth would use (same
goes for Rails, just use the router for that).</p>
<p>By default, omniauth now offers you a <code>/auth/admin</code> endpoint that will
push the user through Google Apps authentication.
Once the authentication is over, the user will be redirected to the
following endpoint:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#75715e"># Callback URL used when the authentication is done</span>
post <span style="color:#e6db74">&#39;/auth/admin/callback&#39;</span> <span style="color:#66d9ef">do</span>
  auth_details <span style="color:#f92672">=</span> request<span style="color:#f92672">.</span>env<span style="color:#f92672">[</span><span style="color:#e6db74">&#39;omniauth.auth&#39;</span><span style="color:#f92672">]</span>
  session<span style="color:#f92672">[</span><span style="color:#e6db74">:email</span><span style="color:#f92672">]</span> <span style="color:#f92672">=</span> auth_details<span style="color:#f92672">.</span>info<span style="color:#f92672">[</span><span style="color:#e6db74">&#39;email&#39;</span><span style="color:#f92672">]</span>
  redirect <span style="color:#e6db74">&#39;/auth/admin/welcome&#39;</span>
<span style="color:#66d9ef">end</span>
</code></pre></div><p>You can access the authentication details from <code>request.env['omniauth.auth']</code>
and redirect the user to another page, like the admin landing page for
instance.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">get <span style="color:#e6db74">&#39;/auth/admin/welcome&#39;</span> <span style="color:#66d9ef">do</span>
  <span style="color:#66d9ef">if</span> session<span style="color:#f92672">[</span><span style="color:#e6db74">:email</span><span style="color:#f92672">]</span>
    erb <span style="color:#e6db74">:welcome_boss</span>
  <span style="color:#66d9ef">else</span>
    redirect <span style="color:#e6db74">&#39;/auth/admin&#39;</span>
  <span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">end</span>
</code></pre></div><p>On the landing page, you need to verify that the user is logged in, in
this case, during the previous step, we added the email of the user to
her session. We can therefore verify the presence of that information to
confirm the authentication status. If the user is authenticated, then we&rsquo;ll render an ERB
template otherwise we&rsquo;ll redirect her back to the login page.</p>
<p>We should also provide an endpoint in case the authentication failed:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">get <span style="color:#e6db74">&#39;/auth/failure&#39;</span> <span style="color:#66d9ef">do</span>
  params<span style="color:#f92672">[</span><span style="color:#e6db74">:message</span><span style="color:#f92672">]</span>
  <span style="color:#75715e"># do whatever you want here.</span>
<span style="color:#66d9ef">end</span>
</code></pre></div><p>Note that by default, in dev mode, Omniauth won&rsquo;t redirect the user
there. To enable this behavior, use the following snippet (works with any rack app,
Rails, Sinatra or whatever):</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">OmniAuth</span><span style="color:#f92672">.</span>config<span style="color:#f92672">.</span>on_failure <span style="color:#f92672">=</span> <span style="color:#66d9ef">Proc</span><span style="color:#f92672">.</span>new { <span style="color:#f92672">|</span>env<span style="color:#f92672">|</span>
  <span style="color:#66d9ef">OmniAuth</span><span style="color:#f92672">::</span><span style="color:#66d9ef">FailureEndpoint</span><span style="color:#f92672">.</span>new(env)<span style="color:#f92672">.</span>redirect_to_failure
}
</code></pre></div><h2 id="conclusion">Conclusion</h2>
<p>Using Google Apps for authentication with OmniAuth is trivial as long
you know two things:</p>
<ul>
<li>the identifier url: <code>'https://www.google.com/accounts/o8/site-xrds?hd=' + your_domain_name</code></li>
<li>Google&rsquo;s discovery service gem</li>
</ul>
<p>This blog post was written using <code>omniauth 1.1.1</code>, <code>omniauth-openid 1.0.1</code>, <code>rack-openid 1.3.1</code> and <code>ruby-openid-apps-discovery 1.2.0</code>. This might not apply to you if you come from the future :)</p>
]]></content>
		</item>
		
		<item>
			<title>real life concurrency in go</title>
			<link>https://matt.aimonetti.net/posts/2012-11-real-life-concurrency-in-go/</link>
			<pubDate>Tue, 27 Nov 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-11-real-life-concurrency-in-go/</guid>
			<description>The structure of a programming language reflects the challenges and solutions the designers decided to address. Each designer coming with his/her own background decides to tackle some specific issues in a novel way and/or often decides to borrow existing paradigms from other languages. We can&amp;rsquo;t, then, fairly judge a language without understanding what problem the language designer was trying to address.
Today we are going to look at Google&amp;rsquo;s Go language.</description>
			<content type="html"><![CDATA[<p>The structure of a programming language reflects the challenges and solutions the
designers decided to address. Each designer coming with his/her own background
decides to tackle some specific issues in a novel way and/or often
decides to borrow existing paradigms from other languages.
We can&rsquo;t, then, fairly judge a language without understanding
what problem the language designer was trying to address.</p>
<p>Today we are going to look at <a href="https://golang.org/">Google&rsquo;s Go language</a>.
Go approaches concurrency from an interesting view point. But instead of digging
into the history and reasoning which led to this approach, I&rsquo;d like to
show you the language constructs by actually writing real life code.</p>
<h2 id="fetching-web-resources-concurrently">Fetching web resources concurrently</h2>
<p>The following example is taken from my recent presentation <a href="/posts/2012/11/02/rubyconf-2012-ruby-vs-the-world/">Ruby vs. the World</a>. I explored a few programming languages and
showed how they changed my Ruby.</p>
<p>To show how <a href="https://golang.org/">Go</a> addresses concurrency, I decided to build a
program which would concurrently fetch various web resources, wait for all of
them to be fetched, then process them all at once. In other
programming languages, we could have used <a href="https://en.wikipedia.org/wiki/Thread_(computing)">threads</a> and a <a href="https://en.wikipedia.org/wiki/Semaphore_(programming)">semaphore</a>, <a href="https://en.wikipedia.org/wiki/Actor_model">actors</a> or
<a href="https://en.wikipedia.org/wiki/Callbacks">callbacks</a>. Go&rsquo;s approach is <a href="https://en.wikipedia.org/wiki/Communicating_sequential_processes">slightly different</a>, let&rsquo;s walk through the
code together.</p>
<p>The first part of our code gets us setup:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#f92672">package</span> <span style="color:#a6e22e">main</span>

<span style="color:#f92672">import</span> (
	<span style="color:#e6db74">&#34;fmt&#34;</span>
	<span style="color:#e6db74">&#34;net/http&#34;</span>
	<span style="color:#e6db74">&#34;time&#34;</span>
)

<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">urls</span> = []<span style="color:#66d9ef">string</span>{
	<span style="color:#e6db74">&#34;https://www.rubyconf.org/&#34;</span>,
	<span style="color:#e6db74">&#34;https://golang.org/&#34;</span>,
	<span style="color:#e6db74">&#34;https://matt.aimonetti.net/&#34;</span>,
}
</code></pre></div><p>The code above names our package then imports a few standard libraries that we are going to need. It then defines an array/slice of strings representing the urls we are going to fetch.</p>
<p>Next we define a type we will use a bit later:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">type</span> <span style="color:#a6e22e">HttpResponse</span> <span style="color:#66d9ef">struct</span> {
	<span style="color:#a6e22e">url</span>      <span style="color:#66d9ef">string</span>
	<span style="color:#a6e22e">response</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Response</span>
	<span style="color:#a6e22e">err</span>      <span style="color:#66d9ef">error</span>
}
</code></pre></div><p>You can think of a struct type as a simple representation of a class. Technically, we are defining a structure with some typed attributes. We will later on, create instances of this defined type.</p>
<p>Go implements OOP <a href="https://golang.org/doc/go_faq.html#Is_Go_an_object-oriented_language">slightly differently</a> than other languages.</p>
<blockquote>
<p>Methods in Go are more general than in C++, Java: they can be defined for any sort of data, even built-in types such as plain, “unboxed” integers. They are not restricted to structs (classes).</p>
</blockquote>
<p>We can therefore define methods/functions for any type of data,
including &ldquo;any/all&rdquo; types.
This approach to types is called <a href="https://en.wikipedia.org/wiki/Structural_type_system">structural typing</a>.</p>
<p>Here is the code:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">asyncHttpGets</span>(<span style="color:#a6e22e">urls</span> []<span style="color:#66d9ef">string</span>) []<span style="color:#f92672">*</span><span style="color:#a6e22e">HttpResponse</span> {
	<span style="color:#a6e22e">ch</span> <span style="color:#f92672">:=</span> make(<span style="color:#66d9ef">chan</span> <span style="color:#f92672">*</span><span style="color:#a6e22e">HttpResponse</span>)
	<span style="color:#a6e22e">responses</span> <span style="color:#f92672">:=</span> []<span style="color:#f92672">*</span><span style="color:#a6e22e">HttpResponse</span>{}
	<span style="color:#a6e22e">client</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">Client</span>{}
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">url</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">urls</span> {
		<span style="color:#66d9ef">go</span> <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">url</span> <span style="color:#66d9ef">string</span>) {
			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;Fetching %s \n&#34;</span>, <span style="color:#a6e22e">url</span>)
			<span style="color:#a6e22e">resp</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">client</span>.<span style="color:#a6e22e">Get</span>(<span style="color:#a6e22e">url</span>)
			<span style="color:#a6e22e">ch</span> <span style="color:#f92672">&lt;-</span> <span style="color:#f92672">&amp;</span><span style="color:#a6e22e">HttpResponse</span>{<span style="color:#a6e22e">url</span>, <span style="color:#a6e22e">resp</span>, <span style="color:#a6e22e">err</span>}
			<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">resp</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">StatusCode</span> <span style="color:#f92672">==</span> <span style="color:#a6e22e">http</span>.<span style="color:#a6e22e">StatusOK</span> {
				<span style="color:#a6e22e">resp</span>.<span style="color:#a6e22e">Body</span>.<span style="color:#a6e22e">Close</span>()
			}
		}(<span style="color:#a6e22e">url</span>)
	}

	<span style="color:#66d9ef">for</span> {
		<span style="color:#66d9ef">select</span> {
		<span style="color:#66d9ef">case</span> <span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">ch</span>:
			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%s was fetched\n&#34;</span>, <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">url</span>)
			<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
				<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#e6db74">&#34;with an error&#34;</span>, <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">err</span>)
			}
			<span style="color:#a6e22e">responses</span> = append(<span style="color:#a6e22e">responses</span>, <span style="color:#a6e22e">r</span>)
			<span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">responses</span>) <span style="color:#f92672">==</span> len(<span style="color:#a6e22e">urls</span>) {
				<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">responses</span>
			}
		<span style="color:#66d9ef">case</span> <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">After</span>(<span style="color:#ae81ff">50</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Millisecond</span>):
			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;.&#34;</span>)
		}
	}
	<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">responses</span>
}
</code></pre></div><p>This is the meat of our application. And there is quite a lot of going
on in just a few lines. Assuming you aren&rsquo;t familiar
with Go, I&rsquo;ll walk though the code.</p>
<p>Let&rsquo;s start with the signature:</p>
<ul>
<li>the function is named <code>asyncHttpGets</code></li>
<li>it takes an argument named<code>urls</code> which is an &ldquo;array&rdquo; of strings (I used quotes around the word
array because it&rsquo;s technically what Go calls a slice)</li>
<li>it returns an &ldquo;array&rdquo; of <code>HttpResponse</code> pointers</li>
</ul>
<p>Then in the function body:</p>
<p>We start by creating an instance of a <code>channel</code> and assigning it to the
<code>ch</code> variable name. Think of a channel as a pipe like in unix. We can write to and read from that channel.</p>
<p>In the next line we create an empty instance of a slice containing pointers to
<code>HttpResponse</code> objects.</p>
<p>Then, using the <code>for range</code> language construct, we iterate through our <code>urls</code>, storing the current value being used into the scoped variable <code>url</code>. The <code>url</code> is then available within the block/lambda/closure marked by the curly braces.</p>
<p>Now this is where the async construct comes in. Using the <code>go</code>
keyword, we define an anonymous function that takes a string argument representing a
url.</p>
<p>The function prints this string, then uses the <code>net/http</code>
library to fetch the web resource. We use the returned data to create an
instance of our <code>HttpResponse</code> type and send it to the channel.</p>
<p>This part gets a bit confusing because I reused the name <code>url</code>. We call this
anonymous function right away passing it the <code>url</code> variable set
by the loop.</p>
<p>You might wonder why we bother to create an anonymous function and
call it right away instead of just executing the code directly.
The <code>go</code> keyword executes the code that is passed in as a <em>goroutine</em> which is well explained <a href="https://golang.org/doc/effective_go.html#goroutines">here</a></p>
<blockquote>
<p>A goroutine is a function executing concurrently with other goroutines in the same address space. It is lightweight, costing little more than the allocation of stack space. And the stacks start small, so they are cheap, and grow by allocating (and freeing) heap storage as required.</p>
</blockquote>
<p>In other words, you start a <em>goroutine</em> and you let the &ldquo;system&rdquo; handle
how it wants to deal with the low level details. Technically, goroutines
might run in one or multiple threads, but you don&rsquo;t need to know.
We trigger each http fetch in a separate goroutine
and then each response is pushed down the channel.</p>
<p>The second block of code begins with another <code>for</code> loop containing a switch/case statement.
The case statement checks if something is
in the channel. If there is something, we&hellip;</p>
<ul>
<li>allocate the data to the <code>r</code> variable</li>
<li>print the resource&rsquo;s url</li>
<li>append the resource to the slice we created at the beginning of the function.</li>
</ul>
<p>If the length of the array is the same as the length of all urls we want to fetch, we are done
fetching all our resources and can return.
While still waiting for responses, we print a dot every 50ms.</p>
<p><strong>Update:</strong>
In the first version of this blog post I had used a &lsquo;default&rsquo; case
statement to print the dot and sleep for 50ms so the loop wouldn&rsquo;t be
too tight and the concurrency effect was more obvious. But some
<a href="https://news.ycombinator.com/item?id=4837919">HN comments</a> pointed out that it wasn&rsquo;t needed and I shouldn&rsquo;t block.
For reference here is what I had before (don&rsquo;t use this code):</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go">	<span style="color:#66d9ef">for</span> {
		<span style="color:#66d9ef">select</span> {
		<span style="color:#66d9ef">case</span> <span style="color:#a6e22e">r</span> <span style="color:#f92672">:=</span> <span style="color:#f92672">&lt;-</span><span style="color:#a6e22e">ch</span>:
			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;%s was fetched\n&#34;</span>, <span style="color:#a6e22e">r</span>.<span style="color:#a6e22e">url</span>)
			<span style="color:#a6e22e">responses</span> = append(<span style="color:#a6e22e">responses</span>, <span style="color:#a6e22e">r</span>)
			<span style="color:#66d9ef">if</span> len(<span style="color:#a6e22e">responses</span>) <span style="color:#f92672">==</span> len(<span style="color:#a6e22e">urls</span>) {
				<span style="color:#66d9ef">return</span> <span style="color:#a6e22e">responses</span>
			}
		<span style="color:#66d9ef">default</span>:
			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#e6db74">&#34;.&#34;</span>)
			<span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Sleep</span>(<span style="color:#ae81ff">50</span> <span style="color:#f92672">*</span> <span style="color:#a6e22e">time</span>.<span style="color:#a6e22e">Millisecond</span>)
		}
	}
</code></pre></div><p>Thank you HackerNews.</p>
<p>With that code constructed, our <code>main</code> can make use of it like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-go" data-lang="go"><span style="color:#66d9ef">func</span> <span style="color:#a6e22e">main</span>() {
	<span style="color:#a6e22e">results</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">asyncHttpGets</span>(<span style="color:#a6e22e">urls</span>)
	<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">result</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">results</span> {
		<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">result</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> <span style="color:#f92672">&amp;&amp;</span> <span style="color:#a6e22e">result</span>.<span style="color:#a6e22e">response</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
			<span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Printf</span>(<span style="color:#960050;background-color:#1e0010">&#34;</span><span style="color:#f92672">%</span><span style="color:#a6e22e">s</span>
                 <span style="color:#a6e22e">result</span>.<span style="color:#a6e22e">response</span>.<span style="color:#a6e22e">Status</span>)
		}
	}
}
</code></pre></div><p>Running the code looks like this:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-bash" data-lang="bash">$ go run concurrency_example.go
.Fetching https://www.rubyconf.org/
Fetching https://golang.org/
Fetching https://matt.aimonetti.net/
.....https://golang.org/ was fetched
.......https://www.rubyconf.org/ was fetched
.https://matt.aimonetti.net/ was fetched
https://golang.org/
https://www.rubyconf.org/
https://matt.aimonetti.net/
</code></pre></div><p>As you can see from the print statements, the 3 urls are triggered in a
sequential way, but the responses come back in different orders due to different server latencies and response transfer time.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Go was designed to make concurrency easy for developers.
It is a very well documented language and you will find <a href="https://golang.org/doc/effective_go.html#concurrency">on this page
a lot of information about its concurrency philosophy</a> and details about each available constructs works.</p>
<p>I like that the language is very simple and the constructs
explicit. If you want to write concurrent code, Go pushes you to do it
in a specific style. That style is clear and comfortable for me. My code stays simple, I don&rsquo;t go crazy with callbacks, and the
conventions make it simple for everyone else to understand my code.</p>
<p>Whether or not Go appeals to you stylistically, clearly the designers
stayed close to the goal of developing to a 21st century C
with a special focus on concurrency with a unix approach.</p>
]]></content>
		</item>
		
		<item>
			<title>Engineers suck at finding right jobs</title>
			<link>https://matt.aimonetti.net/posts/2012-11-engineers-suck-at-finding-right-jobs/</link>
			<pubDate>Wed, 14 Nov 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-11-engineers-suck-at-finding-right-jobs/</guid>
			<description>If you are currently a software engineer you need to realize two things:
 Now is an awesome time to be a software engineer (probably the best time ever). Your job might not be well suited for you.  I&amp;rsquo;ll show you why we are lucky bastards, why we aren&amp;rsquo;t so good at picking the right jobs and some hints on how to solve this issue.
I remember a family friend telling me when I was a kid that computers are going to be the future and that there will be a lot of jobs in this field.</description>
			<content type="html"><![CDATA[<p>If you are currently a software engineer you need to realize two things:</p>
<ul>
<li><strong>Now is an awesome time to be a software engineer</strong> (probably the best time ever).</li>
<li><strong>Your job might not be well suited for you</strong>.</li>
</ul>
<p>I&rsquo;ll show you why we are lucky bastards, why we aren&rsquo;t so good at
picking the right jobs and some hints on how to solve this issue.</p>
<br>
<p>I remember a family friend telling me when I was a kid that computers
are going to be the future and that there will be a lot of jobs in this
field. I also remember that the idea of sitting all day, alone, in front of a
<a href="https://en.wikipedia.org/wiki/Minitel">minitel</a>-like computer scared the hell out of me.
But he was right and I now work from home, spending 12+ hours
in front of a monitor. I get emails and phone calls from many people
reaching out to me to help them find software engineers.</p>
<p>At least three things make &ldquo;now&rdquo; the best time to be a software
engineer:</p>
<ul>
<li><strong>demand</strong></li>
<li><strong>projects</strong></li>
<li><strong>prestige</strong></li>
</ul>
<h2 id="good-time">Good time</h2>
<p>There is a huge demand for engineers. There are many more job openings
than candidates. But this is much better than in late 90s/early 2000
when anyone who could write a line of HTML would get a job.
Now the projects people are building
are way more interesting and have a real potential to change lives.
Before, you had to work for a giant company to
have a chance to do that. But now, with internet and smart mobile
devices everywhere, almost any startup (fancy name for small company) can
have a huge impact &ndash; look at Twitter for instance.</p>
<p>Lastly, being a geek is cool. Movies, cartoons, TV Shows now have
geek heroes (granted they usually don&rsquo;t represent real geeks, but hey
it&rsquo;s better than nothing).</p>
<h2 id="the-problem">The problem</h2>
<p><strong>Most software engineers</strong> I know, are really bad
at choosing the right job for themselves. They <strong>don&rsquo;t design a career</strong>.
Engineers are good at solving technical problems in an objective way, but <strong>when it comes
to our jobs and future, we seem to struggle.</strong></p>
<h2 id="why">Why?</h2>
<p>I&rsquo;m not an expert but I have a few guesses I&rsquo;d like to share with you:</p>
<ul>
<li>We don&rsquo;t know our real worth.</li>
<li>We don&rsquo;t make long term plans.</li>
<li>We get paid well, so why bother changing?</li>
<li>Changing job feels like betrayal.</li>
<li>The system is broken.</li>
</ul>
<h2 id="self-worth">Self worth</h2>
<p>Most modern companies need solid engineers to be relevant in the
short/medium term and they know it. <strong>Most engineers have no idea how
their talent and dedication converts into real business value</strong>.
Without that appreciation, they
can&rsquo;t easily estimate how much they are worth. The
salary scale for software engineers is dramatically different from other jobs/industries.
To your business, you might be worth twice or three times the salary of someone like a teacher.
This is probably not fair because of the social value a teacher offers, but that&rsquo;s the way the <a href="https://en.wikipedia.org/wiki/Law_of_demand">law of
demand</a> works in our society.
Knowing how much you are worth to a company and how much to ask is
critical to properly negotiate or renegotiate a contract.</p>
<p>I remember when I moved to America and was thankful to have a job.
I had no idea that at $45k/year with basically no health coverage and no
vacation, I was grossly underpaid and could have been paid twice that amount
down the street. (Note: the average software engineer salary in the US
is at <a href="https://www.indeed.com/salary/Software-Engineer.html">$89,000 according to indeed.com</a>).
The average salary for a high school teacher is <a href="https://www.indeed.com/salary?q1=high+school+teacher&amp;l1=">$47k/year</a>
so I wasn&rsquo;t complaining. As a matter of fact, I didn&rsquo;t leave this job because of the salary.
I truly believe that <strong>&ldquo;Money doesn&rsquo;t buy happiness&rdquo;</strong> and <strong>it shouldn&rsquo;t be
your primary reason to accept or leave a job</strong>. Money is nice and
often makes life easier. But the point is that you have to understand
how much you&rsquo;re worth, so you can get paid and
focus on your work.</p>
<h2 id="defining-a-vector">Defining a vector</h2>
<p><a href="https://www.kitchensoap.com/about-me/">John Allspaw</a> wrote a great blog
post about <a href="https://www.kitchensoap.com/2012/10/25/on-being-a-senior-engineer/">what it means to be a senior engineer</a>.
I strongly recommend you read it. I often look back at it
and pick up a couple points I need to focus on myself.
John wrote a book which is a collection of essays and interviews
regarding tech/web ops.</p>
<p><a href="https://www.amazon.com/gp/product/1449377440/ref=as_li_ss_il?ie=UTF8&camp=1789&creative=390957&creativeASIN=1449377440&linkCode=as2&tag=merbist-20" style="text-align:center; display:block;"><img border="0" src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&ASIN=1449377440&Format=_SL110_&ID=AsinImage&MarketPlace=US&ServiceVersion=20070822&WS=1&tag=merbist-20" ></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&l=as2&o=1&a=1449377440" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p>Here is a very interesting quote:</p>
<blockquote>
<p>Not everyone can be senior. If, after five years, you are senior, are you at the peak of your game? After five more years will you not have accrued more invaluable experience? What then? “Super engineer”? Five more years? “Super-duper engineer.” I blame the youth of our discipline for this affliction. [&hellip;] Given the dynamics of our industry many elected to move on to managerial positions or risk an entrepreneurial run at things.”</p>
</blockquote>
<p>There are two very strong points in this quote:</p>
<ul>
<li>we don&rsquo;t quite know what it means to be a senior engineer (and John&rsquo;s post does a great
job explaining his take on that).</li>
<li>many of us end up in managerial positions or leading startups.</li>
</ul>
<p>I might be a bit radical &ndash; but the day I stop learning/improving
will be the day that I will quit, change jobs or careers. John&rsquo;s post has great pointers
to help us improve our skills. But the question I&rsquo;m trying to raise is:</p>
<p><strong>what do we want from our career?</strong></p>
<p>&ldquo;Career&rdquo; sounds like a dirty word to many of us. It has a corporate,
sleazy, back stabbing connotation. When I hear it, I picture a
cliché stock photography of a bunch of smiling people wearing 80&rsquo;s suits.
In the context on this post, let&rsquo;s take the Oxford English Dictionary
definition: &ldquo;course or progress through life (or a distinct portion of life)&rdquo;.
The word comes from from French via the Old Occitan word: &ldquo;carriera&rdquo; which means &ldquo;street&rdquo;.</p>
<p><strong>A better word for career might be &ldquo;path&rdquo;.</strong></p>
<p>I think we have a hard time knowing what kind of path we want to be on.
When faced with the question, a lot of us answer:
&ldquo;solving problems&rdquo;, &ldquo;having fun&rdquo;, &ldquo;changing the world&rdquo;.
All these answers sound good, but they aren&rsquo;t paths, they are just attributes.</p>
<p>I have to admit that I&rsquo;m still struggling with this question and
probably will for a while. I&rsquo;m pretty good at defining short term goals but I
have a hard time seeing the long term path.
As a matter of fact, a little while back I was seated in front of <a href="https://www.chadfowler.com/">Chad
Fowler</a> in his office in Washington, DC.
Chad wrote a great book called <a href="https://www.amazon.com/gp/product/1934356344/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1934356344&amp;linkCode=as2&amp;tag=merbist-20">&ldquo;The Passionate Programmer: Creating a Remarkable Career in Software Development&rdquo;</a>.</p>
<p><a href="https://www.amazon.com/gp/product/1934356344/ref=as_li_ss_il?ie=UTF8&camp=1789&creative=390957&creativeASIN=1934356344&linkCode=as2&tag=merbist-20" style="text-align:center; display:block;"><img border="0" src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&ASIN=1934356344&Format=_SL110_&ID=AsinImage&MarketPlace=US&ServiceVersion=20070822&WS=1&tag=merbist-20" ></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&l=as2&o=1&a=1934356344" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p>I&rsquo;ve read Chad&rsquo;s book (which inspired me in many ways) and have known Chad
for years. The point of our meeting was to decide what I was going
to work on next. <strong>Unconsciously, I expected Chad to just tell me what I
should be doing. I trusted him to pick the right &ldquo;path&rdquo; for me.</strong>
But I was surprised when Chad told me: <em>&ldquo;you&rsquo;re the
kind of engineer who can do anything. You&rsquo;re a generalist who can pick
a topic and become a specialist. So what do you want to do?&quot;</em></p>
<p>I wasn&rsquo;t sure how to take it, it sounded like a compliment but, at the
same time, <strong>the fact that Chad didn&rsquo;t have a solution to my problem bothered me.</strong>
I remember thinking, wait, he&rsquo;s the expert and he&rsquo;s deflecting the
situation by asking me the question I came to ask him. Sure, the
compliment was nice but that wouldn&rsquo;t solve anything. What does that
mean about me? If an expert can&rsquo;t figure out what I should do, I might
be screwed.</p>
<p>Then on my way back home, I realized that <strong>it didn&rsquo;t matter how well Chad knew me,
he couldn&rsquo;t guess what I even didn&rsquo;t know about myself.</strong></p>
<p><strong>My long term happiness depends on me finding a direction I want my
professional life to take.</strong>
In Chad&rsquo;s book, there is a strong focus on finding a market,
understanding it, developing skills and marketing yourself.
However there was something I had missed.</p>
<blockquote>
<p>The goal-oriented, destination-focused thinking that you usually do
leads only from one goal to the next. It has no logical end. What most
of us fail to realize is that <em>the path</em> is the end.</p>
</blockquote>
<p>I&rsquo;ve always known that the journey is more important than the destination in itself,
but what I had missed is that you still need to define a destination or
maybe more precisely a direction, a vector.
My problem is that my path was just a bunch of scattered dots. Hopping from one
to the other, I was hoping it was going to make a pretty drawing. The challenge is
when I got to a spot, I was stuck not knowing what to do next. I ended up picking another
short term goal/destination based on the opportunities available at that
time.</p>
<p>What I should do instead was to <strong>define a general direction and then
learn through the process.</strong> I believe this will help me enjoy my job more
than running after goals. It will allow me to see the world differently
and will help me make the right career choices when the time is right.
To be honest, I think that&rsquo;s the only way I can build endurance and not
burn out in 5 years. That said, I&rsquo;ll still have goals,
deadlines and the usual &ndash; but they won&rsquo;t define my own personal progress.</p>
<h2 id="why-bother">Why bother?</h2>
<p>Changing jobs is a pain. As an engineer I weigh the pros and cons and try
to logically pick the right choice &ndash; at least in theory. In practice I
avoid dealing with questions that might result in challenging
consequences.</p>
<p>Quiting a job is tough. You have to tell your current employer and your
colleagues that you are leaving them for something you think is better
for you. <strong>The nicer the people you work with, the harder it is. The better
you are paid, the harder it is.</strong> If you work with nice people and
you&rsquo;re well paid, leaving is <em>really</em> hard (take note if you run a team).</p>
<p>In our profession, changing jobs isn&rsquo;t usually seen as something
bad. Recruiters might pressure you to take a new, better job.
Beware impulsive changes though. Recruiters want their commissions so
they&rsquo;ll do anything they can do make you switch. They&rsquo;ll try to convince
you that the grass is greener on the other side. Maybe that&rsquo;s only &ldquo;bad&rdquo; recruiters.</p>
<p>There are some recruiters who care about people and companies. Recruiters
who will help you find the right job for you. However, they
won&rsquo;t be able to help you if you don&rsquo;t know what direction you want to
go to.</p>
<p>I remember being stuck in a pretty terrible work environment, being
underpaid and the projects I was working on weren&rsquo;t going anywhere.
A friend gave me a Seth Godin&rsquo;s book called <a href="https://www.amazon.com/gp/product/1591841666/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1591841666&amp;linkCode=as2&amp;tag=merbist-20">&ldquo;The Dip: A Little Book That Teaches You When to Quit (and When to Stick)&quot;</a>.</p>
<p><a href="https://www.amazon.com/gp/product/1591841666/ref=as_li_ss_il?ie=UTF8&camp=1789&creative=390957&creativeASIN=1591841666&linkCode=as2&tag=merbist-20" style="text-align:center; display:block;"><img border="0" src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&ASIN=1591841666&Format=_SL110_&ID=AsinImage&MarketPlace=US&ServiceVersion=20070822&WS=1&tag=merbist-20" ></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&l=as2&o=1&a=1591841666" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>
<p>I&rsquo;m not a big fan of self-help/business books, but this book raised a very good and simple question:
how do the efforts compare to the returns?
Which situation are you in:</p>
<p><img src="/images/dip.jpg" alt=""></p>
<p><img src="/images/cliff-dip.jpg" alt=""></p>
<p>Think about it. <strong>Will the effort you put into your work pay off?</strong>
If you don&rsquo;t think it will, then you should quit right away.</p>
<p>The logic is pretty simple but requires you to forecast. For that you need
some sort of metrics helping you to see if you are getting closer or
further from the direction you set for yourself.</p>
<h2 id="trust">Trust</h2>
<p>Trust is the key element of any relationship.
In <a href="https://www.amazon.com/gp/product/B000UCUX0K/ref=as_li_ss_tl?ie=UTF8&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B000UCUX0K&amp;linkCode=as2&amp;tag=merbist-20">The Five Dysfunctions of a Team</a>, Patrick Lencioni explains that the base of management dysfunctions is absence of trust:</p>
<p><img src="/images/fivedysfunctions.gif" alt=""></p>
<p>Turns out it&rsquo;s the same thing for our careers. We need a team of people
to help us define a vision/direction and keep us honest and accountable.</p>
<p>Find people who you can trust to talk to about your professional goals,
your progress, failures and doubts. People who will be honest with you
and tell you things you might not want to hear. Find mentors and honest
people. These people don&rsquo;t have to be working in the industry. They just
have to be able to listen and care.</p>
<p>People like that are extremely hard to find, but so are good executives.
<strong>I believe that having trustworthy friends (partners/family members..) who care is a big part of what
makes someone successful.</strong></p>
<h2 id="my-small-contribution">My small contribution</h2>
<p>As I explained earlier, I&rsquo;m no expert and I also struggle with the issues I described.
However, I&rsquo;d be glad to provide a bit of my free time to help you think
through these issues.</p>
<p><strong>A lot of you are doing a great job without the rest
of us noticing.</strong> If you don&rsquo;t have a popular twitter account, blog, open
source projects, published books or given talks at conferences, it might
be hard to get yourself noticed or even know how much you&rsquo;re worth.
Trust is a big deal and if you are considering moving on, you probably
don&rsquo;t want your boss and your colleagues to know. You probably also
don&rsquo;t know good recruiters you can trust. You might not even be sure
it&rsquo;s worth investing too much time.</p>
<p>Most of you probably won&rsquo;t consider it, but <strong>I&rsquo;d like to offer my
help</strong>
if you&rsquo;d like it. <strong>I promise full anonymity and no strings
attached</strong>. Just</p>
<ul>
<li><del>email me</del></li>
<li><del>tell me about yourself and what you do</del></li>
<li><del>what direction you&rsquo;d like your career to take</del></li>
<li><del>ask any questions you might have </del></li>
</ul>
<p>After exchanging a few emails , <strong>I&rsquo;ll try to make good use of my network</strong>
to find you a way to move in your desired direction.
Or, if you work for an interesting company with current openings, feel free to contact
me too.</p>
<p>date = &ldquo;Update:&rdquo;
slug = &ldquo;Update:/engineers-suck-at-finding-right-jobs&rdquo;
literally days replying to as many people as possible. I&rsquo;m sorry but at
this time I can&rsquo;t reply to any new enquiries. I&rsquo;ll write a follow up
blog post that covers what I learned from my interactions with so many
readers.
**</p>
<p>I have no idea how this will turn out. Maybe I&rsquo;ll get a couple of emails,
zero, or way too many to handle &ndash; but it&rsquo;s worth a try. I do have a full time job,
so please don&rsquo;t expect me to reply to your emails within the hour.</p>
<p>I finally took the time to enable the comments in this blog. Feel free
to leave advice or feedback.</p>
]]></content>
		</item>
		
		<item>
			<title>rubyconf 2012 ruby vs the world</title>
			<link>https://matt.aimonetti.net/posts/2012-11-rubyconf-2012-ruby-vs-the-world/</link>
			<pubDate>Fri, 02 Nov 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-11-rubyconf-2012-ruby-vs-the-world/</guid>
			<description>During RubyConf 2012 in Denver, Colorado Matt Aimonetti gave a talk entitled Ruby Vs. The World.
##Description of the talk:
Ruby is an awesome programming language, it&amp;rsquo;s so pleasing you probably haven&amp;rsquo;t seriously looked at other languages since you switched. The programming world is evolving fast, new languages are created daily, new trends are emerging. Let&amp;rsquo;s take some time to look at a few languages from a Ruby developer perspective.</description>
			<content type="html"><![CDATA[<p>During <a href="https://rubyconf.com/">RubyConf 2012</a> in Denver, Colorado Matt
Aimonetti gave a talk entitled <strong>Ruby Vs. The World</strong>.</p>
<p>##Description of the talk:</p>
<p>Ruby is an awesome programming language, it&rsquo;s so pleasing you probably haven&rsquo;t seriously looked at other languages since you switched. The programming world is evolving fast, new languages are created daily, new trends are emerging. Let&rsquo;s take some time to look at a few languages from a Ruby developer perspective.</p>
<p><img src="https://speakerd.s3.amazonaws.com/presentations/50941f6aeb710400020019ac/slide_19.jpg" alt="Matt Aimonetti talks Scala, Clojure, Go and Ruby"></p>
<p>##Slides</p>
<script async class="speakerdeck-embed" data-id="50941f6aeb710400020019ac" data-ratio="1.2994923857868" src="//speakerdeck.com/assets/embed.js"></script>
<p>The slides are available on [Matt&rsquo;s SpeakerDeck page]https://speakerdeck.com/matt_aimonetti/ruby-vs-the-world) and can be [downloaded here]({{ page.slides }}).</p>
<p>##Video</p>
<iframe width="640" height="360" src="https://www.youtube.com/embed/V_k3q37Tieg" frameborder="0" allowfullscreen></iframe>
<p>##Presentation website</p>
<p>Matt&rsquo;s presentation was filmed by <a href="https://confreaks.com">Confreaks</a> and posted <a href="https://confreaks.com/videos/1288-rubyconf2012-ruby-vs-the-world">here</a>.</p>
<p>For more RubyConf 2012 talks, go <a href="https://confreaks.com/events/rubyconf2012">there</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>mmm dot mruby or why yet another ruby implementation</title>
			<link>https://matt.aimonetti.net/posts/2012-10-mmm-dot-mruby-or-why-yet-another-ruby-implementation/</link>
			<pubDate>Tue, 09 Oct 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-10-mmm-dot-mruby-or-why-yet-another-ruby-implementation/</guid>
			<description>During Aloha RubyConf 2012 in Honolulu, Hawaii Matt Aimonetti gave a talk entitled mmm..mruby or why yet another Ruby implementation.
##Description of the talk:
mruby is Matz’ new Ruby implementation, it’s not cooler than node.js, it doesn’t natively support Hypstermedia, it looks just like the good old Ruby. So why should we, as a community care?
Matt&amp;rsquo;s talk is divided in two parts, an introduction of mruby (embedded Ruby) and and revisiting Ruby.</description>
			<content type="html"><![CDATA[<p>During <a href="https://aloharubyconf.com/">Aloha RubyConf 2012</a> in Honolulu, Hawaii Matt
Aimonetti gave a talk entitled <strong>mmm..mruby or why yet another Ruby implementation</strong>.</p>
<p>##Description of the talk:</p>
<p>mruby is Matz’ new Ruby implementation, it’s not cooler than node.js, it doesn’t natively support Hypstermedia,
it looks just like the good old Ruby. So why should we, as a community care?</p>
<p>Matt&rsquo;s talk is divided in two parts, an introduction of mruby (embedded
Ruby) and and revisiting Ruby.</p>
<p><img src="https://speakerd.s3.amazonaws.com/presentations/50752712f8a4020002043005/slide_10.jpg?1350068026" alt="Matt Aimonetti talks about mruby"></p>
<p>##Slides</p>
<script async class="speakerdeck-embed" data-id="50752712f8a4020002043005" data-ratio="1.2994923857868" src="//speakerdeck.com/assets/embed.js"></script>
<p>The slides are available on [Matt&rsquo;s SpeakerDeck page]https://speakerdeck.com/matt_aimonetti/mmmm-dot-mruby-everywhere-and-revisiting-ruby) and can be [downloaded here]({{ page.slides }}).</p>
<p>##Video</p>
<iframe width="640" height="360" src="https://www.youtube.com/embed/eZYRd86OTbk" frameborder="0" allowfullscreen></iframe>
<p>##Presentation website</p>
<p>Matt&rsquo;s presentation was filmed by <a href="https://confreaks.com">Confreaks</a> and posted <a href="https://confreaks.com/videos/1252-aloharuby2012-mmm-mruby-or-why-yet-another-ruby-implementation">here</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>pulsoconf tour of programming languages</title>
			<link>https://matt.aimonetti.net/posts/2012-10-pulsoconf-tour-of-programming-languages/</link>
			<pubDate>Fri, 05 Oct 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-10-pulsoconf-tour-of-programming-languages/</guid>
			<description>During PulsoConf 2012 in Bogotá, Colombia Matt Aimonetti gave a talk entitled Tower of Babel: a tour of programming languages.
##Description of the talk:
Programming languages affect the way one looks and solves problems. But comparing programming languages isn&amp;rsquo;t as simple as drawing a table comparing features.
In his talk, Matt shows what he likes, dislikes, the philosophy and concrete example of how to use 7 programming languages:
 Ruby JavaScript CoffeeScript Objective-C Clojure Scala Go  ##Slides</description>
			<content type="html"><![CDATA[<p>During <a href="https://pulsoconf.co/">PulsoConf 2012</a> in Bogotá, Colombia Matt
Aimonetti gave a talk entitled <em>Tower of
Babel: a tour of programming languages</em>.</p>
<p>##Description of the talk:</p>
<p>Programming languages affect the way one looks and solves problems. But
comparing programming languages isn&rsquo;t as simple as drawing a table
comparing features.</p>
<p><img src="/images/matt_aimonetti_languages_table.jpg" alt="Matt Aimonetti compares programming languages"></p>
<p>In his talk, Matt shows what he likes, dislikes, the philosophy and concrete example of how to use 7 programming
languages:</p>
<ul>
<li>Ruby</li>
<li>JavaScript</li>
<li>CoffeeScript</li>
<li>Objective-C</li>
<li>Clojure</li>
<li>Scala</li>
<li>Go</li>
</ul>
<p>##Slides</p>
<script async class="speakerdeck-embed" data-id="50662c32244a9d000202ba53" data-ratio="1.299492385786802" src="//speakerdeck.com/assets/embed.js"></script>
<p>The slides are available on <a href="https://speakerdeck.com/u/matt_aimonetti/p/tower-of-babel-a-tour-of-programming-languages">Matt&rsquo;s SpeakerDeck</a> and can be [downloaded here]({{ page.slides }}).</p>
<p>##Video</p>
<p>TBD</p>
]]></content>
		</item>
		
		<item>
			<title>what is scala pattern matching</title>
			<link>https://matt.aimonetti.net/posts/2012-09-what-is-scala-pattern-matching/</link>
			<pubDate>Thu, 20 Sep 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-09-what-is-scala-pattern-matching/</guid>
			<description>Scala is a very interesting programming language. It has for goal to provide both Object Oriented and Functional Programming paradigms. Now Scala isn&amp;rsquo;t the only recent programming language out there mixing the two paradigms. Ruby, JavaScript and Clojure are other examples of popular languages implementing both functional and OO programming patterns. Of course, they each have a different take on the problem and that is what is interesting.
Instead of arguing the pros and cons of OOP vs FP and how each of the previously mentioned languages handle being OOP and FP, I&amp;rsquo;d like to introduce a very powerful Scala idiom: pattern matching.</description>
			<content type="html"><![CDATA[<p><a href="https://www.scala-lang.org/">Scala</a> is a very interesting programming
language. It has for goal to provide
both <a href="https://en.wikipedia.org/wiki/Object-oriented_programming">Object Oriented</a> and <a href="https://en.wikipedia.org/wiki/Functional_programming">Functional Programming</a> paradigms.
Now <a href="https://www.scala-lang.org/">Scala</a> isn&rsquo;t the only recent programming language out there mixing the two paradigms.
<a href="https://www.ruby-lang.org/">Ruby</a>, <a href="https://en.wikipedia.org/wiki/JavaScript">JavaScript</a> and <a href="https://clojure.org/">Clojure</a> are other examples of popular
languages implementing both functional and OO programming patterns. Of
course, they each have a different take on the problem and that is what
is interesting.</p>
<p>Instead of arguing the pros and cons of OOP vs FP and how each of the
previously mentioned languages handle being OOP and FP, I&rsquo;d like to introduce
a very powerful <a href="https://www.scala-lang.org/">Scala</a> idiom: <a href="https://en.wikipedia.org/wiki/Pattern_matching">pattern
matching</a>. Note that
pattern matching isn&rsquo;t something Scala invented nor that it only exists in
Scala. Pattern matching can be achieved many different ways. However,
the majority of the popular languages don&rsquo;t put this concept at the
center of their language. A few languages way before Scala rested
heavily on pattern matching such as <a href="https://www.erlang.org/doc/reference_manual/patterns.html">Erlang</a>,
<a href="https://www.haskell.org/haskellwiki/Haskell">Haskell</a> but that&rsquo;s a different story.
How does Scala offers Pattern Matching, what is it and finally why is it
valuable?</p>
<h2 id="scala-pattern-matching-by-examples">Scala pattern matching by examples</h2>
<p>As its name indicates, pattern matching is used to detect patterns.
Here is an example that covers a few interesting cases:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scala" data-lang="scala"><span style="color:#66d9ef">def</span> listAnalysis<span style="color:#f92672">(</span>list<span style="color:#66d9ef">:</span> <span style="color:#66d9ef">List</span><span style="color:#f92672">[</span><span style="color:#66d9ef">Any</span><span style="color:#f92672">])</span> <span style="color:#66d9ef">=</span> list <span style="color:#66d9ef">match</span> <span style="color:#f92672">{</span>
   <span style="color:#66d9ef">case</span> <span style="color:#a6e22e">Nil</span> <span style="color:#66d9ef">=&gt;</span> <span style="color:#e6db74">&#34;empty&#34;</span>
   <span style="color:#66d9ef">case</span> <span style="color:#e6db74">&#39;a&#39;</span> <span style="color:#66d9ef">:</span><span style="color:#66d9ef">:</span> <span style="color:#66d9ef">tail</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;starting by &#39;a&#39;&#34;</span>
   <span style="color:#66d9ef">case</span> <span style="color:#f92672">(</span>head<span style="color:#66d9ef">:</span><span style="color:#66d9ef">Int</span><span style="color:#f92672">)</span> <span style="color:#66d9ef">:</span><span style="color:#66d9ef">:</span> <span style="color:#66d9ef">_</span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">head</span> <span style="color:#66d9ef">&gt;</span> <span style="color:#960050;background-color:#1e0010">3</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;starting by an int greater than 3&#34;</span>
   <span style="color:#66d9ef">case</span> <span style="color:#f92672">(</span>head<span style="color:#66d9ef">:</span><span style="color:#66d9ef">Int</span><span style="color:#f92672">)</span> <span style="color:#66d9ef">:</span><span style="color:#66d9ef">:</span> <span style="color:#66d9ef">_</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;starting by an int&#34;</span>
   <span style="color:#66d9ef">case</span> <span style="color:#66d9ef">_</span> <span style="color:#66d9ef">=&gt;</span> <span style="color:#e6db74">&#34;whatever&#34;</span>
<span style="color:#f92672">}</span>
</code></pre></div><p>If you&rsquo;ve never seen any Scala that probably looks like gibberish to
you. Let me break it down:</p>
<pre><code>def listAnalysis(list: List[Any]) = list match {}
</code></pre><p>I define a new function called <code>listAnalysis</code> which takes an argument
named <code>list</code> which is of type <code>List</code> (this list could contain any kind
of elements).
The implementation of this function is a pattern match on the list
argument.
The body of this &lsquo;pattern match&rsquo; looks like a classical switch statement.
But it&rsquo;s actually much more than a simple switch statement. Surely it
could be used like one, but as we will see, it can do much more.</p>
<p>Note that you can apply a pattern match against more than one object at
once as shown a bit later.</p>
<p>Let&rsquo;s look at the statements inside the function.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scala" data-lang="scala"><span style="color:#66d9ef">case</span> <span style="color:#a6e22e">Nil</span> <span style="color:#66d9ef">=&gt;</span> <span style="color:#e6db74">&#34;empty&#34;</span>
</code></pre></div><p>In this case we are checking that the list is empty or nil. If that&rsquo;s
the case, the statement on the other side of the &ldquo;fat arrow&rdquo; is
executed. In this case, we return a string but we could have called
another function or so whatever.</p>
<p>Now the second statement is much more complex and much more powerful:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scala" data-lang="scala"><span style="color:#66d9ef">case</span> <span style="color:#e6db74">&#39;a&#39;</span> <span style="color:#66d9ef">:</span><span style="color:#66d9ef">:</span> <span style="color:#66d9ef">tail</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;starting by &#39;a&#39;&#34;</span>
</code></pre></div><p>Remember that we are doing pattern matching against our list object.
What we are doing here is use the <code>::</code> operator (aka cons operator) to
extract the head and the rest of the list and then we match the head
against the <code>'a'</code> character.</p>
<p>This statement could have been written different ways:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scala" data-lang="scala"><span style="color:#66d9ef">case</span> <span style="color:#e6db74">&#39;a&#39;</span> <span style="color:#66d9ef">:</span><span style="color:#66d9ef">:</span> <span style="color:#66d9ef">rest</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;starting by &#39;a&#39;&#34;</span>
</code></pre></div><p>In that case we named the <code>tail</code> of the list <code>rest</code>, but really we don&rsquo;t
care how it&rsquo;s called or its value, so the sensitive thing to do is to
rewrite that statement like that:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scala" data-lang="scala"><span style="color:#66d9ef">case</span> <span style="color:#e6db74">&#39;a&#39;</span> <span style="color:#66d9ef">:</span><span style="color:#66d9ef">:</span> <span style="color:#66d9ef">_</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;starting by &#39;a&#39;&#34;</span>
</code></pre></div><p>This basically says we are looking for a list that starts by <code>'a'</code> (and we
don&rsquo;t care about the rest).</p>
<p>Another statement:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scala" data-lang="scala"><span style="color:#66d9ef">case</span> <span style="color:#f92672">(</span>head<span style="color:#66d9ef">:</span><span style="color:#66d9ef">Int</span><span style="color:#f92672">)</span> <span style="color:#66d9ef">:</span><span style="color:#66d9ef">:</span> <span style="color:#66d9ef">_</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;starting by an int&#34;</span>
</code></pre></div><p>In this case we type match the first element of the list and check that
we have an integer. Note that using the cons operator in the match cases
doesn&rsquo;t seem to affect performance. It would seem that at compilation,
the statement are rewritten to avoid creating uneeded objects (List also implements structural sharing of the tail list).
I&rsquo;m not a Scala expert so someone with more experience might be able to
confirm/clarify.</p>
<p>Now let&rsquo;s look at a variant of this statement:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scala" data-lang="scala"><span style="color:#66d9ef">case</span> <span style="color:#f92672">(</span>head<span style="color:#66d9ef">:</span><span style="color:#66d9ef">Int</span><span style="color:#f92672">)</span> <span style="color:#66d9ef">:</span><span style="color:#66d9ef">:</span> <span style="color:#66d9ef">_</span> <span style="color:#66d9ef">if</span> <span style="color:#66d9ef">head</span> <span style="color:#66d9ef">&gt;</span> <span style="color:#960050;background-color:#1e0010">3</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;starting by an int greater than 3&#34;</span>
</code></pre></div><p>This is the same statement as above, but we are adding an extra
condition after the match. This is quite useful when simple matching
doesn&rsquo;t cut it.</p>
<p>Finally we have a fallback statement:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scala" data-lang="scala"><span style="color:#66d9ef">case</span> <span style="color:#66d9ef">_</span> <span style="color:#66d9ef">=&gt;</span> <span style="color:#e6db74">&#34;whatever&#34;</span>
</code></pre></div><p>For more information about the cons operator, <a href="https://www.scala-lang.org/node/112">read about the extractor objects</a> and what they can do.</p>
<p>Here is the result of calling our function with different lists:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scala" data-lang="scala">listAnalysis<span style="color:#f92672">(</span><span style="color:#a6e22e">List</span><span style="color:#f92672">())</span>                             <span style="color:#75715e">//&gt; java.lang.String = empty
</span><span style="color:#75715e"></span>listAnalysis<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;This is a test&#34;</span><span style="color:#f92672">.</span>toList<span style="color:#f92672">)</span>            <span style="color:#75715e">//&gt; java.lang.String = whatever
</span><span style="color:#75715e"></span>listAnalysis<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;abcde&#34;</span><span style="color:#f92672">.</span>toList<span style="color:#f92672">)</span>                     <span style="color:#75715e">//&gt; java.lang.String = starting by &#39;a&#39;
</span><span style="color:#75715e"></span>listAnalysis<span style="color:#f92672">(</span><span style="color:#a6e22e">List</span><span style="color:#f92672">(</span><span style="color:#ae81ff">1</span><span style="color:#f92672">,</span><span style="color:#ae81ff">2</span><span style="color:#f92672">,</span><span style="color:#ae81ff">3</span><span style="color:#f92672">))</span>                        <span style="color:#75715e">//&gt; java.lang.String = starting by an int
</span><span style="color:#75715e"></span>listAnalysis<span style="color:#f92672">(</span><span style="color:#a6e22e">List</span><span style="color:#f92672">(</span><span style="color:#ae81ff">42</span><span style="color:#f92672">,</span><span style="color:#ae81ff">24</span><span style="color:#f92672">,</span><span style="color:#ae81ff">36</span><span style="color:#f92672">))</span>                     <span style="color:#75715e">//&gt; java.lang.String = starting by an int greater than 3
</span><span style="color:#75715e"></span>listAnalysis<span style="color:#f92672">(</span><span style="color:#e6db74">&#34;a&#34;</span><span style="color:#f92672">.</span>toList<span style="color:#f92672">)</span>                         <span style="color:#75715e">//&gt; java.lang.String = starting by &#39;a&#39;
</span></code></pre></div><p>Here is another example using 2 items for the match:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-scala" data-lang="scala"><span style="color:#66d9ef">def</span> doubleMatch<span style="color:#f92672">(</span>foo<span style="color:#66d9ef">:</span> <span style="color:#66d9ef">Any</span><span style="color:#f92672">,</span> bar<span style="color:#66d9ef">:</span> <span style="color:#66d9ef">Any</span><span style="color:#f92672">)</span> <span style="color:#66d9ef">=</span> <span style="color:#f92672">(</span>foo<span style="color:#f92672">,</span> bar<span style="color:#f92672">)</span> <span style="color:#66d9ef">match</span> <span style="color:#f92672">{</span>
  <span style="color:#66d9ef">case</span> <span style="color:#f92672">(</span><span style="color:#e6db74">&#39;a&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;b&#39;</span><span style="color:#f92672">)</span> <span style="color:#66d9ef">=&gt;</span> <span style="color:#e6db74">&#34;a and b&#34;</span>
  <span style="color:#66d9ef">case</span> <span style="color:#f92672">(</span><span style="color:#ae81ff">1</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;b&#39;</span><span style="color:#f92672">)</span> <span style="color:#66d9ef">=&gt;</span> <span style="color:#e6db74">&#34;1 and b&#34;</span>
  <span style="color:#66d9ef">case</span> <span style="color:#f92672">(</span><span style="color:#ae81ff">1</span><span style="color:#f92672">,</span> <span style="color:#66d9ef">_</span><span style="color:#f92672">)</span> <span style="color:#66d9ef">=&gt;</span> <span style="color:#e6db74">&#34;1 and &#34;</span><span style="color:#f92672">+</span> bar
  <span style="color:#66d9ef">case</span> <span style="color:#f92672">(</span>a<span style="color:#66d9ef">:</span><span style="color:#66d9ef">Float</span><span style="color:#f92672">,</span> <span style="color:#66d9ef">_</span><span style="color:#f92672">)</span> <span style="color:#66d9ef">=&gt;</span> <span style="color:#e6db74">&#34;foo float&#34;</span>
  <span style="color:#66d9ef">case</span> <span style="color:#66d9ef">_</span> <span style="color:#66d9ef">=&gt;</span> <span style="color:#e6db74">&#34;unknown case&#34;</span>
<span style="color:#f92672">}</span>

doubleMatch<span style="color:#f92672">(</span><span style="color:#ae81ff">1</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#34;test&#34;</span><span style="color:#f92672">)</span>                           <span style="color:#75715e">//&gt; java.lang.String = 1 and test
</span><span style="color:#75715e"></span>doubleMatch<span style="color:#f92672">(</span><span style="color:#ae81ff">1</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;b&#39;</span><span style="color:#f92672">)</span>                              <span style="color:#75715e">//&gt; java.lang.String = 1 and b
</span><span style="color:#75715e"></span>doubleMatch<span style="color:#f92672">(</span><span style="color:#ae81ff">42</span><span style="color:#f92672">,</span> <span style="color:#a6e22e">Nil</span><span style="color:#f92672">)</span>                             <span style="color:#75715e">//&gt; java.lang.String = unknown case
</span><span style="color:#75715e"></span>doubleMatch<span style="color:#f92672">(</span><span style="color:#e6db74">&#39;a&#39;</span><span style="color:#f92672">,</span> <span style="color:#e6db74">&#39;b&#39;</span><span style="color:#f92672">)</span>                            <span style="color:#75715e">//&gt; java.lang.String = a and b
</span><span style="color:#75715e"></span>doubleMatch<span style="color:#f92672">(</span><span style="color:#ae81ff">4.2f</span><span style="color:#f92672">,</span> <span style="color:#ae81ff">42</span><span style="color:#f92672">)</span>                            <span style="color:#75715e">//&gt; java.lang.String = foo float
</span></code></pre></div><h1 id="why-is-pattern-matching-valuable">Why is pattern matching valuable?</h1>
<p>In short, pattern matching allows the developer to deconstruct a structure to find specific
elements, in other words the pattern, needed to then constuct an
object/structure or trigger a function.</p>
<p>It&rsquo;s the opposite process of calling a method on an object. Here we
start from a structure (instead of the instance of an object), this structure is just a basic struct and
based on a found pattern, we then trigger a function (with access to the data if we need it).
When you have a stable and known data structure, it&rsquo;s often very interesting to
use the pattern matching approach because you can easily expand the
operations you can execute. However, if your operations are stable but the data changes,
then the Object Oriented approach seems more adequate.</p>
<p>Besides that, pattern matching will often make your code clearer than
using if/else statements. Especially in a language like Scala where you
can define pattern matching function within a function and you can also
pass pattern matching functions around. Like eveything else, it needs to be used with caution so the intend of
the code is still understandable. That said it&rsquo;s a great tool to have handy and I&rsquo;ve
had a lot of fun rewriting my newbie Scala code using a more idiomatic
approach based on pattern matching.</p>
<p>I hope you enjoyed this quick introduction. You can read more about pattern matching in Scala in the following articles:
<em>(note: <a href="https://ikaisays.com">Ikai</a>&rsquo;s post on how he uses regexps with pattern matching is a fun read.)</em></p>
<ul>
<li><a href="https://www.scala-lang.org/node/120">https://www.scala-lang.org/node/120</a></li>
<li><a href="https://pragprog.com/magazines/2012-03/scala-for-the-intrigued">https://pragprog.com/magazines/2012-03/scala-for-the-intrigued</a></li>
<li><a href="https://kerflyn.wordpress.com/2011/02/14/playing-with-scalas-pattern-matching/">https://kerflyn.wordpress.com/2011/02/14/playing-with-scalas-pattern-matching/</a></li>
<li><a href="https://ikaisays.com/2009/04/04/using-pattern-matching-with-regular-expressions-in-scala/">https://ikaisays.com/2009/04/04/using-pattern-matching-with-regular-expressions-in-scala/</a></li>
<li><a href="https://www.artima.com/scalazine/articles/pattern_matching.html">https://www.artima.com/scalazine/articles/pattern_matching.html</a></li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>ruby class module mixins</title>
			<link>https://matt.aimonetti.net/posts/2012-07-ruby-class-module-mixins/</link>
			<pubDate>Mon, 30 Jul 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-07-ruby-class-module-mixins/</guid>
			<description>When you first get started with the Ruby programming and you come from a different language, the only tricky piece is often Ruby&amp;rsquo;s approach to block/closure/anonymous functions. Sure the metaprogramming seems a bit odd, but you don&amp;rsquo;t have to use it. That&amp;rsquo;s why a lot of developers think that Ruby is a simple language. Turns out that when you dig a bit further, you realize that Ruby is actually quite a complex language.</description>
			<content type="html"><![CDATA[<p>When you first get started with the Ruby programming and you come from a different
language, the only tricky piece is often Ruby&rsquo;s approach to block/closure/anonymous functions.
Sure the metaprogramming seems a bit odd, but you don&rsquo;t have to use it.
That&rsquo;s why a lot of developers think that Ruby is a simple language.
Turns out that when you dig a bit further, you realize that Ruby is
actually quite a complex language. Ask any developer who worked on a
Ruby implementation, they&rsquo;ll all tell you the same thing: Ruby is full of
small little things that makes it complicated.</p>
<p>An example of something that might seem simple is inheritance. Ruby,
unlike C++, doesn&rsquo;t support multiple inheritance. What that means is
that a Ruby class can only have 1 parent class (superclass). However
multiple inheritance can be achieved via modules used as a mixins.
That&rsquo;s a very common pattern, people put some code in a module and then
mix it in/include it in a bunch of classes.
The problem I see though, is that people abuse these concepts and don&rsquo;t
respect the difference between a class, a module and a module used a
mixin.</p>
<h2 id="the-class">The Class</h2>
<p>Object Oriented Programming 101:</p>
<blockquote>
<p>&ldquo;In object-oriented programming, a class is a construct that is used to create instances of itself – referred to as class instances, class objects, instance objects or simply objects. A class defines constituent members which enable its instances to have state and behavior.&rdquo;</p>
</blockquote>
<p>So if you create a class and you don&rsquo;t create instances, you are using
the wrong construct. Here is an example of what I often see:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Settings</span>

  @settings <span style="color:#f92672">=</span> {}
  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">self</span><span style="color:#f92672">.</span><span style="color:#a6e22e">all</span>
    @settings
  <span style="color:#66d9ef">end</span>

  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">self</span><span style="color:#f92672">.</span><span style="color:#a6e22e">[]</span>(key)
    all<span style="color:#f92672">[</span>key<span style="color:#f92672">]</span>
  <span style="color:#66d9ef">end</span>

  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">self</span><span style="color:#f92672">.</span><span style="color:#a6e22e">[]=</span>(key, value)
    all<span style="color:#f92672">[</span>key<span style="color:#f92672">]</span> <span style="color:#f92672">=</span> value
  <span style="color:#66d9ef">end</span>

<span style="color:#66d9ef">end</span>
</code></pre></div><p>Which can be used as such:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">Settings</span><span style="color:#f92672">[</span><span style="color:#e6db74">:secret</span><span style="color:#f92672">]</span> <span style="color:#f92672">=</span> <span style="color:#ae81ff">42</span> <span style="color:#f92672">*</span> <span style="color:#66d9ef">Math</span><span style="color:#f92672">::</span><span style="color:#66d9ef">PI</span> <span style="color:#f92672">*</span> <span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>now<span style="color:#f92672">.</span>to_f
p <span style="color:#66d9ef">Settings</span><span style="color:#f92672">[</span><span style="color:#e6db74">:secret</span><span style="color:#f92672">]</span>
<span style="color:#75715e"># =&gt; 177243152913.2707</span>
</code></pre></div><p><em>(granted this isn&rsquo;t a great example since we could have used a subclass
of <code>Hash</code> but just bear with me)</em></p>
<p>Actually, the developer who wrote the code above would probably also use
some Ruby magic like <code>method_missing</code> to provide a more laxed API and allow for &ldquo;nicer&rdquo; getters
such as <code>Settings.secret</code> and <code>Settings['secret']</code>. I have my
own thoughts on the topic but it&rsquo;s
an entirely different subject.</p>
<p>Note also that the way class level methods are defined
can also be different depending on who wrote the code, you might see the
following variations (and other more esoteric ones):</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Settings</span>

  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">Settings</span><span style="color:#f92672">.</span><span style="color:#a6e22e">all</span>; <span style="color:#66d9ef">end</span>

  <span style="color:#75715e"># or</span>
  <span style="color:#66d9ef">class</span> <span style="color:#f92672">&lt;&lt;</span> self
    <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">all</span>; <span style="color:#66d9ef">end</span>
  <span style="color:#66d9ef">end</span>

<span style="color:#66d9ef">end</span>
</code></pre></div><p>The <code>Settings</code> code above works, the code is simple, yet I will argue one thing: <strong>it&rsquo;s
an abuse of the class construct</strong>. We&rsquo;re breaking the #1 rule of classes:
<em>&ldquo;create instances of self&rdquo;</em>.</p>
<p><strong>It&rsquo;s easy, whenever you don&rsquo;t create instances of a class,
please don&rsquo;t use a class.</strong></p>
<p>That&rsquo;s also true for slightly different examples such as:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">API</span>

  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">fetch</span>(id)
    <span style="color:#66d9ef">HTTP</span><span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#39;https://matt.aimonetti.net/article/:id&#39;</span>, <span style="color:#e6db74">:id</span> <span style="color:#f92672">=&gt;</span> id)
  <span style="color:#66d9ef">end</span>

<span style="color:#66d9ef">end</span>
</code></pre></div><div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">resource <span style="color:#f92672">=</span> <span style="color:#66d9ef">API</span><span style="color:#f92672">.</span>new<span style="color:#f92672">.</span>fetch(<span style="color:#ae81ff">42</span>)
</code></pre></div><p>There is no need whatsoever to create an instance of <code>API</code>, using a class is
picking the wrong construct. Also, I don&rsquo;t care if you use the <code>Singleton</code>
module to only allow 1 instance of the class, you still shouldn&rsquo;t use a
class in the above example.</p>
<h2 id="the-module">The Module</h2>
<p>In Ruby&rsquo;s object hierarchy, the Class object actually inherits from the
Module object.</p>
<pre><code>ruby -v -e &quot;p Class.ancestors&quot;
ruby 1.9.3p194 (2012-04-20 revision 35410) [x86_64-darwin11.3.0]
[Class, Module, Object, Kernel, BasicObject]
</code></pre><p>As per Ruby&rsquo;s source code defintion:</p>
<blockquote>
<p>&ldquo;A Module is a collection of methods and constants.&rdquo;</p>
</blockquote>
<p>I like to think of modules as namespaced methods and constants. Whenever
you want code that logically belongs together but that
won&rsquo;t require that you create instances of a &lsquo;model&rsquo;, then a module is
the right construct to use.</p>
<p>As a matter of fact, the two examples above are great cases where a
module should have been used.</p>
<p>The confusing bit is that modules can have module level methods but also
instance level methods. Here is an example:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">module</span> API

  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">self</span><span style="color:#f92672">.</span><span style="color:#a6e22e">fetch</span>(id)
    <span style="color:#66d9ef">HTTP</span><span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#39;https://matt.aimonetti.net/article/:id&#39;</span>, <span style="color:#e6db74">:id</span> <span style="color:#f92672">=&gt;</span> id)
  <span style="color:#66d9ef">end</span>

<span style="color:#66d9ef">end</span>
</code></pre></div><p>This is a module level function, it could also be written like that:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">module</span> API

  <span style="color:#66d9ef">module_function</span>

  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">fetch</span>(id)
    <span style="color:#66d9ef">HTTP</span><span style="color:#f92672">.</span>get(<span style="color:#e6db74">&#39;https://matt.aimonetti.net/article/:id&#39;</span>, <span style="color:#e6db74">:id</span> <span style="color:#f92672">=&gt;</span> id)
  <span style="color:#66d9ef">end</span>

<span style="color:#66d9ef">end</span>
</code></pre></div><p>And be used like that:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">resource <span style="color:#f92672">=</span> <span style="color:#66d9ef">API</span><span style="color:#f92672">.</span>fetch(<span style="color:#ae81ff">42</span>)
</code></pre></div><p>Until now, it makes sense. The weird thing is that even though, modules
unlike classes aren&rsquo;t meant to create instances, we have the possibility
to define module instance methods.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">module</span> Settings

  <span style="color:#66d9ef">DATA</span> <span style="color:#f92672">=</span> {<span style="color:#e6db74">repo</span>: <span style="color:#e6db74">&#39;https://github.com/mattetti&#39;</span>}

  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">repository</span>
    <span style="color:#66d9ef">DATA</span><span style="color:#f92672">[</span><span style="color:#e6db74">:repo</span><span style="color:#f92672">]</span>
  <span style="color:#66d9ef">end</span>

  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">secret_key</span>
    <span style="color:#66d9ef">DATA</span><span style="color:#f92672">[</span><span style="color:#e6db74">:key</span><span style="color:#f92672">]</span> <span style="color:#f92672">||=</span> <span style="color:#ae81ff">42</span><span style="color:#f92672">*</span><span style="color:#66d9ef">Math</span><span style="color:#f92672">::</span><span style="color:#66d9ef">PI</span>
  <span style="color:#66d9ef">end</span>

<span style="color:#66d9ef">end</span>
</code></pre></div><p>Great, but we can&rsquo;t actually use these methods since they are instance
methods and we don&rsquo;t create instances of modules. Well, that isn&rsquo;t quite
true, there is a way to access them and that&rsquo;s by using a module as a
mixin. What that means is that we inject/copy the module code inside a
class or an(other) object. Example in code:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">a <span style="color:#f92672">=</span> <span style="color:#66d9ef">Object</span><span style="color:#f92672">.</span>new
a<span style="color:#f92672">.</span>extend(<span style="color:#66d9ef">Settings</span>)
a<span style="color:#f92672">.</span>repository
<span style="color:#75715e"># =&gt; &#34;https://github.com/mattetti&#34;</span>
</code></pre></div><p>Or we can add the code to a class so the instances of this class can
access our module instance methods:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Foo</span>
  <span style="color:#66d9ef">include</span> <span style="color:#66d9ef">Settings</span>
<span style="color:#66d9ef">end</span>

<span style="color:#66d9ef">Foo</span><span style="color:#f92672">.</span>new<span style="color:#f92672">.</span>repository
<span style="color:#75715e"># =&gt; &#34;https://github.com/mattetti&#34;</span>
</code></pre></div><h2 id="the-mixin-modules">The mixin modules</h2>
<p>There a plenty of resources online about the many ways to use mixins in Ruby to achieve multiple inheritance and do cool stuff.
But the point of this article is to try to demonstrate that mixins
shouldn&rsquo;t be abused.</p>
<p>My problem with the above example is that by mixing in the <code>Settings</code>
module inside our <code>Foo</code> class, we created an uneeded, confusing extra
level of abstraction. Instances of <code>Foo</code> now have access to two
methods/objects: <code>repository</code> and <code>secret_key</code>. These methods or the
objects they refer to don&rsquo;t belong to the <code>Foo</code> class, but it seems
convenient to not have to type <code>Settings.repository</code> so we mixed things
in. Plus, a lot of Ruby developers seem to dislike adding class/module
level methods so they feel that this approach &lsquo;feels better&rsquo;.</p>
<p>Here is the thing, the convenience of typing a few less characters isn&rsquo;t
worth it. Next time you or someone else will look at an instance of the
<code>Foo</code> class calling <code>repository</code>, finding where it is defined is going
to be a pain. That&rsquo;s especially true if you have many mixins in your
class. <code>Settings</code> will also probably grow and you will end up with a
bunch of methods that have nothing to do with your class instances.
In this case, I will call the use of a mixin, an abuse of construct.
Sure, Ruby allows you to do it, but that doesn&rsquo;t mean it&rsquo;s the right
thing to do. In Ruby, unlike in Python, there are 101 ways to do a
simple thing. It doesn&rsquo;t mean that the 101 ways are good, it just means
that Matz wasn&rsquo;t sure how people would use his programming language and
chose to give us more freedom to messup/doing it our own way.</p>
<h3 id="when-to-use-mixins">When to use mixins?</h3>
<p>I have my own rule: use mixins whenever you need to <em>share behaviors</em> between
different classes.</p>
<p>In the above example, we weren&rsquo;t sharing behaviors, we were sharing
objects, there was no need to actually use a mixin.</p>
<p>That said, rules aren&rsquo;t rules without exceptions. A good example of this
exception would be the <code>Math</code> module from the standard library.
This module offers trigonometric and transcendental functions. You might
think that this module would be designed to be a mixin so you can get
<code>log</code>, <code>cos</code>, <code>exp</code> and friends available in your math related classes.
It turns out, all Math&rsquo;s methods are defined a module functions meaning
that they are meant to be called from the <code>Math</code> module directly.</p>
<p>However, Ruby allows you to mixin module functions, but these functions
become private. If you do include the module inside your class, your instance methods
will be able to call <code>hypot(x,y)</code> directly, but these methods won&rsquo;t be
available from the outside (<code>Foo.new.log(42)</code> would raise an
exception).</p>
<p>To conclude with mixins: mixins are great but don&rsquo;t abuse them or you
will endup with so much abstraction that your coworkers will secretely
call you <a href="https://en.wikipedia.org/wiki/Wassily_Kandinsky">Kandinsky</a>.
Stick to simple mixins allowing you to share behaviors between at least
a couple classes. See <code>DataMapper</code> for a great way to use mixins.</p>
<h2 id="modules-your-secret-functional-programming-weapon">Modules: your secret functional programming weapon</h2>
<p>I have to say that I do like functional programming. The idea of having
functions not mutating the states of things around them pleases me. It
just seems clean, you feed data to a function and you get another piece
of data. No states were changed, maybe some temporary variables were
allocated to process the data, but the only thing that matters is the
input and the output. Easy to grasp, easy to follow, no magical states
being changed by some code fairies.</p>
<p>The good news is that Ruby allows us to write code like that. And this
is where modules are great. Very much like the <code>Math</code> module we
discussed above, there are many cases where you want to have a bunch of
functions that process an input and provide an output without keeping
any states. A good example of such a module would be a param
verification filter. The filter takes an input, takes some rules and
verifies that the input matches the rules.
Surely, we could create an instance for each verification, this would
allow to keep states in our class and do the usual OOP things. But we
could also simply use a module with a bunch of module (level) functions
that would pass to each other the input they need to not need to keep
states. The end result will be faster, nicer on the GC and easy to
follow.</p>
<p>Mixing OOP and functional programming isn&rsquo;t new, ask <a href="https://www.scala-lang.org/">Scala</a> developers!
If done right, by adopting this approach we can simply our code base,
make it faster, easier to maintain and not losing the chance to also use
OOP paradigms when needed.</p>
<h2 id="compromise">Compromise</h2>
<p>As shown earlier, modules and classes have pros and cons. Classes are
however much more natural to use for Object Oriented Programming. A
compromise about the <code>Settings</code> examples was suggested by Evan Phoenix.
The solution is elegant and simple. Use a class and an instance.
Here is an implementation based on his suggestion:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">AppSettings</span> <span style="color:#f92672">&lt;</span> <span style="color:#66d9ef">Hash</span>

  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">custom_method</span>
  <span style="color:#66d9ef">end</span>

<span style="color:#66d9ef">end</span>

<span style="color:#66d9ef">SETTINGS</span> <span style="color:#f92672">=</span> <span style="color:#66d9ef">AppSettings</span><span style="color:#f92672">.</span>new
</code></pre></div><p>The point here is not about the class implementation but that fact that we use
a class and associate an instance of this class to a constant so it can
be shared all over the place. Wow, a constant, this is so nasty you
might think. Classes are constants too and so are modules, here we just
allocate an instance of a class to a constant. Surpisingly simple and efficient.</p>
]]></content>
		</item>
		
		<item>
			<title>ruby the differences between dup and clone</title>
			<link>https://matt.aimonetti.net/posts/2012-07-ruby-the-differences-between-dup-and-clone/</link>
			<pubDate>Sat, 28 Jul 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-07-ruby-the-differences-between-dup-and-clone/</guid>
			<description>Have you ever wondered what the differences are between #dup and #clone in Ruby?
They both create a shallow copy of an object (meaning that they don&amp;rsquo;t copy the objects that might be referenced within the copied object). However, #clone does two things that #dup doesn&amp;rsquo;t:
 copy the singleton class of the copied object maintain the frozen status of the copied object  Examples of the singleton methods not being copied.</description>
			<content type="html"><![CDATA[<p>Have you ever wondered what the differences are between <strong>#dup</strong> and <strong>#clone</strong> in Ruby?</p>
<p>They both create a shallow copy of an object (meaning that they don&rsquo;t copy the objects that might be referenced within the copied object). However, <strong>#clone</strong> does two things that <strong>#dup</strong> doesn&rsquo;t:</p>
<ul>
<li>copy the singleton class of the copied object</li>
<li>maintain the frozen status of the copied object</li>
</ul>
<p>Examples of the singleton methods not being copied.</p>
<p>dup:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">a <span style="color:#f92672">=</span> <span style="color:#66d9ef">Object</span><span style="color:#f92672">.</span>new
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">a</span><span style="color:#f92672">.</span><span style="color:#a6e22e">foo</span>; <span style="color:#e6db74">:foo</span> <span style="color:#66d9ef">end</span>
p a<span style="color:#f92672">.</span>foo
<span style="color:#75715e"># =&gt; :foo</span>
b <span style="color:#f92672">=</span> a<span style="color:#f92672">.</span>dup
p b<span style="color:#f92672">.</span>foo
<span style="color:#75715e"># =&gt; undefined method `foo&#39; for #&lt;Object:0x007f8bc395ff00&gt; (NoMethodError)</span>
</code></pre></div><p>vs clone:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">a <span style="color:#f92672">=</span> <span style="color:#66d9ef">Object</span><span style="color:#f92672">.</span>new
<span style="color:#66d9ef">def</span> <span style="color:#a6e22e">a</span><span style="color:#f92672">.</span><span style="color:#a6e22e">foo</span>; <span style="color:#e6db74">:foo</span> <span style="color:#66d9ef">end</span>
p a<span style="color:#f92672">.</span>foo
<span style="color:#75715e"># =&gt; :foo</span>
b <span style="color:#f92672">=</span> a<span style="color:#f92672">.</span>clone
p b<span style="color:#f92672">.</span>foo
<span style="color:#75715e"># =&gt; :foo</span>
</code></pre></div><p>Frozen state:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">a <span style="color:#f92672">=</span> <span style="color:#66d9ef">Object</span><span style="color:#f92672">.</span>new
a<span style="color:#f92672">.</span>freeze
p a<span style="color:#f92672">.</span>frozen?
<span style="color:#75715e"># =&gt; true</span>
b <span style="color:#f92672">=</span> a<span style="color:#f92672">.</span>dup
p b<span style="color:#f92672">.</span>frozen?
<span style="color:#75715e"># =&gt; false</span>
c <span style="color:#f92672">=</span> a<span style="color:#f92672">.</span>clone
p c<span style="color:#f92672">.</span>frozen?
<span style="color:#75715e"># =&gt; true</span>
</code></pre></div><p>Looking at the <a href="https://github.com/rubinius/rubinius/blob/master/kernel/alpha.rb#L230">Rubinius source code</a> makes the difference extremely obvious.</p>
<p>Because of the extra steps, <strong>clone</strong> is a bit slower than <strong>dup</strong> but that&rsquo;s probably <strong>not</strong> what will make your app too slow.</p>
<p>Just a quick note about shallow copies (true for <strong>clone</strong> and <strong>dupe</strong>). Notice how the array referenced by the bar attribute doesn&rsquo;t get copied but shared between the original and the copied instances:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">class</span> <span style="color:#a6e22e">Foo</span>
  <span style="color:#66d9ef">attr_accessor</span> <span style="color:#e6db74">:bar</span>
  <span style="color:#66d9ef">def</span> <span style="color:#a6e22e">initialize</span>
    self<span style="color:#f92672">.</span>bar <span style="color:#f92672">=</span> <span style="color:#f92672">[</span><span style="color:#ae81ff">1</span>,<span style="color:#ae81ff">2</span>,<span style="color:#ae81ff">3</span><span style="color:#f92672">]</span>
  <span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">end</span>

a <span style="color:#f92672">=</span> <span style="color:#66d9ef">Foo</span><span style="color:#f92672">.</span>new
b <span style="color:#f92672">=</span> a<span style="color:#f92672">.</span>clone
p a<span style="color:#f92672">.</span>bar
<span style="color:#75715e"># =&gt; [1, 2, 3]</span>
p b<span style="color:#f92672">.</span>bar
<span style="color:#75715e"># =&gt; [1, 2, 3]</span>
a<span style="color:#f92672">.</span>bar<span style="color:#f92672">.</span>clear <span style="color:#75715e"># clearing the array #bar points to</span>
p a<span style="color:#f92672">.</span>bar
<span style="color:#75715e"># =&gt; []</span>
p b<span style="color:#f92672">.</span>bar
<span style="color:#75715e"># =&gt; []</span>
</code></pre></div><p>Both objects, <strong>a</strong> and <strong>b</strong> share the same reference to the array instance created when <strong>a</strong> is initiated. There are a few ways to do a deep copy of an object, but that&rsquo;s a different matter.</p>
]]></content>
		</item>
		
		<item>
			<title>rethinking web service development</title>
			<link>https://matt.aimonetti.net/posts/2012-06-rethinking-web-service-development/</link>
			<pubDate>Wed, 13 Jun 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-06-rethinking-web-service-development/</guid>
			<description>While it&amp;rsquo;s true that there are still a lot of places where software isn&amp;rsquo;t leveraged and many places where software needs to evolve, software is nearly everywhere!. The type of software we write today needs to interact with other software via some sort of network. Any web developer out there is used to that, (s)he writes software that runs on a server somewhere on the internet and users via a local software (browser) consume their web applications using an internet connection.</description>
			<content type="html"><![CDATA[<p>While it&rsquo;s true that there are still a lot of places where software isn&rsquo;t
leveraged and many places where software needs to evolve, software is nearly everywhere!.
The type of software we write today needs to interact
with other software via some sort of network.
Any web developer out there is used to that, (s)he writes software that
runs on a server somewhere on the internet and users via a local software
(browser) consume their web applications using an internet connection.</p>
<p>What has changed in the last few years is that web applications start
providing more than just dynamically rendered HTML templates.
JavaScript is used to run more and more logic on the client side and JS
usually talks to some backends via JSON.
But web APIs are also more and more used to expose raw data to other
software. <strong>The challenge though, is that we haven&rsquo;t changed the way we
write web applications to adapt to this new way of providing data.</strong>
In this article, I&rsquo;d like to explore why and how we need to rethink web API development
and focus on communication and interaction.</p>
<h2 id="unlearning">Unlearning</h2>
<p><a href="{{ root_url }}/images/matt_aimonetti-unlearn.jpeg"><img src="{{ root_url }}/images/matt_aimonetti-unlearn.jpeg"
style="width:250px;display:block;margin:auto"/></a></p>
<p>Many are used to doing certain
things a certain way and it&rsquo;s really hard to unlearn old habits. The more
concerning part of this fact is that it makes it <strong>hard for someone to step
back and evaluate honestly if a technical decision is due to comfort or
if it&rsquo;s truly the right choice to achieve a given goal.</strong>
Ruby on Rails revolutionized the way we wrote web applications almost 10
years ago and since then, many web frameworks have adopted the Rails philosophy.
As a matter of fact, I personally think that when it comes to writing
front end applications, Rails is still one if not the best web
frameworks out there. But in its current state, I&rsquo;m far from convinced that it&rsquo;s a great tool to write
web APIs mainly because it was not designed for that and because it
comes with a lot of baggage.</p>
<h2 id="focusing-on-the-api">Focusing on the API</h2>
<p>Let&rsquo;s take a step back and consider what is critical when developing a web
API:</p>
<ul>
<li><strong>Documentation</strong> for end users to know how to consume your services.</li>
<li><strong>Consistent and reliable</strong> output so you don&rsquo;t break client applications
relying on your services.</li>
<li><strong>Maintainability</strong></li>
</ul>
<p>Note that I didn&rsquo;t mention performance because I consider performance
almost always being important.
I also didn&rsquo;t mention the whole
<a href="https://en.wikipedia.org/wiki/Representational_state_transfer">REST</a>/<a href="https://en.wikipedia.org/wiki/Remote_procedure_call">RPC</a>/<a href="https://en.wikipedia.org/wiki/Hypermedia">Hypstermedia</a> debate
since I consider it being an implementation detail and a totally orthogonal
discussion. But for the record, I personally don&rsquo;t like solutions forcing you into a specific way of
providing your data (I&rsquo;m looking at you <a href="https://wiki.basho.com/Webmachine.html">webmachine</a>).</p>
<h3 id="documentation">Documentation</h3>
<p>Documentation isn&rsquo;t as important when you consume your own APIs because
you can look at your source code. However it gets much more tricky when
you start working with other teams. They might not know the
language/framework you use. They might not have time to go dig into your
source code to figure out what your <strong>meta-magical piece of clever
code</strong> does.</p>
<p>Lately more and more applications provide their raw data to the
outside world via web APIs. The developers who will consume your
resources don&rsquo;t have access to your source code, probably don&rsquo;t use the same
programming language and don&rsquo;t have much time to guess how your API
work. Also your test suite won&rsquo;t help communicate how your API works so
we need to find a different approach.
Also note that in this scenario, TDD/BDD won&rsquo;t help us communicate
better and tests can&rsquo;t be used as documentation since your tests aren&rsquo;t
exposed.</p>
<p><em>Documentation is your #1 way to communicate with your human audience.</em>
Communication is key and even if as engineers we love to focus on code, if we
can&rsquo;t communicate about it, end users will have a hard time using our
code and might just not even do it. <strong>The key is to communicate what your API does,
why someone might want to use it and how to use it.</strong></p>
<h3 id="consistent-and-reliable-output">Consistent and reliable output</h3>
<p>This point seems obvious but what we realize in reality is that
for many, API&rsquo;s consistency and reliability doesn&rsquo;t include
documentation. You find a lot of APIs out there poorly documented or out
of sync with the actual implementation.</p>
<p><strong>Documentation is a contract between
you: the developer and the other developers consuming your APIs.</strong>
As a developer, when you write any type of tests, they become some sort of quality contract.
If someone changes your code and break your tests, they break the implicit contract.
However, when talking about consuming data via an API, things get a bit more complicated.
We need a way to ensure that the end user expectations are matching our
implementation/documentation. Unit testing simply can&rsquo;t guarantee that. Unit testing will
guarantee that the logic of your units of code is intact but it can&rsquo;t
easily guarantee that the API output matches the documentation, however
this is something that has to be done.</p>
<h3 id="maintainability">Maintainability</h3>
<p>This is a tricky point since maintainability is very subjective. But I
think we can agree that <a href="https://en.wikipedia.org/wiki/Decoupling#Software_development">decoupling</a>/<a href="https://en.wikipedia.org/wiki/Separation_of_concerns">separating concerns</a>
will make our code more maintainable.</p>
<p>That&rsquo;s why I personally don&rsquo;t think it&rsquo;s a good idea to mix HTML
rendering code and web API code. Consider using different controllers or
different files depending on the way your code is structured.</p>
<p>I also strongly believe that the implementation details shouldn&rsquo;t define
the way you design your web APIs. Don&rsquo;t just slap a CRUD API on top of your
model and call it done. In most cases, you will pay a high price later
on if you take this approach because whenever you will need to change your
web API or your model, you will be stuck. This is because your interface
is now used by a lot of people and you can&rsquo;t easily change it.
There are many ways to avoid API/model coupling, I don&rsquo;t advocate one particularly, but whatever you do,
be sure you can make your models and APIs can evolve separately.</p>
<p><br><br></p>
<h2 id="my-approach">My approach</h2>
<p>I&rsquo;ve been designing and developing web APIs for many years and I&rsquo;ve been
struggling with everything I mentioned until now.
I don&rsquo;t claim that I&rsquo;ve found <strong>the</strong> solution but I&rsquo;d like to think that I
found one own way of addressing what are for me some of the most important parts
of API design.</p>
<h2 id="being-explicit">Being explicit</h2>
<p>I believe that there is value in being explicit in the way we describe
web APIs. Sometimes people get confused between being <a href="https://en.wiktionary.org/wiki/verbose">verbose</a> and being
<a href="https://en.wiktionary.org/wiki/explicit">explicit</a>. These are two different concepts.
Being explicit can sometimes seem verbose, but we need to evaluate the
value that can be extracted from the provided information. If there isn&rsquo;t any clear value and too many words are used, then we
aren&rsquo;t explicit, we are verbose.</p>
<p>When designing a web API, I don&rsquo;t write it for myself, I do it for someone
else. <strong>It&rsquo;s crucial to consider who you are writing for
and to expose what&rsquo;s important for them.</strong>
A &ldquo;small&rdquo; problem is that we don&rsquo;t show our code to our end users, so we
need to find a way to explicitly provide the important information and
to have this information provided to our end users.</p>
<h2 id="dsl">DSL</h2>
<p>For that I use a Domain Specific Language (DSL) which is a fancy way to
say that I have some specific code allowing me to explicitly define my
web services. These services exist as objects that can then be used to
<em>process requests</em> but also to <em>validate inputs</em>, and even more importantly
to <em>generate documentation</em>.</p>
<p>The DSL allows me to define the following:</p>
<ul>
<li>details about consuming the service (uri, HTTP verb, authentication details,
other service details&hellip;)</li>
<li>incoming params (which ones are allowed, the type, are they required,
optional?, what are they for)</li>
<li>service output</li>
</ul>
<p>The input details is really important to validate incoming requests and
reject them before even dispatching them. This is done for data sanity
and for security reason. It also defines a strong interface that is
easier to develop against and to maintain.</p>
<p>The output details might sound quite surprising and redundant. After all, isn&rsquo;t that a
duplication of effort since we already have this information in the
&ldquo;view&rdquo;? Well, if we consider the important points I highlighted in the
first part of this article, we need a way to enforce a &ldquo;contract&rdquo;
between the end users and our implementation. To do that, we can&rsquo;t
simply rely on our code since we can&rsquo;t trust it. The output is important
to document the expected output but also to validate that our services
match our documentation and therefore our &ldquo;contract&rdquo;.</p>
<p>Here is an example of a Ruby <a href="https://github.com/mattetti/Weasel-Diesel">DSL</a> use to describe a hello world service:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">describe_service <span style="color:#e6db74">&#34;hello_world&#34;</span> <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>service<span style="color:#f92672">|</span>
  service<span style="color:#f92672">.</span>formats   <span style="color:#e6db74">:json</span>
  service<span style="color:#f92672">.</span>http_verb <span style="color:#e6db74">:get</span>
  service<span style="color:#f92672">.</span>disable_auth <span style="color:#75715e"># on by default</span>

  <span style="color:#75715e"># INPUT</span>
  service<span style="color:#f92672">.</span>param<span style="color:#f92672">.</span>string  <span style="color:#e6db74">:name</span>, <span style="color:#e6db74">:default</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#39;World&#39;</span>, <span style="color:#e6db74">:doc</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;The name of the person to greet.&#34;</span>

  <span style="color:#75715e"># OUTPUT</span>
  service<span style="color:#f92672">.</span>response <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>response<span style="color:#f92672">|</span>
    response<span style="color:#f92672">.</span>object <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>obj<span style="color:#f92672">|</span>
      obj<span style="color:#f92672">.</span>string <span style="color:#e6db74">:message</span>, <span style="color:#e6db74">:doc</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;The greeting message sent back. Defaults to &#39;World&#39;&#34;</span>
      obj<span style="color:#f92672">.</span>datetime <span style="color:#e6db74">:at</span>, <span style="color:#e6db74">:doc</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;The timestamp of when the message was dispatched&#34;</span>
    <span style="color:#66d9ef">end</span>
  <span style="color:#66d9ef">end</span>

  <span style="color:#75715e"># DOCUMENTATION</span>
  service<span style="color:#f92672">.</span>documentation <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>doc<span style="color:#f92672">|</span>
    doc<span style="color:#f92672">.</span>overall <span style="color:#e6db74">&#34;This service provides a simple hello world implementation example.&#34;</span>
    doc<span style="color:#f92672">.</span>example <span style="color:#e6db74">&#34;&lt;code&gt;curl -I &#39;https://localhost:9292/hello_world?name=Matt&#39;&lt;/code&gt;&#34;</span>
  <span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">end</span>
</code></pre></div><p>The DSL style isn&rsquo;t really important, what&rsquo;s important is that it allows
us to address some of the concerns we discussed earlier such as clearly
defined interface that can be communicated as documentation but also
acts as code. The focus is really on the API and everything fits in one
page. Because everything is an object and can be inspected, proper
and up to date documentation can be generated. And the implementation
can be tested against the documentation since everything is maintained
as code.</p>
<h2 id="being-agnostic">Being agnostic</h2>
<p>While I like Ruby for many reasons, I don&rsquo;t think that it&rsquo;s the only
good language to implement great web services. It actually has its pros
and cons and so have all the web frameworks out there.
That&rsquo;s why I wrote my DSL as a <a href="https://github.com/mattetti/Weasel-Diesel">standalone library</a> that could virtually
run on top of any web engine since it only outputs a representation of services.</p>
<p>While I hope to one day create an interesting interop solution across
programming language (by exporting the objects in a shared data
structure for instance), I started by focusing on the various Ruby web
frameworks.</p>
<p>The best starting point for me was to use <a href="https://www.sinatrarb.com/">Sinatra</a>.
I almost started just using <a href="https://rack.github.com/">rack</a>, but <a href="https://www.sinatrarb.com/">Sinatra</a> was providing me with a bit more feature for very
little headache and little code to grasp. I wrote <a href="https://github.com/mattetti/wd-sinatra">wd-sinatra</a> which
is a Ruby gem providing the <a href="https://github.com/mattetti/Weasel-Diesel">WeaselDiesel DSL</a> on top of a Sinatra app.
It comes with a generator and all the needed hooks to design, implement, test and
generate documentation for modern web APIs.</p>
<p>Using a simple rake command (Ruby&rsquo;s version of make) one can generate
documentation or test the APIs against the implementations.
The &ldquo;mini framework&rdquo; is still very free form and should let you do
whatever you want. I don&rsquo;t even set a default ORM for you to use since
this choice is highly personal. I do however leave you places to set
these things.</p>
<p><a href="{{ root_url }}/images/matt_aimonetti-WeaselDiesel_doc_generation.jpeg"><img src="{{ root_url }}/images/matt_aimonetti-WeaselDiesel_doc_generation.jpeg" style="width:200px;display:block;margin:auto" title="Matt Aimonetti - WeaselDiesel documentation generation example" alt="Matt Aimonetti - WeaselDiesel documentation generation example"></a></p>
<p>Sinatra and my &ldquo;freedom framework&rdquo; might seem too free form for
you. So I&rsquo;m currently working on getting the DSL to run on top of Rails,
and by goal is to actually get it to run with a normal Rails app.</p>
<h2 id="reconsidering-rails-mvc">Reconsidering Rails' MVC</h2>
<p>The Rails code base is very deeply marked with its own concept of MVC and having controllers and actions.
The challenge I have is that I like my service to be self contained. I
want my services to be simple and easy to grasp. I like having 1 service
per file. Models, libraries and other optional presenters/decorators live separately
but I like to have my service implementation code with the rest of my
service description. I honestly don&rsquo;t like telling developers that they
need to go check a route file and that my simple service requires that
you open 12 files to understand what&rsquo;s going on. Simpler is often better
and that&rsquo;s why in <a href="https://github.com/mattetti/wd-sinatra">wd-sinatra</a>
the DSL and the implementation live together which is quite harder to do
with Rails.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">describe_service <span style="color:#e6db74">&#34;hello_world&#34;</span> <span style="color:#66d9ef">do</span> <span style="color:#f92672">|</span>service<span style="color:#f92672">|</span>

  <span style="color:#75715e"># [...] see the DSL section to see how the</span>
  <span style="color:#75715e"># service is described. The block below is being</span>
  <span style="color:#75715e"># being called in the context of the request</span>
  <span style="color:#75715e"># after the request was validated.</span>

  <span style="color:#75715e"># SERVICE IMPLEMENTATION</span>
  <span style="color:#75715e"># the returned value is used as the response body, all the Sinatra helpers</span>
  <span style="color:#75715e"># are available.</span>
  service<span style="color:#f92672">.</span>implementation <span style="color:#66d9ef">do</span>
    {<span style="color:#e6db74">:message</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;Hello </span><span style="color:#e6db74">#{</span>params<span style="color:#f92672">[</span><span style="color:#e6db74">:name</span><span style="color:#f92672">]</span><span style="color:#e6db74">}</span><span style="color:#e6db74">&#34;</span>, <span style="color:#e6db74">:at</span> <span style="color:#f92672">=&gt;</span> <span style="color:#66d9ef">Time</span><span style="color:#f92672">.</span>now}<span style="color:#f92672">.</span>to_json
  <span style="color:#66d9ef">end</span>
<span style="color:#66d9ef">end</span>
</code></pre></div><h2 id="learning-from-experience">Learning from experience</h2>
<p>While the DSL fits most of my needs, we all have different use cases.
While it&rsquo;s critical for a library to have a clearly defined objective, it&rsquo;s also important to
have many people help improve it. Part of the learning/vetting
excercise is to test an approach against different needs to define when
and why it works well in some cases and why sometinmes it doesn&rsquo;t. This
allows us to define a sweet spot that should match the clearly defined
objective. However to be able to do that, a design needs to be tested by
many people. So far my approach seems to work very well when an
API needs to live outside an application and that 3rd parties need to
consume the resources. It also seems to work well with edge cases that
many API designers seem to encounter sooner or later.</p>
<h2 id="conclusion">Conclusion</h2>
<p>At the end of the day, we have to remember that API stands for
<em>Application Programming Interface</em> and that these interfaces have to be
programmed so humans can write to comsume them. One of Ruby&rsquo;s main design points has always
been to try to address human needs more than computer&rsquo;s. As API
designers/implementers, it seems important to adopt the same approach and
consider who will use our interfaces.
I think the discussion should focus more on what to value when
defining web APIs, instead of arguing about how to implement APIs.
Standardization is a great concept but a really hard to implement. And
even with standards, we have to find a way to communicate with the API
users to express what standards we follow and where to find the various
entry points.
Think about your API, <strong>how well does it
communicate with your future API users</strong>, is it good enough for them to get
excited? Is it good enough for them to create something amazing with it?
If not, why not?</p>
<h3 id="discussion">Discussion</h3>
<p>Comments are available on <a href="https://news.ycombinator.com/item?id=4107126">this HackerNews thread</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>macruby on ios rubymotion review</title>
			<link>https://matt.aimonetti.net/posts/2012-05-macruby-on-ios-rubymotion-review/</link>
			<pubDate>Fri, 04 May 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-05-macruby-on-ios-rubymotion-review/</guid>
			<description>Yesterday, RubyMotion was released and let&amp;rsquo;s be honest, it is one the best alternatives to Objective-C out there (if not the best).
RubyMotion is a commercial, proprietary fork of MacRuby that targets iOS. This is not a small achievement, MacRuby relies on Objective C&amp;rsquo;s Garbage Collector (libauto) which is not available on iOS. Static compilation and new memory management solution was required to target the iOS platform . The new runtime had to be small and efficient.</description>
			<content type="html"><![CDATA[<p>Yesterday, <a href="https://www.rubymotion.com/">RubyMotion</a> was released and let&rsquo;s be honest, it is one the best alternatives to Objective-C out there (if not the best).</p>
<p>RubyMotion is a commercial, proprietary fork of MacRuby that targets iOS. This is not a small achievement, MacRuby relies on Objective C&rsquo;s Garbage Collector (libauto) which is not available on iOS. Static compilation and new memory management solution was required to target the iOS platform . The new runtime had to be small and efficient. Furthermore, being able to run code on iOS isn&rsquo;t enough, you need tools to interact with the compiler, to debug, to packages applications etc&hellip;</p>
<p>I don&rsquo;t think anyone will contest the fact that RubyMotion is a well done product. The question however is, &ldquo;<strong>is it worth for you to invest some money, time and energy in this product instead of using Apple&rsquo;s language and tools</strong>&rdquo;. In this article, I&rsquo;ll try to balance the pros and cons of RubyMotion so you can have a better understanding of what RubyMotion could mean for you. As a disclaimer I should say that I was beta testing RubyMotion, that they are strong ties between RubyMotion and the MacRuby project I&rsquo;m part of and finally that having MacRuby on iOS has been something I&rsquo;ve been looking forward for a very long time.</p>
<p>Over the last few months I&rsquo;ve seen RubyMotion take shape and finally hit the big 1.0. As you can see from <a href="https://twitter.com/#!/search/rubymotion?q=rubymotion">Twitter</a> and <a href="https://news.ycombinator.com/item?id=3924657">HackerNews</a>, the Ruby community is excited about being able to use their language to write statically compiled, native iOS apps. Spoiler alert, they are right, it&rsquo;s a lot of fun.</p>
<p> </p>
<hr>
<p> </p>
<h2 id="what-i-like-about-rubymotion">What I like about RubyMotion:</h2>
<h3 id="ruby-language">Ruby Language</h3>
<p>I don&rsquo;t mind Objective-C, I think it&rsquo;s a fine superset of C, with the arrival of blocks, new literals and automatic memory management via ARC, Objective-C is actually getting better over time. But frankly, it&rsquo;s not Ruby. You still have to deal with headers, you always have to compile your code via some weird Xcode voodoo settings, testing is a pain, the language, even with the new literals is quite verbose. On the other hand, using Ruby syntax I can get much more flexibility, reuse my code via mixins, easily reopen existing classes etc&hellip; At the end of the day, I end up with some code that seems cleaner, easier to understand and maintain even though I&rsquo;m calling the same underlying APIs. Ruby&rsquo;s flexibility also allows developers to make their own higher level APIs, take a look at some of the <a href="https://github.com/mattetti/BubbleWrap">wrappers/helpers</a> I wrote while playing with RubyMotion.</p>
<p><a href="https://www.ruby-lang.org/en/"><img src="https://merbist.com/wp-content/uploads/2012/05/matt_aimonetti-Ruby_logo-150x150.jpg" alt="Matt Aimonetti - Ruby Logo"></a></p>
<h3 id="macruby">MacRuby</h3>
<p>RubyMotion is based on MacRuby, meaning that all the time and energy invested in the project will benefit RubyMotion&rsquo;s users. All the concepts I explain in my <a href="https://shop.oreilly.com/product/0636920000723.do">MacRuby book</a> apply to RubyMotion. You don&rsquo;t have to find workarounds to work with native APIs, Ruby objects are Objective-C objects and performance is great. I do regret Apple didn&rsquo;t decide to embrace MacRuby for iOS but at the same time, even though we lost the Open Source aspect of the project and Apple&rsquo;s backing, we gained much more flexibility and freedom on Laurent&rsquo;s part.</p>
<p><a href="https://www.amazon.com/dp/1449380379?tag=merbist-20&amp;camp=213381&amp;creative=390973&amp;linkCode=as4&amp;creativeASIN=1449380379&amp;adid=1SKHT7ABMG1YJZ3136WQ&amp;"><img src="https://merbist.com/wp-content/uploads/matt_aimonetti/matt_aimonetti_macruby_book.gif" alt=""></a></p>
<h3 id="replinteractive-shell">REPL/Interactive shell</h3>
<p>RubyMotion doesn&rsquo;t currently have a debugger, but it does have something Objective-C developers don&rsquo;t have, a <a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a> working with the simulator. This feature is quite handy when debugging your application or learning the Cocoa APIs. You can click on a visual element in the simulator and start modifying the objects in real time in a terminal window and see the modifications in the simulator. It reminds me of the first time I used firebug to edit the html/css of a web page and saw the changes in real time.</p>
<p><a href="https://www.youtube.com/watch?feature=player_embedded&amp;v=rejYKzLglSE#!"><img src="https://merbist.com/wp-content/uploads/2012/05/matt_aimonetti-RubyMotion-REPL-150x150.jpg" alt="Matt Aimonetti - RubyMotion REPL"></a></p>
<h3 id="not-dependent-on-xcode">Not dependent on Xcode</h3>
<p>Xcode is fine when you write Objective-C code, but it crashes often, it has a complicated UI and never really worked well for MacRuby due to the fact that Objective-C and Ruby have different requirements and the that Xcode is not open source. It&rsquo;s also fully controlled by Apple and doesn&rsquo;t provide APIs for 3rd party developers. (That said, the Xcode team has often helped out when a new released of Xcode broke MacRuby, so thank you guys).</p>
<p>Being able to use simple rake tasks to compile, simulate and deploy applications is just really really nice. I&rsquo;m sure we&rsquo;ll end up with better IDE integration, nice GUIs for some who like that, but in the meantime, as a &ldquo;hacker&rdquo;, I really enjoy the simplicity of the Rake tasks and not being forced in using a specific IDE.</p>
<p> </p>
<h3 id="memory-management">Memory management</h3>
<p>Even though ARC made memory management much easier for Objective-C developers, when using RubyMotion you don&rsquo;t have to worry about memory (well at least not explicitly, don&rsquo;t be dumb and create a bazillion objects and hold references to them either). This includes the CoreFoundation objects that you still have to manually manage in Objective-C. Memory management is transparent and in most cases it&rsquo;s really nice.</p>
<p> </p>
<hr>
<p> </p>
<h2 id="what-i-like-less-about-rubymotion">What I like less about RubyMotion</h2>
<p>Here is a list of things that are cons to using RubyMotion, note that while the list is longer than my list of &ldquo;pros&rdquo;, I listed a lot of small things. I also think that most of these issues will get solved in the next few months.</p>
<p> </p>
<h3 id="ruby-language-1">Ruby language</h3>
<p>There are some cases where Ruby just isn&rsquo;t that great or is not an option. Examples include dealing with API relying heavily on pointers, when using some of the lower level APIs or when you have to interact with C++ (video game engines for instance). The good news is that within the same project, you can write part of your code in Objective-C and the rest in RubyMotion. The other thing that bothers me a little bit with writing Ruby code for iOS is that you can&rsquo;t easily enforce argument types and therefore you are losing a lot of the features provided by Clang to the Objective-C developers. I dream of an optionally typed Ruby &ndash; but that&rsquo;s a different topic.</p>
<p>Another downside of using Ruby is that Ruby developers will assume all standard libraries and gems will be compatible with RubyMotion. This isn&rsquo;t the case. You need to think of RubyMotion as only offering the Ruby syntax (modulo a few differences). To be honest, most of the std libs and gems aren&rsquo;t that useful when writing iOS apps. Even when I write MacRuby apps, I rarely rely on them and pick libraries designed to work in a non-blocking, multi-threaded environment (usually ObjC libs that I wrap).</p>
<p> </p>
<h3 id="cocoa-touch">Cocoa Touch</h3>
<p>If you&rsquo;re already an iOS/OS X developer, you know that most of the hurdles aren&rsquo;t the language syntax but the Cocoa APIs. These APIs are what you need to interact with to create your application. Cocoa APIs are usually much lower-level compared to what you usually see in Python, Ruby or even Java. While they are quite consistent, the APIs still have a stiff learning curve and currently,  if you want to write iOS applications, even if you know Ruby, you still have to learn Cocoa.</p>
<p>However, I do think that with RubyMotion now building a userbase, we will start seeing more and more <a href="https://github.com/mattetti/BubbleWrap">wrappers</a> around these sometimes <a href="https://github.com/HipByte/RubyMotionSamples/blob/master/GestureTable/app/gesture_recognizer.rb">hideous APIs</a>.</p>
<p> </p>
<h3 id="no-xcodeide">No Xcode/IDE</h3>
<p>There are cases where an IDE is really practical, especially when learning new APIs. Being able to have code completion, quick access to the documentation, instrumentation, debugging, interface builder, refactoring tools are things that Objective-C developers might have a hard time with when switching to RubyMotion. If you don&rsquo;t know either Ruby or Cocoa, getting started with RubyMotion might be quite hard and you are probably not currently in the target audience.</p>
<p> </p>
<h3 id="writing-ui-code-by-hand">Writing UI code by hand</h3>
<p>In some cases, it makes sense, in other, it should be much easier. I know that Laurent is working on a DSL to make that easier and I&rsquo;m looking forward to it. But in the mean time, this is quite a painful exercise, especially due to the complexity of the Cocoa UI APIs. Using Xcode&rsquo;s interface builder and Storyboards is something I know a lot of us wish we could do with RubyMotion when developing specific types of applications.</p>
<p><a href="https://kurrytran.blogspot.fr/2011/07/simple-ios-5-tutorial-using-storyboard.html"><img src="https://merbist.com/wp-content/uploads/2012/05/matt_aimonetti_storyboard-1.jpg" alt="Matt Aimonetti - Xcode iOS storyboard"></a></p>
<h3 id="no-debugger">No debugger</h3>
<p>Again, this is eventually coming but the current lack of debugger can be problematic at times, especially when the problem isn&rsquo;t obvious.</p>
<p> </p>
<h3 id="lack-of-clear-target-audience">Lack of clear target audience</h3>
<p>It&rsquo;s hard to blame a brand new product for not having clearly defined a target audience. But as a developer I find myself wondering &ldquo;when should I use RubyMotion and for what kinds of problems?&rdquo; Is RubyMotion great for quick prototypes I can then turn into production code? Or is good for throw away prototypes? Is it reserved for &ldquo;fart and flash light&rdquo; applications? Is it ready for prime time and should I invest and write my new awesome apps using it? Should I convert over my existing code base over from Titanium (or whatever other alternatives you used)? Should I use RubyMotion every time I would use Objective-C?</p>
<p>I guess we will see when the first applications start hitting the app store and people start reporting on their experience.</p>
<h3 id="documentation">Documentation</h3>
<p>I&rsquo;m partially to blame here since I could have moved my butt and start writing a book but the point is nonetheless valid. All the iOS documentation out there is for Objective-C, all the APIs and samples provided by Apple are obviously only for Objective-C. Thankfully, you can use the 2 MacRuby books available out there to understand how to convert this existing documentation into something useful, but RubyMotion will need to provide better and more adapted documentation for beginners. I have no doubt that this is coming sooner than later.</p>
<p> </p>
<h3 id="proprietary-solution">Proprietary solution</h3>
<p>RubyMotion isn&rsquo;t open source and currently fully relies on the shoulders of a single man. If unfortunately, Laurent goes out of business or decides to do something else then we will have to rewrite our apps in Objective-C.  Using RubyMotion for a professional product represents a significant business risk, which is exactly the same as using proprietary technology from any vendor. Apple could also decide to switch to JavaScript or rewrite iOS in Java and deprecate Objective-C. Let&rsquo;s just say that it is unlikely.</p>
<p>I usually favor open source solutions, from the programming language I use to the OS I deploy on. This isn&rsquo;t always possible and if you want to write iOS applications, you don&rsquo;t currently have a choice. I do wish Laurent had found a way to make money while keeping the source code open. But who knows &ndash; after he makes his first million(s), he might change his mind.</p>
<p><a href="https://merbist.com/wp-content/uploads/2012/05/matt_aimonetti-rms.jpg"><img src="https://merbist.com/wp-content/uploads/2012/05/matt_aimonetti-rms-150x150.jpg" alt="Matt Aimonetti - RMS"></a></p>
<h2 id="conclusion">Conclusion</h2>
<p>I would strongly suggest you consider giving RubyMotion a try. I can assure you that it will provide at least a few hours of &lsquo;hacking fun&rsquo; (and you will be able to brag about havng written your own iPhone app).  It will also help support financially someone who&rsquo;s taking a risk in trying to push mobile development to the next level.</p>
<p>RubyMotion is, by far, my favorite alternative to Objective-C. But it is hard to tell, just 48 hours after its release, what people will do with it. Can it transcend the programming language barriers and attract Python, PHP, Java, ObjC and JavaScript developers? What is the sweet spot for RubyMotion applications? Will it affect the native vs web app battle? Can it make iOS development more accessible to the masses? Only time will tell.</p>
<br/>
<hr>
<h3 id="update">Update:</h3>
<p>Since RubyMotion 1.0 was released, I spent quite a lot of my free time leading the
development of <a href="https://bubblewrap.io/">BubbleWrap</a>, a free and open
source 3rd party library for <a href="https://www.rubymotion.com/">RubyMotion</a>.
Unfortunately, as of July 2011 <strong>I took a break from this project and
RubyMotion in general</strong>. I explained my motivations in <a href="https://groups.google.com/d/topic/rubymotion/XIE673vnuQk/discussion">this mailing list
post</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>getting started with mruby</title>
			<link>https://matt.aimonetti.net/posts/2012-04-getting-started-with-mruby/</link>
			<pubDate>Wed, 25 Apr 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-04-getting-started-with-mruby/</guid>
			<description>mruby is the latest Ruby implementation in an already quite long list:
 MRI REE JRuby Rubinius MacRuby Maglev IronRuby  And many other less known implementations.
This time, the main man behind the project is the Ruby creator himself: Yukihiro &amp;lsquo;Matz&amp;rsquo; Matsumoto. I already covered the announcement, you can read more about it there.
Why mruby? Following my previous article on mruby, some people seemed to be confused by the &amp;ldquo;raison d&amp;rsquo;être&amp;rdquo;/purpose of the project and the difference between MRI and mruby.</description>
			<content type="html"><![CDATA[<p>mruby is the latest Ruby implementation in an already quite long list:</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Ruby_MRI">MRI</a></li>
<li><a href="https://www.rubyenterpriseedition.com/">REE</a></li>
<li><a href="https://jruby.org/">JRuby</a></li>
<li><a href="https://rubini.us/">Rubinius</a></li>
<li><a href="https://macruby.org">MacRuby</a></li>
<li><a href="https://maglev.github.com/">Maglev</a></li>
<li><a href="https://www.ironruby.net/">IronRuby</a></li>
</ul>
<p>And many other less known implementations.</p>
<p>This time, the main man behind the project is the Ruby creator
himself: <a href="https://en.wikipedia.org/wiki/Yukihiro_Matsumoto">Yukihiro &lsquo;Matz&rsquo; Matsumoto</a>.
I already covered the <a href="https://matt.aimonetti.net/posts/2012/04/20/mruby-and-mobiruby/">announcement, you can read more about it there</a>.</p>
<h2 id="why-mruby">Why mruby?</h2>
<p>Following my previous <a href="https://matt.aimonetti.net/posts/2012/04/20/mruby-and-mobiruby/">article on mruby</a>, some people seemed to be confused by the &ldquo;raison d&rsquo;être&rdquo;/purpose of the project and the difference between <a href="https://en.wikipedia.org/wiki/Ruby_MRI">MRI</a> and mruby.</p>
<p>mruby is designed to be modular and to be embedded, which means that
it&rsquo;s expected to live inside other software applications. In other words
mruby&rsquo;s goal is to make Ruby an embedded language. mruby is library that you link in other applications.</p>
<p>When talking about embedded languages, <a href="https://www.lua.org/">Lua</a> is
probably the most well known interpreted language.
<a href="https://www.lua.org/">Lua</a> is usually used for the purpose of offering a
higher level language (scripting language) inside a software written in a low level language
(usually C/C++). This is why <a href="https://www.lua.org/">Lua</a> is very popular
in the game industry to allow a scriptable interface and have parts of
the code interpreted instead of requiring to recompile the code base
against the target platform. According to <a href="https://www.satori.org/2009/03/the-engine-survey-general-results/">this survey from 2009</a>,
Lua was by far the most popular scripting language for game developers.</p>
<p><img src="https://www.satori.org/images/GE1/9Scripting.gif" alt="Lua vs other scripting languages"></p>
<p>Of course, Lua is also popular outside of the game industry and the
reasons are simple to understand:</p>
<ul>
<li>very easily embedded (simple and well documented API)</li>
<li>small footprint</li>
<li>portable (runs almost everywhere)</li>
</ul>
<p>That gives you an idea of what mruby is trying to be. As a matter of
fact, this definition of Lua applies very well to mruby:</p>
<blockquote>
<p>&ldquo;Lua is dynamically typed, runs by interpreting bytecode for a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal for configuration, scripting, and rapid prototyping.&rdquo;</p>
</blockquote>
<h2 id="why-not-lua">Why not Lua?</h2>
<p>This is a matter of taste and requirements. It should eventually boil
down to the difference in the language designs.</p>
<img src='/images/lua_logo.gif' alt='Lua logo, Matt Aimonetti site' style='margin:auto;display:block;width:100px' class='no-caption'/>
<blockquote>
<p>Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics.</p>
</blockquote>
</br>
 <img src='/images/ruby_logo.png' alt='Ruby logo, Matt Aimonetti site' style='margin:auto;display:block;width:100px'class='no-caption' />
<blockquote>
<p>Ruby is a dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.</p>
</blockquote>
<br style="clear:both">
<p>So on one hand you have a very simple language with a focus on
functional programming and on the other, a <a href="https://www.ruby-lang.org/en/about/">richer language</a> (albeit more
complex) with a
main focus on Object Oriented programming.</p>
<p>If you don&rsquo;t know Lua, it&rsquo;s quite close to JavaScript in the sense that
it&rsquo;s a prototype based language and you can therefore write code that is
Object Oriented.</p>
<p>Ruby being a full OO and richer language, you can organize your code
differently and write more of your complex logic in a scriptable language.
One could even potentially leverage the language to create its own
Domain Specific Language in pure Ruby and create a &ldquo;Rails like&rdquo; experience
within its application.</p>
<p>To be honest, I don&rsquo;t think that Ruby via mruby will just replace Lua,
but I do believe it will become a very interesting alternative for some
use cases. Especially if mruby manages to perform as well as Lua with the
same type of footprint. There is also the fact that mruby being
a sponsored project from the Japanese government, I wouldn&rsquo;t be
surprised to see big Japanese companies experiment with embedding Ruby
in their devices. After all, software is being added in every object we
own, rapid development and being first to market is more critical than
ever which makes mruby is a very attractive solution.</p>
<h2 id="getting-started">Getting started</h2>
<p>I wrote a simple hello world example to give you a place to start:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;stdlib.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;stdio.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e"></span>
<span style="color:#75715e">/* Include the mruby header */</span>
<span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;mruby.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;mruby/compile.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e"></span>
<span style="color:#66d9ef">int</span> <span style="color:#a6e22e">main</span>(<span style="color:#66d9ef">void</span>)
{
  mrb_state <span style="color:#f92672">*</span>mrb <span style="color:#f92672">=</span> mrb_open();
  <span style="color:#66d9ef">char</span> code[] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;p &#39;hello world!&#39;&#34;</span>;
  printf(<span style="color:#e6db74">&#34;Executing Ruby code with mruby!</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>);

  mrb_load_string(mrb, code);
  <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
}
</code></pre></div><p>Or the longer/more complex version:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-c" data-lang="c"><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;stdlib.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;stdio.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e"></span>
<span style="color:#75715e">/* Include the mruby headers */</span>
<span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;mruby.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;mruby/proc.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;mruby/data.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e">#include</span> <span style="color:#75715e">&lt;mruby/compile.h&gt;</span><span style="color:#75715e">
</span><span style="color:#75715e"></span>
<span style="color:#66d9ef">int</span> <span style="color:#a6e22e">main</span>(<span style="color:#66d9ef">int</span> argc, <span style="color:#66d9ef">const</span> <span style="color:#66d9ef">char</span> <span style="color:#f92672">*</span> argv[])
{
  <span style="color:#66d9ef">struct</span> mrb_parser_state <span style="color:#f92672">*</span>p;
  mrb_state <span style="color:#f92672">*</span>mrb <span style="color:#f92672">=</span> mrb_open();
  <span style="color:#66d9ef">char</span> code[] <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;p &#39;hello world!&#39;&#34;</span>;
  printf(<span style="color:#e6db74">&#34;Executing code with mruby!</span><span style="color:#ae81ff">\n</span><span style="color:#e6db74">&#34;</span>);

  p <span style="color:#f92672">=</span> mrb_parse_string(mrb, code);
  <span style="color:#66d9ef">int</span> n;
  n <span style="color:#f92672">=</span> mrb_generate_code(mrb, p);
  mrb_run(mrb, mrb_proc_new(mrb, mrb<span style="color:#f92672">-&gt;</span>irep[n]), mrb_top_self(mrb));
  <span style="color:#66d9ef">if</span> (mrb<span style="color:#f92672">-&gt;</span>exc) {
      mrb_p(mrb, mrb_obj_value(mrb<span style="color:#f92672">-&gt;</span>exc));
  }

    <span style="color:#66d9ef">return</span> <span style="color:#ae81ff">0</span>;
}
</code></pre></div><p>To compile and link the code:</p>
<pre><code>$ gcc -Iinclude hello.c lib/libmruby.a -lm -o hello.out
</code></pre><p>To execute it:</p>
<pre><code>$ ./hello.out
Executing Ruby code with mruby!
&quot;hello world!&quot;
</code></pre><p>To get started, you just need the <a href="https://github.com/mruby/mruby">mruby source code</a> and a compiler. (I haven&rsquo;t tried to compile mruby or my sample on Windows for this code, but I assume it would work just fine with Visual C++).</p>
<p>The above example is very trivial and takes a line of Ruby code:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">p <span style="color:#e6db74">&#39;hello world!&#39;</span>
</code></pre></div><p>that the linked mruby lib interprets.
You can take the compiled file and use it on other machines using the
same platform and the code will run fine, just like normal C code.</p>
<p>For a more complete example, take a look at the <a href="https://github.com/mruby/mruby/blob/master/tools/mruby/mruby.c">mruby&rsquo;s standalone
interpreter</a></p>
<h2 id="future">Future</h2>
<p>It&rsquo;s a bit too early to know if mruby will be successful or not. There are few things I will keep my
eyes on.</p>
<h3 id="performance">Performance</h3>
<p>To be a true alternative to Lua, mruby will have to interpret Ruby code
much faster than what MRI is able to do right now. It will also need to
keep the memory footprint really tiny. Ruby being a more complicated
language than Lua, it might be tricky, but we&rsquo;ll see.</p>
<h3 id="documentation">Documentation</h3>
<p>While the idea of using Ruby has a macro language might get a lot of
people excited, if documentation lacks or if the process is painful, the very same people might
fallback to another language.
Historically speaking, the MRI team has had issues with documentation
and communication due to various factors. I hope that thanks to Matz
experience and to the strong Ruby community, mruby will become a easy
and efficient alternative to Lua or people wanting to embed one of the
greatest interpreted languages.</p>
<h3 id="ruby-outside-of-rails">Ruby outside of Rails</h3>
<p>While <a href="https://rubyonrails.org">Ruby on Rails</a> really made Ruby popular,
I&rsquo;m always a bit dissapointed when I see how many popular projects the
Ruby community has outside of Rails. Think about it, we have some
awesome implementation such as JRuby and MacRuby which allow you to use
an amazing amount of libraries to do the craziest thing one could
imagine using the language they like the most. But yet, Rails is still
by far the #1 Ruby project. Of course, there are many non-Rails related
projects out there, but they don&rsquo;t benefit from Rails' aura.</p>
<p>What I hope with mruby is that it will allow developers to leverage the
beauty of Ruby and to create other niches for people to have fun.
Some people already started:</p>
<p>####MobiRuby
<a href="https://github.com/masuidrive">Yuichiro MASUI</a>
is working on having Ruby available on iOS and Android.</p>
<p>####Ruby for Node.js
<a href="https://mattn.kaoriya.net/">Yasuhiro Matsumoto</a> is working on <a href="https://github.com/mattn/mruby-uv">mruby-uv</a> an interface for <a href="https://github.com/joyent/libuv">libuv</a> Node.js' platform layer.</p>
<p>####mod_mruby</p>
<p><a href="https://blog.matsumoto-r.jp/">MATSUMOTO Ryosuke</a> is working on an Apache
module for mruby called <a href="https://github.com/matsumoto-r/mod_mruby">mod_mruby</a> which would
be comparable to <a href="https://httpd.apache.org/docs/2.3/mod/mod_lua.html">mod_lua</a></p>
<p>####mruby REPL</p>
<p><a href="">Frank Celler</a> started working and blogging about writing a REPL for
mruby, go check out <a href="https://www.avocadodb.org/category/mruby">his excellent blog posts</a> on the shell he&rsquo;s working on and other stuff he&rsquo;s doing with mruby.</p>
<p>But there is plenty more to do, <a href="https://antirez.com/post/scripting-branch-released.html">redis</a> for instance now has/is about to be scriptabled via Lua, what about trying to use mruby to also support Ruby?
What about scripting game logic and even full games in Ruby?
What about mruby on a <a href="https://www.raspberrypi.org/">Raspberry pi</a>?
Ruby on my TV, fridge, car, AC, solar panel controller&hellip;</p>
<p>I will certainly be looking forward to people trying to reproduce the success
of Rails in a different domain thanks to the Ruby language.</p>
]]></content>
		</item>
		
		<item>
			<title>mruby and mobiruby</title>
			<link>https://matt.aimonetti.net/posts/2012-04-mruby-and-mobiruby/</link>
			<pubDate>Fri, 20 Apr 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-04-mruby-and-mobiruby/</guid>
			<description>Today, two big Ruby news came directly from Japan:
 The Open Source release of Matz&#39; mruby on GitHub. The announce of MobiRuby, an upcoming solution to develop iOS and Android applications using Ruby.  Probably due to my involvement with the MacRuby project, people have been asking me what I thought of these news.
mruby mruby is far from being a new project. It&amp;rsquo;s based on the RiteVM which is a sponsored project by the Japanese ministry of Economy, Trade and Industry and lead by Ruby&amp;rsquo;s creator: Yukihiro &amp;ldquo;Matz&amp;rdquo; Matsumoto and was explained in details during Matz&amp;rsquo;s RubyConf 2010 keynote.</description>
			<content type="html"><![CDATA[<p>Today, two big Ruby news came directly from Japan:</p>
<ul>
<li>The Open Source release of <a href="https://en.wikipedia.org/wiki/Yukihiro_Matsumoto">Matz'</a> <a href="https://github.com/mruby/mruby">mruby on GitHub</a>.</li>
<li>The announce of MobiRuby, an upcoming solution
to develop iOS and Android applications using Ruby.</li>
</ul>
<p>Probably due to my involvement with the <a href="https://macruby.org/">MacRuby</a>
project, people have been asking me what I thought of these news.</p>
<h2 id="mruby">mruby</h2>
<p>mruby is far from being a new project. It&rsquo;s based on the RiteVM which is a
sponsored project by the <a href="https://www.meti.go.jp/english/">Japanese ministry of Economy, Trade and Industry</a> and lead by Ruby&rsquo;s creator: <a href="https://en.wikipedia.org/wiki/Yukihiro_Matsumoto">Yukihiro &ldquo;Matz&rdquo; Matsumoto</a> and was explained in details during <a href="https://www.slideshare.net/yukihiro_matz/rubyconf-2010-keynote-by-matz">Matz&rsquo;s RubyConf 2010 keynote</a>.</p>
<p>Back in November 2011 Matz also explained mruby. His talk was recorded
and he explains very well the current Ruby ecosystem and why mruby makes
sense.</p>
<div class="video-container">
<iframe width="560" height="315" src="https://www.youtube.com/embed/sB-IifjyeLI" frameborder="0" allowfullscreen></iframe></div>
<p>As explained, the main goal of mruby is to have a Ruby version that can
be embedded and therefore have a smaller footprint, be compiled and
linked within another application.</p>
<p>Hiroshi Nakamura gave a great 1 line definition of mruby:</p>
<p><img src="/images/mruby_def.jpg" alt="mruby"></p>
<p>mruby targets game developers (to use instead of Lua), embedded
application developers (devices, TV, phones..) and small memory
footprint server applications (instead of JS for instance).</p>
<p>I&rsquo;m personally quite excited by mruby, it&rsquo;s not there yet and there is
still a lot of work to do to prove the value of the project but it&rsquo;s
certainly a great step in the right direction. What&rsquo;s also really nice
is that the project is released under an OSS license allowing for all of
us to contribute and companies to improve the implementation based on
their own needs.</p>
<p><strong>Summary:</strong> mruby is a promising project even if it is still in its infancy.
Besides being yet another Ruby implementation, the fact that the
target audience and the project scope are well defined and that the project is lead
by Ruby&rsquo;s author and sponsored by the Japanese government makes me want to believe that it can be a successful project. That said Lua is a simpler language and it is already well implemented in the targeted market, so hopefuly Matz, his team and the Japanese government have a plan to advocate and champion this new technology. Good luck to them and I&rsquo;ll keep an attentive eye on the project.</p>
<p>**
date = &ldquo;I&rdquo;
slug = &ldquo;I/mruby-and-mobiruby&rdquo;
**</p>
<h2 id="mobiruby">MobiRuby</h2>
<p>MobiRuby is being developed by <a href="https://github.com/masuidrive">Yuichiro MASUI</a> who works for <a href="https://www.appcelerator.com/">Appcelerator</a> the company behind the popular <a href="https://www.appcelerator.com/platform/titanium-sdk">Titanium platform</a> to write native iOS, Android apps in JS.</p>
<p>MobiRuby is built on top of mruby making it the first demonstration of
what motivated developers can do with Matz new implementation. Very much
like mruby, MobiRuby will be released under an OSS license but unlike
mruby, the <a href="https://www.apache.org/licenses/LICENSE-2.0.html">Apache license</a> was chosen.</p>
<p>So far this was just an announcement with a code sample and a
screenshot. That was enough to make the front page of <a href="https://news.ycombinator.com/item?id=3866418">HackerNews</a>. Apparently the author is planning on releasing a first version in a few months.</p>
<p>It might surprise some, but I&rsquo;m quite glad to see this kind of projects
even though, they compete to some extent against MacRuby. It proves two
things:</p>
<ul>
<li>there is a strong interest in having Ruby on mobile devices.</li>
<li>it&rsquo;s technically possible to do so.</li>
</ul>
<p>Now, this is not something new either, Lua developers have been able to
write iOS apps for a while, yet the majority of the iOS developers still
use Objective-C. What are the challenges facing implementations trying
to replace Objective-C?</p>
<h3 id="the-replacement-language-might-not-fit-the-cocoa-design">The replacement language might not fit the Cocoa design.</h3>
<p>Developing an iOS/OS X app means that you spend your time using provided
libraries (called frameworks in Apple&rsquo;s jargon). These frameworks have
specific patterns, a well defined syntax and usually work in a very
consistent/constraining way. Or your language is quite similar (like Ruby) and the
transition is easy, or you need to start writing and maintaining
wrappers (titanium).</p>
<h3 id="bridged-runtimes">Bridged runtimes.</h3>
<p>Having 2 runtimes running at the same time is quite challenging and not
efficient. That&rsquo;s one of the reasons why Apple pushed MacRuby to move from <a href="https://en.wikipedia.org/wiki/RubyCocoa">RubyCocoa</a> being a bridge and to have a Ruby implementation running in Objective-C runtime itself.
This allows something else, in MacRuby all objects are actually
Objective-C objects which means you don&rsquo;t need to convert anything and
Cocoa APIs can be extended from Ruby code by just reopening them.</p>
<h3 id="support">Support.</h3>
<p>This one is critical for many. Often, you don&rsquo;t want to have your next big
project rely on a technology that doesn&rsquo;t have a good backing and
support. What happens if you build your app using an alternate
implementation and all a sudden the developer(s) get bored and move on,
or take another job?
What about the updates needed as Apple/Google update their platforms?
It might not be the best reason to not choose an alternative, but it&rsquo;s
a reasonable reason especially for companies who want to be &ldquo;safe&rdquo;.</p>
<h3 id="cocoa">Cocoa</h3>
<p>Cocoa APIs represent probably 90% of the challenge when writing iOS/OS X
applications. The APIs, while powerful and efficient, are often a pain
to get used to and to learn.</p>
<p>You have the challenge of the documentation and the examples that
are only in Objective-C, requiring that someone <a href="https://www.amazon.com/gp/product/1449380379/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1449380379">writes a book</a> and/or that
you convert and maintain an enormous amount of documentation.</p>
<p>You also have all the tools provided by Apple which, you often can&rsquo;t
fully use because you aren&rsquo;t using their toolchain.</p>
<p>To be honest, after so many years using MacRuby, I think that the real
value of such a project isn&rsquo;t in the easier syntax but instead in the
fact that you can easily build wrappers and higher level interfaces
around repetitive tasks. Having a mix of a well designed DSL and yet
access to the native object is something extremely powerful.</p>
<h3 id="objective-c-is-evolving">Objective-C is evolving.</h3>
<p>Objective-C is evolving, with the introduction of <a href="https://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html">ARC</a>, memory management became much easier. The latest version of clang also granted Objective-C with a nicer syntax thanks to new literals and object subscripting (<a href="https://clang.llvm.org/docs/ObjectiveCLiterals.html">read more</a>). As a matter of fact, Objective-C&rsquo;s syntax is getting closer and closer to Ruby&rsquo;s making the choice to use an alternate much harder.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-objective-c" data-lang="objective-c"><span style="color:#75715e">// character literals.
</span><span style="color:#75715e"></span>NSNumber <span style="color:#f92672">*</span>theLetterZ <span style="color:#f92672">=</span> <span style="color:#e6db74">@&#39;Z&#39;</span>;          <span style="color:#75715e">// equivalent to [NSNumber numberWithChar:&#39;Z&#39;]
</span><span style="color:#75715e"></span>
<span style="color:#75715e">// integral literals.
</span><span style="color:#75715e"></span>NSNumber <span style="color:#f92672">*</span>fortyTwo <span style="color:#f92672">=</span> <span style="color:#ae81ff">@42</span>;             <span style="color:#75715e">// equivalent to [NSNumber numberWithInt:42]
</span><span style="color:#75715e"></span>
<span style="color:#75715e">// floating point literals.
</span><span style="color:#75715e"></span>NSNumber <span style="color:#f92672">*</span>piDouble <span style="color:#f92672">=</span> <span style="color:#ae81ff">@3.1415926535</span>;   <span style="color:#75715e">// equivalent to [NSNumber numberWithDouble:3.1415926535]
</span><span style="color:#75715e"></span>
<span style="color:#75715e">// BOOL literals.
</span><span style="color:#75715e"></span>NSNumber <span style="color:#f92672">*</span>yesNumber <span style="color:#f92672">=</span> <span style="color:#ae81ff">@YES</span>;           <span style="color:#75715e">// equivalent to [NSNumber numberWithBool:YES]
</span><span style="color:#75715e"></span>
<span style="color:#75715e">// Container literals
</span><span style="color:#75715e"></span>NSArray <span style="color:#f92672">*</span>array <span style="color:#f92672">=</span> <span style="color:#ae81ff">@[</span> <span style="color:#e6db74">@&#34;Hello&#34;</span>, NSApp, [NSNumber numberWithInt:<span style="color:#ae81ff">42</span>] <span style="color:#ae81ff">]</span>;
<span style="color:#66d9ef">id</span> value <span style="color:#f92672">=</span> array[idx];

NSDictionary <span style="color:#f92672">*</span>dictionary <span style="color:#f92672">=</span> <span style="color:#ae81ff">@{</span>
  <span style="color:#e6db74">@&#34;name&#34;</span> <span style="color:#f92672">:</span> NSUserName(),
  <span style="color:#e6db74">@&#34;date&#34;</span> <span style="color:#f92672">:</span> [NSDate date],
  <span style="color:#e6db74">@&#34;processInfo&#34;</span> <span style="color:#f92672">:</span> [NSProcessInfo processInfo]
<span style="color:#ae81ff">}</span>;
<span style="color:#66d9ef">id</span> oldObject <span style="color:#f92672">=</span> dictionary[key];
dictionary[key] <span style="color:#f92672">=</span> newObject;	<span style="color:#75715e">// replace oldObject with newObject
</span></code></pre></div><h3 id="performance">Performance.</h3>
<p>Even though devices are more and more powerful, performance is often
critical and Apple optimized the performance of their solution for their
language. If you have ever developed a Titanium app, you know that it
can be an issue and you might have to find workarounds to get decent
performance.</p>
<p><strong>Summary:</strong> Based on all these things, once MobiRuby will be released, I will be
able to make a better judgement. But based on what I have seen so far,
I&rsquo;m quite concerned by the syntax and the performance we will get out of
the box. But time will tell and things can always be improved.
Ruby on iOS/Android is something exciting and I&rsquo;m looking forward to
testing the first betas.</p>
]]></content>
		</item>
		
		<item>
			<title>building and implementing a single sign on solution</title>
			<link>https://matt.aimonetti.net/posts/2012-04-building-and-implementing-a-single-sign-on-solution/</link>
			<pubDate>Wed, 04 Apr 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-04-building-and-implementing-a-single-sign-on-solution/</guid>
			<description>Most modern web applications start as a monolithic code base and, as complexity increases, the once small app gets split apart into many &amp;ldquo;modules&amp;rdquo;. In other cases, engineers opt for a SOA design approach from the beginning. One way or another, we start running multiple separate applications that need to interact seamlessly. My goal will be to describe some of the high-level challenges and solutions found in implementing a Single-Sign-On service.</description>
			<content type="html"><![CDATA[<p>Most modern web applications start as a monolithic code base and, as complexity increases, the once small app gets split apart into many &ldquo;modules&rdquo;. In other cases, engineers opt for a <a href="https://en.wikipedia.org/wiki/Service-oriented_architecture">SOA</a> design approach from the beginning. One way or another, we start running multiple separate applications that need to interact seamlessly. My goal will be to describe some of the high-level challenges and solutions found in implementing a Single-Sign-On service.</p>
<h2 id="authentication-vs-authorization">Authentication vs Authorization</h2>
<p>I wish these two words didn&rsquo;t share the same root because it surely confuses a lot of people. My most frequently-discussed example is <a href="https://en.wikipedia.org/wiki/OAuth">OAuth</a>. Every time I start talking about implementing a centralized/unified authentication system, someone jumps in and suggests that we use <a href="https://en.wikipedia.org/wiki/OAuth">OAuth</a>. The challenge is that <a href="https://en.wikipedia.org/wiki/OAuth">OAuth</a> is an authorization system, not an authentication system.</p>
<p>It&rsquo;s tricky, because you might actually be &ldquo;authenticating&rdquo; yourself to website X using OAuth. What you are really doing is allowing website X to use your information stored by the OAuth provider. It is true that OAuth offers a pseudo-authentication approach via its provider but that is not the main goal of <a href="https://en.wikipedia.org/wiki/OAuth">OAuth</a>: the Auth in OAuth stands for Authorization, not Authentication.</p>
<p>Here is how we could briefly describe each role:</p>
<ul>
<li>
<p><strong>Authentication</strong>: recognizes who you are.</p>
</li>
<li>
<p><strong>Authorization</strong>: know what you are allowed to do, or what you allow others to do.</p>
</li>
</ul>
<p>If you are feel stuck in your design and something seems wrong, ask yourself if you might be confused by the 2 auth words. This article will only focus on <strong>authentication</strong>.</p>
<h2 id="a-common-scenario">A Common Scenario</h2>
<p><a href="https://merbist.com/wp-content/uploads/2012/04/SSO-simplescenario.png"><img src="https://merbist.com/wp-content/uploads/2012/04/SSO-simplescenario.png" alt="SSO diagram with 3 top applications connecting to an authorization service."></a></p>
<p>This is probably the most common structure, though I made it slightly more complex by drawing the three main apps in different programming languages. We have three web applications running on different subdomains and sharing account data via a centralized authentication service.</p>
<p><strong>Goals:</strong></p>
<ul>
<li>
<p>Keep authentication and basic account data isolated.</p>
</li>
<li>
<p>Allow users to stay logged in while browsing different apps.</p>
</li>
</ul>
<p>Implementing such a system should be easy. That said, if you migrate an existing app to an architecture like that, you will spend 80% of your time decoupling your legacy code from authentication and wondering what data should be centralized and what should be distributed. Unfortunately, I can&rsquo;t tell you what to do there since this is very domain specific. Instead, let&rsquo;s see how to do the &ldquo;easy part.&rdquo;</p>
<h2 id="centralizing-and-isolating-shared-account-data">Centralizing and Isolating Shared Account Data</h2>
<p>At this point, you more than likely have each of your apps talk directly to shared database tables that contain user account data. The first step is to migrate away from doing that. We need a single interface that is the only entry point to create or update shared account data. Some of the data we have in the database might be app specific and therefore should stay within each app, anything that is shared across apps should be moved behind the new interface.</p>
<p>Often your centralized authentication system will store the following information:</p>
<ul>
<li>
<p>ID</p>
</li>
<li>
<p>first name</p>
</li>
<li>
<p>last name</p>
</li>
<li>
<p>login/nickname</p>
</li>
<li>
<p>email</p>
</li>
<li>
<p>hashed password</p>
</li>
<li>
<p>salt</p>
</li>
<li>
<p>creation timestamp</p>
</li>
<li>
<p>update timestamp</p>
</li>
<li>
<p>account state (verified, disabled &hellip;)</p>
</li>
</ul>
<p>Do not duplicate this data in each app, instead have each app rely on the account ID to query data that is specific to a given account in the app. Technically that means that instead of using SQL joins, you will query your database using the ID as part of the condition.</p>
<p>My suggestion is to do things slowly but surely. Migrate your database schema piece by piece assuring that everything works fine. Once the other pieces will be in place, you can migrate one code API a time until your entire code base is moved over. You might want to change your DB credentials to only have read access, then no access at all.</p>
<h2 id="login-workflow">Login workflow</h2>
<p>Each of our apps already has a way for users to login. We don&rsquo;t want to change the user experience, instead we want to make a transparent modification so the authentication check is done in a centralized way instead of a local way. To do that, the easiest way is to keep your current login forms but instead of POSTing them to your local apps, we&rsquo;ll POST them to a centralized authentication API. (SSL is strongly recommended)</p>
<p><a href="https://merbist.com/wp-content/uploads/2012/04/SSO-login.png"><img src="https://merbist.com/wp-content/uploads/2012/04/SSO-login.png" alt="diagram showing the login workflow"></a></p>
<p>As shown above, the login form now submits to an endpoint in the authentication application. The form will more than likely include a login or email and a clear text password as well as a hidden callback/redirect url so that the authentication API can redirect the user&rsquo;s browser to the original app. For security reasons, you might want to white list the domains you allow your authentication app to redirect to.</p>
<p>Internally, the Authentication app will validate the identifier (email or login) using a hashed version of the clear password against the matching record in the account data. If the verification is successful, a token will be generated containing some user data (for instance: id, first name, last name, email, created date, authentication timestamp). If the verification failed, the token isn&rsquo;t generated. Finally the user&rsquo;s browser is redirected to the callback/redirect URL provided in the request with the token being passed.</p>
<p>You might want to safely encrypt the data in a way that allows the clients to verify and trust that the token comes from a trusted source. A great solution for that would be to use <a href="https://en.wikipedia.org/wiki/RSA_(algorithm)">RSA encryption</a> with the public key available in all your client apps but the private key only available on the auth server(s). Other strong encryption solutions would also work. For instance, another appropriate approach would be to add a signature to the params sent back. This way the clients could check the authenticity of the params. <a href="https://en.wikipedia.org/wiki/HMAC">HMAC</a> or <a href="https://en.wikipedia.org/wiki/Digital_Signature_Algorithm">DSA</a> signature are great for that but in some cases, you don&rsquo;t want people to see the content of the data you send back. That&rsquo;s especially true if you are sending back a &lsquo;mobile&rsquo; token for instance. But that&rsquo;s a different story. What&rsquo;s important to consider is that we need a way to ensure that the data sent back to the client can&rsquo;t be tampered with. You might also make sure you prevent replay attacks.</p>
<p>On the other side, the application receives a GET request with a token param. If the token is empty or can&rsquo;t be decrypted, authentication failed. At that point, we need to show the user the login page again and let him/her try again. If on the other hand, the token can be decrypted, the content should be saved in the session so future requests can reuse the data.</p>
<p>We described the authentication workflow, but if a user logins in application X, (s)he won&rsquo;t be logged-in in application Y or Z. The trick here, is to set a top level domain cookie that can be seen by all applications running on subdomains. Certainly, this solution only works for apps being on the same domain, but we&rsquo;ll see later how to handle apps on different domains.</p>
<p><a href="https://merbist.com/wp-content/uploads/2012/04/SSO-login-cookie.png"><img src="https://merbist.com/wp-content/uploads/2012/04/SSO-login-cookie.png" alt=""></a></p>
<p>The cookie doesn&rsquo;t need to contain a lot of data, its value can contain the account id, a timestamp (to know when authentication happened and a trusted signature) and a signature. The signature is critical here since this cookie will allow users to be automatically logged in other sites. I&rsquo;d recommend the  <a href="https://en.wikipedia.org/wiki/HMAC">HMAC</a> or <a href="https://en.wikipedia.org/wiki/Digital_Signature_Algorithm">DSA</a> encryptions to generate the signature. The DSA encryption, very much like the RSA encryption is an asymmetrical encryption relying on a public/private key. This approach offers more security than having something based a shared secret like HMAC does. But that&rsquo;s really up to you.</p>
<p>Finally, we need to set a filter in your application. This auto-login filter will check the presence of an auth cookie on the top level domain and the absence of local session. If that&rsquo;s the case, a session is automatically created using the user id from the cookie value after the cookie integrity is verified. We could also share the session between all our apps, but in most cases, the data stored by each app is very specific and it&rsquo;s safer/cleaner to keep the sessions isolated. The integration with an app running on a different service will also be easier if the sessions are isolated.</p>
<p> </p>
<h2 id="registration">Registration</h2>
<p>For registration, as for login, we can take one of two approaches: point the user&rsquo;s browser to the auth API or make S2S (server to server) calls from within our apps to the Authentication app. POSTing a form directly to the API is a great way to reduce duplicated logic and traffic on each client app so I&rsquo;ll demonstrate this approach.</p>
<p><a href="https://merbist.com/wp-content/uploads/2012/04/CopyofSSO-register.png"><img src="https://merbist.com/wp-content/uploads/2012/04/CopyofSSO-register.png" alt=""></a></p>
<p>As you can see, the approach is the same we used to login. The difference is that instead of returning a token, we just return some params (id, email and potential errors). The redirect/callback url will also obviously be different than for login. You could decide to encrypt the data you send back, but in this scenario, what I would do is set an auth cookie at the .domain.com level when the account is created so the &ldquo;client&rdquo; application can auto-login the user. The information sent back in the redirect is used to re-display the register form with the error information and the email entered by the user.</p>
<p>At this point, our implementation is almost complete. We can create an account and login using the defined credentials. Users can switch from one app to another without having to re login because we are using a shared signed cookie that can only be created by the authentication app and can be verified by all &ldquo;client&rdquo; apps. Our code is simple, safe and efficient.</p>
<h2 id="updating-or-deleting-an-account">Updating or deleting an account</h2>
<p>The next thing we will need is to update or delete an account. In this case, this is something that needs to be done between a &ldquo;client&rdquo; app and the authentication/accounts app. We&rsquo;ll make S2S (server to server) calls. To ensure the security of our apps and to offer a nice way to log requests, API tokens/keys will be used by each client to communicate with the authentication/accounts app. The API key can be passed using a <a href="https://en.wikipedia.org/wiki/List_of_HTTP_header_fields">X-header</a> so this concern stays out of the request params and our code can process separately the authentication via X-header and the actual service implementation. S2S services should have a filter verifying and logging the API requests based on the key sent with the request. The rest is straight forward.</p>
<h2 id="using-different-domains">Using different domains</h2>
<p>Until now, we assumed all our apps were on the same top domain. In reality, you will often find yourself with apps on different domains. This means that you can&rsquo;t use the shared signed cookie approach anymore. However, there is a simple trick that will allow you to avoid requiring your users to re-login as they switch apps.</p>
<p><a href="https://merbist.com/wp-content/uploads/2012/04/SSO-differentdomains-1.png"><img src="https://merbist.com/wp-content/uploads/2012/04/SSO-differentdomains-1.png" alt=""></a></p>
<p> </p>
<p>The trick consists, when a local session isn&rsquo;t present, of using an iframe in the application using the different domain. The iframe loads a page from the authentication/accounts app which verifies that a valid cookie was set on the main top domain. If that is the case, we can tell the application that the user is already globally logged in and we can tell the iframe host to redirect to an application end point passing an auth token the same way we did during the authentication. The app would then create a session and redirect the user back to where (s)he started. The next requests will see the local session and this process will be ignored.</p>
<p>If the authentication application doesn&rsquo;t find a signed cookie, the iframe can display a login form or redirect the iframe host to a login form depending on the required behavior.</p>
<p>Something to keep in mind when using multiple apps and domains is that you need to keep the shared cookies/sessions in sync, meaning that if you log out from an app, you need to also delete the auth cookie to ensure that users are globally logged out. (It also means that you might always want to use an iframe to check the login status and auto-logoff users).</p>
<p> </p>
<h2 id="mobile-clients">Mobile clients</h2>
<p>Another part of implementing a SSO solution is to handle mobile clients. Mobile clients need to be able to register/login and update accounts. However, unlike S2S service clients, mobile clients should only allow calls to modify data on the behalf of a given user. To do that, I recommend providing opaque mobile tokens during the login process. This token can then be sent with each request in a X-header so the service can authenticate the user making the request. Again, SSL is strongly recommended.</p>
<p>In this approach, we don&rsquo;t use a cookie and we actually don&rsquo;t need a SSO solution, but an unified authentication system.</p>
<p> </p>
<h2 id="writing-web-services">Writing web services</h2>
<p>Our Authentication/Accounts application turns out to be a pure web API app.</p>
<p>We also have 3 sets of APIs:</p>
<ul>
<li>
<p>Public APIs: can be accessed from anywhere, no authentication required</p>
</li>
<li>
<p>S2S APIs: authenticated via API keys and only available to trusted clients</p>
</li>
<li>
<p>Mobile APIs: authenticated via a mobile token and limited in scope.</p>
</li>
</ul>
<p>We don&rsquo;t need dynamic HTML views, just simple web service related code. While this is a little bit off topic, I&rsquo;d like to take a minute to show you how I personally like writing web service applications.</p>
<p>Something that I care a lot about when I implement web APIs is to validate incoming params. This is an opinionated approach that I picked up while at Sony and that I think should be used every time you implement a web API. As a matter of fact, I wrote a Ruby <a href="https://github.com/mattetti/Weasel-Diesel">DSL library (Weasel Diesel)</a> allowing you <a href="https://github.com/mattetti/sinatra-web-api-example/blob/master/api/hello_world.rb">describe a given service</a>, its <a href="https://github.com/mattetti/sinatra-web-api-example/blob/master/api/hello_world.rb#L7">incoming params</a>, and the <a href="https://github.com/mattetti/sinatra-web-api-example/blob/master/api/hello_world.rb#L10-15">expected output</a>. This DSL is hooked into a web backend so you can implement services using a web engine such as <a href="https://www.sinatrarb.com/">Sinatra</a> or maybe Rails3. Based on the DSL usage, incoming parameters are be verified before being processed. The other advantage is that you can generate documentation based on the API description as well as automated tests.</p>
<p>You might be familiar with <a href="https://github.com/intridea/grape">Grape</a>, another DSL for web services. Besides the obvious style difference <a href="https://github.com/mattetti/Weasel-Diesel">Weasel Diesel </a>offers the following advantages:</p>
<ul>
<li>
<p>input validation/sanitization</p>
</li>
<li>
<p>service isolation</p>
</li>
<li>
<p>generated documentation</p>
</li>
<li>
<p>contract based design</p>
</li>
</ul>
<p>Here is a hello world webservice being implemented using Weasel Diesel and Sinatra:</p>
<p>{% gist 2300131 %}</p>
<p>Basis test validating the contract defined in the DSL and the actual output when the service is called:</p>
<p>{% gist 2300440 %}</p>
<p>Generated documentation:</p>
<p><img src="https://img.skitch.com/20120404-t1j93b73tef5pmd5idfqqa61td.jpg" alt=""></p>
<p>If the DSL and its features seem appealing to you and you are interested in digging more into it, the easiest way is to fork <a href="https://github.com/mattetti/sinatra-web-api-example/">this demo repo</a> and start writing your own services.</p>
<p>The DSL has been used in production for more than a year, but there certainly are tweaks and small changes that can make the user experience even better. Feel free to fork the <a href="https://github.com/mattetti/Weasel-Diesel">DSL repo</a> and send me Pull Requests.</p>
]]></content>
		</item>
		
		<item>
			<title>learning from rails failures</title>
			<link>https://matt.aimonetti.net/posts/2012-02-learning-from-rails-failures/</link>
			<pubDate>Wed, 29 Feb 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-02-learning-from-rails-failures/</guid>
			<description>Ruby on Rails undisputedly changed the way web frameworks are designed. Rails became a reference when it comes to leveraging conventions, easy baked in feature set and a rich ecosystem. However, I think that Rails did and still does a lot of things pretty poorly. By writing this post, I&amp;rsquo;m not trying to denigrate Rails, there are many other people out there already doing that. My hope is that by listing what I think didn&amp;rsquo;t and still doesn&amp;rsquo;t go well, we can learn from our mistakes and improve existing solutions or create better new ones.</description>
			<content type="html"><![CDATA[<p>Ruby on Rails undisputedly changed the way web frameworks are designed. Rails became a reference when it comes to leveraging conventions, easy baked in feature set and a rich ecosystem. However, I think that Rails did and still does a lot of things pretty poorly.  By writing this post, I&rsquo;m not trying to denigrate Rails, there are many other people out there already doing that. My hope is that by listing what I think didn&rsquo;t and still doesn&rsquo;t go well, we can learn from our mistakes and improve existing solutions or create better new ones.</p>
<p><a href="https://merbist.com/2012/02/29/learning-from-rails-failures/train_fail/"><img src="https://merbist.com/wp-content/uploads/2012/02/train_fail-300x188.jpg" alt=""></a></p>
<h2 id="migrationupgrades">Migration/upgrades</h2>
<p>Migrating a Rails App from a version to the other is very much like playing the lottery, you are almost sure you will lose. To be more correct, you know things will break, you just don&rsquo;t know what, when and how. The Rails team seems to think that everybody is always running on the cutting edge version and don&rsquo;t consider people who prefer to stay a few version behind for stability reasons. What&rsquo;s worse is that plugins/gems might or might not compatible with the version you are updating to, but you will only know that by trying yourself and letting others try and report potential issues.</p>
<p>This is for me, by far, the biggest issue with Rails and something that should have been fixed a long time ago. If you&rsquo;re using the WordPress blog engine, you know how easy and safe it is to upgrade the engine or the plugins. Granted WordPress isn&rsquo;t a web dev framework, but it gives you an idea of what kind of experience we should be striving for.</p>
<p> </p>
<h2 id="stability-vs-playground-zone">Stability vs playground zone</h2>
<p>New features are cool and they help make the platform more appealing to new comers. They also help shape the future of a framework. But from my perspective, that shouldn&rsquo;t come to the cost of stability. Rails 3&rsquo;s new asset pipeline is a good example of a half-baked solution shoved in a release at the last minute and creating a nightmare for a lot of us trying to upgrade. I know, I know, you can turn off the asset pipeline and it got better since it was first released. But shouldn&rsquo;t that be the other way around? Shouldn&rsquo;t fun new ideas risking the stability of an app or making migration harder, be off by default and turned on only by people wanting to experiment? When your framework is young, it&rsquo;s normal that you move fast and sometimes break, but once it matures, these things shouldn&rsquo;t happen.</p>
<p> </p>
<h2 id="publicprivateplugin-apis">Public/private/plugin APIs</h2>
<p>This is more of a recommendation than anything else. When you write a framework in a very dynamic language like Ruby, people will &ldquo;monkey patch&rdquo; your code to inject features. Sometimes it is due to software design challenges, sometimes it&rsquo;s because people don&rsquo;t know better. However,  by not explicitly specifying what APIs are private (they can change at anytime, don&rsquo;t touch), what APIs are public (stable, will be slowly deprecated when they need to be changed) and which ones are for plugin devs only (APIs meant for instrumentation, extension etc..), you are making migration to newer versions much harder. You see, if you have a small, clean public API, then it&rsquo;s easy to see what could break, warn developers and avoid migration nightmares. However, you need to start doing that early on in your project, otherwise you will end up like Rails where all code can potentially change anytime.</p>
<p> </p>
<h2 id="railsmerb-merge-was-a-mistake">Rails/Merb merge was a mistake</h2>
<p>This is my personal opinion and well, feel free to disagree, nobody will ever be able to know to for sure. Without explaining what happened behind closed doors and the various personal motivations, looking at the end result, I agree with the group of people thinking that the merge didn&rsquo;t turn up to be a good thing. For me, Rails 3 isn&rsquo;t significantly better than Rails 2 and it took forever to be released. You still can&rsquo;t really run a mini Rails stack like promised. I did hear that Strobe (company who was hiring Carl Lerche, Yehuda Katz and contracted Jose Valim) used to have an ActionPack based, mini stack but it was never released and apparently only Rails core members really knew what was going on there. Performance in vanilla Rails 3 are only now getting close to what you had with Rails 2 (and therefore far from the perf you were getting with Merb). Thread-safety is still OFF by default meaning that by default your app uses a giant lock only allowing a process to handle 1 request at a time. For me, the flexibility and performance focus of Merb were mainly lost in the merge with Rails. (Granted, some important things such as ActiveModel, cleaner internals and others have made their way into Rails 3)</p>
<p>But what&rsquo;s worse than everything listed so far is that the lack of competition and the internal rewrites made Rails lose its headstart.  Rails is very much HTML/view focused, its primarily strength is to make server side views trivial and it does an amazing job at that. But let&rsquo;s be honest, that&rsquo;s not the future for web dev. The future is more and more logic pushed to run on the client side (in JS) and the server side being used as an API serving data for the view layer. I&rsquo;m sorry but adding support for CoffeeScript doesn&rsquo;t really do much to making Rails evolve ahead of what it currently is. Don&rsquo;t get me wrong, I&rsquo;m a big fan of CoffeeScript, that said I still find that Rails is far from being optimized to developer web APIs in Rails. You can certainly do it, but you are basically using a tool that wasn&rsquo;t designed to write APIs and you pay the overhead for that. If there is one thing I wish Rails will get better at is to make writing pure web APIs better (thankfully there is Sinatra). But at the end of the day, I think that two projects with different philosophies and different approaches are really hard to merge, especially in the open source world. I wouldn&rsquo;t go as far as saying like others that Rails lost its sexiness to node.js because of the wasted time, but I do think that things would have been better for all if that didn&rsquo;t happen. However, I also have to admit that I&rsquo;m not sure how much of a big deal that is. I prefer to leave the past behind, learn from my own mistake and move on.</p>
<p> </p>
<h2 id="technical-debts">Technical debts</h2>
<p>Here I&rsquo;d like to stop to give a huge props to Aaron &ldquo;<a href="https://twitter.com/tenderlove">@tenderlove</a>&rdquo; Patterson, the man who&rsquo;s actively working to reduce the <a href="https://en.wikipedia.org/wiki/Technical_debt">technical debts</a> in the Rails code base. This is a really hard job and definitely not a very glamorous one. He&rsquo;s been working on various parts of Rails including its router and its ORM (ActiveRecord). Technical debts are unfortunately normal in most project, but sometimes they are overwhelming to the point that nobody dares touching the code base to clean it up. This is a hard problem, especially when projects move fast like Rails did. But looking back, I think that you want to start tackling technical debts on the side as you move on so you avoid getting to the point that you need a hero to come up and clean the piled errors made in the past. But don&rsquo;t pause your entire project to clean things up otherwise you will lose market, momentum and excitement. I feel that this is also very much true for any legacy project you might pick up as a developer.</p>
<p> </p>
<h2 id="keep-the-cost-of-entry-level-low">Keep the cost of entry level low</h2>
<p>Getting started with Rails used to be easier. This can obviously argued since it&rsquo;s very subjective, but from my perspective I think we forgot where we come from and we involuntary expect new comers to come with unrealistic knowledge. Sure, Rails does much more than it used to do, but it&rsquo;s also much harder to get started. I&rsquo;m not going to argue how harder  it is now or why we got there. Let&rsquo;s just keep in mind that it is a critical thing that should always be re-evaluated. Sure, it&rsquo;s harder when you have an open source project, but it&rsquo;s also up to the leadership to show that they care and to encourage and mentor volunteers to  focus on this important part of a project.</p>
<p> </p>
<h2 id="documentation">Documentation</h2>
<p>Rails documentation isn&rsquo;t bad, but it&rsquo;s far from being great. Documentation certainly isn&rsquo;t one of the Ruby&rsquo;s community strength, especially compared with the Python community, but what saddens me is to see the state of <a href="https://guides.rubyonrails.org/">the official documentation</a> which, should, in theory be the reference. Note that the Rails guides are usually well written and provide value, but they too often seem too light and not useful when you try to do something not totally basic (for instance use an ActiveModel compliant object). That&rsquo;s probably why most people don&rsquo;t refer to them or don&rsquo;t spend too much time there. I&rsquo;m not trying to blame anyone there. I think that the people who contributed theses guides did an amazing job, but if you want to build a strong and easy to access community, great documentation is key. Look at the <a href="https://docs.djangoproject.com/en/1.3/">Django</a> documentation as a good example. That said, I also need to acknowledge the amazing job done by many community members such as <a href="https://railscasts.com/">Ryan Bates</a> and <a href="https://ruby.railstutorial.org/">Michael Hartl</a> consistently providing high value external documentation via the <a href="https://railscasts.com/">railscasts</a> and the intro to <a href="https://ruby.railstutorial.org/">Rails tutorial</a> available for free.</p>
<p> </p>
<p>In conclusion, I think that there is a lot to learn from Rails, lots of great things as well as lots of things you would want to avoid. We can certainly argue on Hacker News or via comments about whether or not I&rsquo;m right about Rails failures, my point will still be that the mentioned issues should be avoided in any projects, Rails here is just an example. Many of these issues are currently being addressed by the Rails team but wouldn&rsquo;t it be great if new projects learn from older ones and avoid making the same mistakes? So what other mistakes do you think I forgot to mention and that one should be very careful of avoiding?</p>
<p> </p>
<h3 id="updates">Updates:</h3>
<ol>
<li>
<p>Rails 4 had an API centric app generator but it <a href="https://github.com/rails/rails/commit/6db930cb5bbff9ad824590b5844e04768de240b1">was quickly reverted</a> and will live as gem until it&rsquo;s mature enough.</p>
</li>
<li>
<p>Rails 4 improved the ActiveModel API to be simpler to get started with. See <a href="https://blog.plataformatec.com.br/2012/03/barebone-models-to-use-with-actionpack-in-rails-4-0/">this blog</a> post for more info.</p>
</li>
</ol>
]]></content>
		</item>
		
		<item>
			<title>quick dive into ruby orm object initialization</title>
			<link>https://matt.aimonetti.net/posts/2012-02-quick-dive-into-ruby-orm-object-initialization/</link>
			<pubDate>Thu, 23 Feb 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-02-quick-dive-into-ruby-orm-object-initialization/</guid>
			<description>Yesterday I did some quick digging into how ORM objects are initialized and the performance cost associated to that. In other words, I wanted to see what&amp;rsquo;s going on when you initialize an ActiveRecord object.
Before I show you the benchmark numbers and you jump to conclusions, it&amp;rsquo;s important to realize that in the grand scheme of things, the performance cost we are talking is small enough that it is certainly not the main reason why your application is slow.</description>
			<content type="html"><![CDATA[<p>Yesterday I did some quick digging into how ORM objects are initialized and the performance cost associated to that. In other words, I wanted to see what&rsquo;s going on when you initialize an ActiveRecord object.</p>
<p>Before I show you the benchmark numbers and you jump to conclusions, it&rsquo;s important to realize that in the grand scheme of things, the performance cost we are talking is small enough that it is certainly not the main reason why your application is slow. Spoiler alert: ActiveRecord is slow but the cost of initialization isn&rsquo;t by far the worse part of ActiveRecord. Also, even though this article doesn&rsquo;t make activeRecord look good, and I&rsquo;m not trying to diss it. It&rsquo;s a decent ORM that does a great job in most cases.</p>
<p>Let&rsquo;s get started by the benchmarks number to give us an idea of the damage (using Ruby 1.9.3 p125):</p>
<p> </p>
<pre><code>                                                             | Class | Hash  | AR 3.2.1 | AR no protection | Datamapper | Sequel |
--------------------------------------------------------------------------------------------------------------------------------------
.new() x100000                                               | 0.037 | 0.049 | 1.557    | 1.536            | 0.027      | 0.209  |
.new({:id=&gt;1, :title=&gt;&quot;Foo&quot;, :text=&gt;&quot;Bar&quot;}) x100000          | 0.327 | 0.038 | 6.784    | 5.972            | 4.226      | 1.986  |
</code></pre>
<p> </p>
<p>You can see that I am comparing the allocation of a Class instance, a Hash and some ORM models. The benchmark suite tests the allocation of an empty object and one with passed attributes. The benchmark in question is available <a href="https://github.com/mattetti/benchmarks/blob/master/init_objects.rb">here</a>.</p>
<p>As you can see there seems to be a huge performance difference between allocating a basic class and an ORM class. Instantiating an ActiveRecord class is 20x slower than instantiating a normal class, while ActiveRecord offers some extra features, why is it so much slower, especially at initialization time?</p>
<p>The best way to figure it out is to profile the initialization. For that, I used <a href="https://github.com/tmm1/perftools.rb">perftools.rb</a> and I generated a graph of the call stack.</p>
<p>Here is what Ruby does (and spends its time) when you initialize a new Model instance (click to download the PDF version):</p>
<p> </p>
<p><a href="https://github.com/mattetti/benchmarks/blob/master/ar_init_profile.pdf?raw=true"><img src="https://merbist.com/wp-content/uploads/2012/02/AR-model-instantation-by-Matt-Aimonetti.jpg" alt="Profiler diagram of AR model instantiation by Matt Aimonetti"></a></p>
<p> </p>
<p>This is quite a scary graph but it shows nicely the features you are getting and their cost associated. For instance, the option of having the before and after initialization callback cost you 14% of your CPU time per instantiation, even though you probably almost never use these callbacks. I&rsquo;m reading that by interpreting the node called ActiveSupport::Callback#run_callbacks, 3rd level from the top. So 14.1% of the CPU time is spent trying to run callbacks. As a quick note, note that 90.1% of the CPU time is spent initializing objects, the rest is spent in the loop and in the garbage collection (because the profiler runs many loops). You can then follow the code and see how the code works, creating a dynamic class callback method on the fly (the one with the long name) and then recreating the name of this callback to call it each time the object is allocated. It sounds like that&rsquo;s a good place for some micro optimizations which could yield up to 14% performance increase in some cases.</p>
<p>Another major part of the CPU time is spent in ActiveModel&rsquo;s sanitization. This is the piece of code that allows you to block some model attributes to be mass assigned. This is useful when you don&rsquo;t want to sanitize your incoming params but want to create or update a model instance by using all the passed user params. To avoid malicious users to modify some specific params that might be in your model but not in your form, you can protect these attributes. A good example would be an admin flag on a User object. That said, if you manually initialize an instance, you don&rsquo;t need this extra protection, that&rsquo;s why in the benchmark above, I tested and without the protection. As you can see, it makes quite a big difference. The profiler graph of the same initialization without the mass assignment protection logically ends up looking quite different:</p>
<p> </p>
<p><a href="https://github.com/mattetti/benchmarks/blob/master/ar_init_no_protection.pdf?raw=true">
</a><a href="https://github.com/mattetti/benchmarks/blob/master/ar_init_no_protection.pdf?raw=true"><img src="https://merbist.com/wp-content/uploads/2012/02/AR-model-instantiation-without-mass-assignment-by-Matt-Aimonetti.jpg" alt="Matt Aimonetti shows the stack trace generated by the instantiation of an Active Record model"></a></p>
<p> </p>
<p><strong>Update:</strong> My colleague <a href="https://twitter.com/#!/glv">Glenn Vanderburg</a> pointed out that some people might assuming that the shown code path is called for each record loaded from the database. This isn&rsquo;t correct, the graph represents instances allocated by calling #new. See the addition at the bottom of the post for more details about what&rsquo;s going on when you fetch data from the DB.</p>
<p>I then decided to look at the graphs for the two other popular Ruby ORMs:</p>
<p><a href="https://datamapper.org/">Datamapper</a></p>
<p><a href="https://github.com/mattetti/benchmarks/blob/master/dm_init_profile.pdf?raw=true"><img src="https://img.skitch.com/20120223-txs4wa7b5rdpg45aj6354xg1wt.jpg" alt=""></a></p>
<p> </p>
<p>and <a href="https://sequel.rubyforge.org/">Sequel</a></p>
<p><a href="https://github.com/mattetti/benchmarks/blob/master/sequel_init_profile.pdf?raw=true"><img src="https://img.skitch.com/20120223-p2jx6ypk35ucsgtx7p1tcabpes.jpg" alt=""></a></p>
<p> </p>
<p> </p>
<p>While I didn&rsquo;t give you much insight in ORM code, I hope that this post will motivate you to sometimes take a look under the cover and profile your code to see what&rsquo;s going on and why it might be slow. <strong>Never assume, always measure</strong>. Tools such as perftools are a great way to get a visual feedback and get a better understanding of how the Ruby interpreter is handling your code.</p>
<h2 id="update">UPDATE:</h2>
<p>I heard you liked graphs so I added some more, here is what&rsquo;s going on when you do Model.first:</p>
<p><a href="https://github.com/mattetti/benchmarks/blob/master/ar_first_profile.pdf?raw=true"><img src="https://img.skitch.com/20120224-f23s8xctghi8mj6ax3cdw9aq25.jpg" alt=""></a></p>
<p> </p>
<p>Model.all</p>
<p><a href="https://github.com/mattetti/benchmarks/blob/master/ar_all_profile.pdf?raw=true"><img src="https://img.skitch.com/20120224-q29q4n7bj3i96erk1enxdqxb5e.jpg" alt=""></a></p>
<p> </p>
<p>And finally this is the code graph for a call to Model.instantiate which is called after a record was retrieved from the database to convert into an Object. (You can see the #instantiate call referenced in the graph above).</p>
<p> </p>
<p><a href="https://github.com/mattetti/benchmarks/blob/master/ar_instantiate_profile.pdf?raw=true"><img src="https://img.skitch.com/20120224-8scmun9n1c9ufdnxa8rq2961bq.jpg" alt=""></a></p>
]]></content>
		</item>
		
		<item>
			<title>larubyconf 2012</title>
			<link>https://matt.aimonetti.net/posts/2012-02-larubyconf-2012/</link>
			<pubDate>Sat, 04 Feb 2012 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2012-02-larubyconf-2012/</guid>
			<description>During LA RubyConf 2012 in Los Angeles, CA Matt Aimonetti gave a talk entitled Ruby: time to move on.
##Description of the talk:
Let&amp;rsquo;s be honest, Ruby became mainstream a few years back and it isn&amp;rsquo;t the cool underground programming language it once was. It&amp;rsquo;s quite likely that your cousin&amp;rsquo;s boyfriend who&amp;rsquo;s &amp;ldquo;into computers&amp;quot; knows what Ruby on Rails is. There are hundreds of books, conferences, training and meetups for Rubyists.</description>
			<content type="html"><![CDATA[<p>During <a href="https://larubyconf.org/">LA RubyConf 2012</a> in Los Angeles, CA Matt
Aimonetti gave a talk entitled <em>Ruby: time to move on</em>.</p>
<p>##Description of the talk:</p>
<p>Let&rsquo;s be honest, Ruby became mainstream a few years back and it isn&rsquo;t the cool underground programming language it once was. It&rsquo;s quite likely that your cousin&rsquo;s boyfriend who&rsquo;s &ldquo;into computers&quot; knows what Ruby on Rails is. There are hundreds of books, conferences, training and meetups for Rubyists. Recruiters fight to hire whoever knows how to generate a scaffolded Rails app. But now cool kids can&rsquo;t stop talking about node.js, CoffeeScript, Clojure, Haskell and pushing code to the UI layer. What does it mean for the new, existing and prospecting Ruby developers? Is it time to jump ship and move on to something else?</p>
<p><img src="/images/matt_aimonetti_timeToMoveOn.jpg" alt="Matt Aimonetti showing that the end result is what matters the most"></p>
<p>##Slides</p>
<script async class="speakerdeck-embed" data-id="4f904c27a542080022020653" data-ratio="1.299492385786802" src="https://speakerdeck.com/assets/embed.js"></script>
<p>The slides are available on <a href="https://speakerdeck.com/u/matt_aimonetti/p/ruby-time-to-move-on">Matt&rsquo;s SpeakerDeck</a> and can be [downloaded here]({{ page.slides }}).</p>
<p>##Video</p>
<p>{% video <a href="https://cdn.confreaks.com/system/assets/datas/3173/original/816-larubyconf2012-time-to-move-away-from-ruby-small.mp4">https://cdn.confreaks.com/system/assets/datas/3173/original/816-larubyconf2012-time-to-move-away-from-ruby-small.mp4</a> 640 360 /images/matt_aimonetti_larubyconf2012_video.png %}</p>
<p>##Presentation website</p>
<p>Matt&rsquo;s presentation was filmed by <a href="https://confreaks.com">Confreaks</a> and posted <a href="https://confreaks.com/videos/816-larubyconf2012-time-to-move-away-from-ruby">here</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>books to read in 2012 recommended to me by twitter</title>
			<link>https://matt.aimonetti.net/posts/2011-12-books-to-read-in-2012-recommended-to-me-by-twitter/</link>
			<pubDate>Fri, 30 Dec 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-12-books-to-read-in-2012-recommended-to-me-by-twitter/</guid>
			<description>Today, I asked on Twitter what non-technical books I should read in 2012.
I was nicely surprised to see so many of my followers send recommendations. Here is a list of 25 books that like-minded people suggested I read. Hopefully you will find a book or two to read too. Feel free to send more recommendations via the comments.
 1Q84 by Haruki Murakami
suggested by @mrb_bk and @chadfowler
The Floating Opera and The End of the Road by John Barthsuggested by @chadfowler</description>
			<content type="html"><![CDATA[<p>Today, I asked on Twitter what non-technical books I should read in 2012.</p>
<p>I was nicely surprised to see so many of my followers send recommendations. Here is a list of 25 books that like-minded people suggested I read. Hopefully you will find a book or two to read too. Feel free to send more recommendations via the comments.</p>
<p> </p>
<p><a href="https://www.amazon.com/gp/product/0307593312/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0307593312"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0307593312&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0307593312" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0307593312/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0307593312">1Q84 by Haruki Murakami</a></p>
<p>suggested by <a href="https://twitter.com/#!/mrb_bk">@mrb_bk</a> and <a href="https://twitter.com/#!/chadfowler">@chadfowler</a></p>
<p><a href="https://www.amazon.com/gp/product/0385240899/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0385240899"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0385240899&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0385240899" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0385240899/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0385240899">The Floating Opera and The End of the Road by John Barth</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0385240899" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/chadfowler">@chadfowler</a></p>
<p><a href="https://www.amazon.com/gp/product/0613663616/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0613663616"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0613663616&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0613663616" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0613663616/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0613663616">Into Thin Air by Jon Krakauer</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0613663616" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/bradly">@bradly</a></p>
<p><a href="https://www.amazon.com/gp/product/0375714367/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0375714367"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0375714367&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0375714367" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0375714367/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0375714367">Cutting for Stone by Abraham Verghese</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0375714367" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/bradly">@bradly</a></p>
<p><a href="https://www.amazon.com/gp/product/0452011876/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0452011876"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0452011876&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0452011876" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0452011876/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0452011876">Atlas Shrugged by Ayn Rand</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0452011876" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/bradly">@bradly</a></p>
<p><a href="https://www.amazon.com/gp/product/0307474720/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0307474720"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0307474720&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0307474720" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0307474720/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0307474720">Cien años de soledad by Gabriel Garcia Marquez</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0307474720" alt=""> (es)</p>
<p>suggested by <a href="https://twitter.com/#!/romanandreg">@romanandreg</a> &amp; <a href="https://twitter.com/#!/jrfernandez">@jrfernandez</a> &amp; <a href="https://twitter.com/#!/edgarschmidt">@edgarschmidt</a></p>
<p><a href="https://www.amazon.com/gp/product/0060883286/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0060883286"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0060883286&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0060883286" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0060883286/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0060883286">One Hundred Years of Solitude by Gabriel García Marquez</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0060883286" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/romanandreg">@romanandreg</a> &amp; <a href="https://twitter.com/#!/jrfernandez">@jrfernandez</a> &amp; <a href="https://twitter.com/#!/edgarschmidt">@edgarschmidt</a></p>
<p><a href="https://www.amazon.com/gp/product/0553348981/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0553348981"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0553348981&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0553348981" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0553348981/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0553348981">Jitterbug Perfume by Tom Robbins</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0553348981" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/supaspoida">@supaspoida</a></p>
<p><a href="https://www.amazon.com/gp/product/0062041266/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0062041266"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0062041266&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0062041266" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0062041266/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0062041266">The Sisters Brothers by Patrick deWitt</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0062041266" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/dennismajor1">@dennismajor1</a></p>
<p><a href="https://www.amazon.com/gp/product/0312278497/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0312278497"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0312278497&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0312278497" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0312278497/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0312278497">The Glass Bead Game by Hermann Hesse</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0312278497" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/dj2sincl">@dj2sincl</a></p>
<p><a href="https://www.amazon.com/gp/product/0679775439/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0679775439"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0679775439&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0679775439" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0679775439/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0679775439">The Wind-Up Bird Chronicle by Haruki Murakami</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0679775439" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/chadfowler">@chadfowler</a></p>
<p><a href="https://www.amazon.com/gp/product/0983873100/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0983873100"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0983873100&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0983873100" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0983873100/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0983873100">Mindfire by Scott Berkun</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0983873100" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/lucasdicioccio">@lucasdicioccio</a></p>
<p><a href="https://www.amazon.com/gp/product/2226052577/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=2226052577"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=2226052577&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=2226052577" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/2226052577/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=2226052577">Les Fourmis by Bernard Werber</a> (fr)</p>
<p>suggested by <a href="https://twitter.com/#!/twitty_tim">@twitty_tim</a></p>
<p><a href="https://www.amazon.com/gp/product/0375725849/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0375725849"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0375725849&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0375725849" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0375725849/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0375725849">Perfume: The Story of a Murderer by Patrick Suskind</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0375725849" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/twitty_tim">@twitty_tim</a></p>
<p><a href="https://www.amazon.com/gp/product/1613820259/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1613820259"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=1613820259&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=1613820259" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/1613820259/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1613820259">Les Miserables by Victor Hugo</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=1613820259" alt=""> (en, free ebook)</p>
<p>suggested by <a href="https://twitter.com/#!/tutec">@tutec</a></p>
<p><a href="https://www.amazon.com/gp/product/0307292134/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0307292134"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0307292134&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0307292134" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0307292134/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0307292134">Song Of Ice and Fire by George R.R. Martin</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0307292134" alt=""> (Game of Thrones saga)</p>
<p>suggested by <a href="https://twitter.com/#!/eeppa">@eeppa</a> &amp; <a href="https://twitter.com/jarin">@jarin</a></p>
<p><a href="https://www.amazon.com/gp/product/0765329468/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0765329468"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0765329468&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0765329468" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0765329468/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0765329468">Clockwork Century by Cherie Priest</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0765329468" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/eeppa">@eeppa</a></p>
<p><a href="https://www.amazon.com/gp/product/1590201183/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1590201183"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=1590201183&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=1590201183" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/1590201183/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1590201183">The Darkness that Comes Before by R. Scott Bakker</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=1590201183" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/eeppa">@eeppa</a></p>
<p><a href="https://www.amazon.com/gp/product/B003GAN3VE/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B003GAN3VE"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=B003GAN3VE&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=B003GAN3VE" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/B003GAN3VE/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B003GAN3VE">Drood by Dan Simmons</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=B003GAN3VE" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/eeppa">@eeppa</a></p>
<p><a href="https://www.amazon.com/gp/product/0316068225/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0316068225"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0316068225&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0316068225" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0316068225/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0316068225">This Is Water by David Foster Wallace</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0316068225" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/atduskgreg">@atduskgreg</a></p>
<p><a href="https://www.amazon.com/gp/product/B005DI71QA/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B005DI71QA"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=B005DI71QA&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=B005DI71QA" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/B005DI71QA/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B005DI71QA">Anathem by Neal Stephenson</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=B005DI71QA" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/jarin">@jarin</a></p>
<p><a href="https://www.amazon.com/gp/product/0812550706/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0812550706"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0812550706&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0812550706" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0812550706/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0812550706">Ender&rsquo;s Game by Orson Scott Card</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0812550706" alt=""> (entire saga)</p>
<p>suggested by <a href="https://twitter.com/#!/jarin">@jarin</a> &amp; <a href="https://twitter.com/#!/edgarschmidt">@edgarschmidt</a></p>
<p><a href="https://www.amazon.com/gp/product/344245302X/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=344245302X"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=344245302X&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=344245302X" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/344245302X/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=344245302X">Snow Crash by Neal Stephenson</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=344245302X" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/jarin">@jarin</a></p>
<p><a href="https://www.amazon.com/gp/product/1422171647/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1422171647"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=1422171647&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=1422171647" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/1422171647/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=1422171647">Fixing the Game by Roger L. Martin</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=1422171647" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/jarkko">@jarkko</a></p>
<p><a href="https://www.amazon.com/gp/product/0307387895/ref=as_li_ss_il?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0307387895"><img src="https://ws.assoc-amazon.com/widgets/q?_encoding=UTF8&amp;Format=_SL110_&amp;ASIN=0307387895&amp;MarketPlace=US&amp;ID=AsinImage&amp;WS=1&amp;tag=merbist-20&amp;ServiceVersion=20070822" alt=""></a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0307387895" alt=""></p>
<p><a href="https://www.amazon.com/gp/product/0307387895/ref=as_li_ss_tl?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=0307387895">The Road by Cormac McCarthy</a><img src="https://www.assoc-amazon.com/e/ir?t=merbist-20&amp;l=as2&amp;o=1&amp;a=0307387895" alt=""></p>
<p>suggested by <a href="https://twitter.com/#!/mrreynolds">@mrreynolds</a></p>
]]></content>
		</item>
		
		<item>
			<title>developing a curriculum</title>
			<link>https://matt.aimonetti.net/posts/2011-12-developing-a-curriculum/</link>
			<pubDate>Wed, 21 Dec 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-12-developing-a-curriculum/</guid>
			<description>Recently I asked a friend of mine to give me pointers on how to develop a curriculum (he used to teach an education PHD program), after discussing his response on Twitter, people asked me to put it somewhere, so here it is:
Process to develop a curriculum:
Purpose. Know why you&amp;rsquo;re doing what you&amp;rsquo;re doing.
 You know how to do this.  Product. Start with the end in mind.</description>
			<content type="html"><![CDATA[<p>Recently I asked a friend of mine to give me pointers on how to develop a curriculum (he used to teach an education PHD program), after discussing his response on Twitter, people asked me to put it somewhere, so here it is:</p>
<p>Process to develop a curriculum:</p>
<p><strong>Purpose</strong>. <em>Know why you&rsquo;re doing what you&rsquo;re doing.</em></p>
<ul>
<li>You know how to do this.</li>
</ul>
<p><strong>Product</strong>. <em>Start with the end in mind.</em></p>
<ul>
<li>
<p>What does the student look like when they walk out the door at the end of the training.</p>
</li>
<li>
<p>Usually, we break these down into <strong>Knowledge</strong>, <strong>Skills</strong>, or <strong>Attitudes</strong>.</p>
</li>
<li>
<p>Sometimes it&rsquo;s helpful to see a photograph or drawing of a someone who finished the program and just talk about what they can do that makes them successful.</p>
</li>
<li>
<p>This &ldquo;product&rdquo; should be connected and help you accomplish your mission</p>
</li>
</ul>
<p><strong>Practices</strong>. <em>Then ask yourself, &ldquo;How do people become like this?&quot;</em></p>
<ul>
<li>
<p>If you can break down your Product into 3-5 bit-sized chunks, then see how people learn each one of those skills, gain each one of those knowledge points, and how to they gain the attitudes you want them to have.</p>
</li>
<li>
<p>This one is much easier the more experience you have in seeing people develop the &ldquo;Product.&rdquo;</p>
</li>
<li>
<p>This is also easier to determine when you understand <a href="https://en.wikipedia.org/wiki/Learning_theory_(education)">Learning Theory</a>.</p>
</li>
<li>
<p>The results from this section will result in a list of:</p>
<ul>
<li>
<p>       Activities or experiences</p>
</li>
<li>
<p>       Resources. What books, website, teachers, software, etc. will help them learn more effectively and efficiently</p>
</li>
<li>
<p>       Assessments. How you would know if the activity was helpful?</p>
</li>
</ul>
</li>
</ul>
<p><strong>Plans</strong>. <em>Make your plans based on the practices you&rsquo;ve determined you&rsquo;ve needed.</em></p>
<p> </p>
<p>On a related topic, Chad Fowler posted an interesting <a href="https://chadfowler.com/2011/12/21/re-thinking-software-development-education">blog post about what LivingSocial is doing to change the software development education</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>rubyconf argentina 2011</title>
			<link>https://matt.aimonetti.net/posts/2011-11-rubyconf-argentina-2011/</link>
			<pubDate>Tue, 08 Nov 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-11-rubyconf-argentina-2011/</guid>
			<description>During RubyConf Argentina 2011 in Buenos Aires, Argentina Matt Aimonetti gave a talk entitled Inside Ruby: concurrency &amp;amp; garbage collection explained.
##Description of the talk:
Concurrency in Ruby and Python implementations is quite a hot topic nowadays. In this talk, Matt will explain how concurrency works for a language that uses a Global Interpreter Lock and it means concretely. Finally Aimonetti will also cover Ruby&amp;rsquo;s garbage collector (GC) and why it&amp;rsquo;s important to understand how automatic memory management works to get better performance out of your code.</description>
			<content type="html"><![CDATA[<p>During <a href="https://rubyconfargentina.org/en">RubyConf Argentina 2011</a> in Buenos Aires, Argentina Matt
Aimonetti gave a talk entitled <em>Inside Ruby: concurrency &amp; garbage collection explained</em>.</p>
<p>##Description of the talk:</p>
<p>Concurrency in Ruby and Python implementations is quite a hot topic
nowadays. In this talk, Matt will explain how concurrency works for a
language that uses a Global Interpreter Lock and it means concretely.
Finally Aimonetti will also cover Ruby&rsquo;s garbage collector (GC)
and why it&rsquo;s important to understand how automatic memory
management works to get better performance out of your code.</p>
<p>##Slides</p>
<p>[<img src="/images/Matt_Aimonetti_-_RubyConf_Argentina_2011.jpg" alt="Matt Aimonetti&rsquo;s slides of his RubyConf Argentina presentation">]({{ page.slides }})
[The HTML5 slides can be seen online]({{ page.slides}}).</p>
<p>##Video</p>
<div class="video-container">
<iframe src="https://player.vimeo.com/video/38531248?title=0&amp;byline=0&amp;portrait=0" width="600" height="500" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe><p><a href="https://vimeo.com/38531248">Matt Aimonetti - Inside Ruby: concurrency & garbage collection explained</a> from <a href="https://vimeo.com/rubyargentina">Ruby Argentina</a> on <a href="https://vimeo.com">Vimeo</a>.</p>
</div>
<p>[Vimeo page of the presentation]({{ page.video_page }})</p>
<p>##Presentation website</p>
<p>Matt&rsquo;s presentation was filmed by <a href="https://rubyconfigargentina.org/">RubyConf Argentina</a> and posted [here]({{ page.video_page }}).</p>
<p>##Matt&rsquo;s articles related to this presentation</p>
<ul>
<li><a href="/posts/2011/10/03/about-concurrency-and-the-gil/">About concurrency and the GIL</a></li>
<li><a href="/posts/2011/10/18/data-safety-and-gil-removal/">Data safety and GIL removal</a></li>
<li><a href="/posts/2011/02/22/concurrency-in-ruby-explained/">Concurrency in Ruby explained</a></li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>data safety and gil removal</title>
			<link>https://matt.aimonetti.net/posts/2011-10-data-safety-and-gil-removal/</link>
			<pubDate>Tue, 18 Oct 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-10-data-safety-and-gil-removal/</guid>
			<description>After my recent RubyConf talk and follow up post addressing the Ruby &amp;amp; Python&amp;rsquo;s Global Interpreter Lock (aka GVL/Global VM Lock). a lot of people asked me to explain what I meant by &amp;ldquo;data safety&amp;rdquo;. While my point isn&amp;rsquo;t to defend one approach or the other, I spent a lot of time explaining why C Ruby and C Python use a GIL and where it matters and where it matters less.</description>
			<content type="html"><![CDATA[<p>After my recent <a href="https://rubyconf11.merbist.com">RubyConf talk</a> and <a href="https://merbist.com/2011/10/03/about-concurrency-and-the-gil/">follow up post addressing the Ruby &amp; Python&rsquo;s Global Interpreter Lock</a> (aka GVL/Global VM Lock). a lot of people asked me to explain what I meant by &ldquo;data safety&rdquo;. While my point isn&rsquo;t to defend one approach or the other, I spent a lot of time explaining why C Ruby and C Python use a GIL and where it matters and where it matters less. As a reminder and as mentioned by Matz himself, the main reason why C Ruby still has a GIL is data safety. But if this point isn&rsquo;t clear to you, you might be missing the main argument supporting the use of a GIL.</p>
<p>Showing obvious concrete examples of data corruption due to unsafe threaded code isn&rsquo;t actually as easy at it sounds. First of all, even with a GIL, developers can write unsafe threaded code. So we need to focus only on the safety problems raised by removing the GIL. To demonstrate what I mean, I will try to create some race conditions and show you the unexpected results you might get. Again, before you go crazy on the comments, remember that threaded code is indeterministic and the code below might potentially work on your machine and that&rsquo;s exactly why it is hard to demonstrate. Race conditions depend on many things, but in this case I will focus on race conditions affecting basic data structures since it might be the most surprising.</p>
<h2 id="example">Example:</h2>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">@array, threads <span style="color:#f92672">=</span> <span style="color:#f92672">[]</span>, <span style="color:#f92672">[]</span>
<span style="color:#ae81ff">4</span><span style="color:#f92672">.</span>times <span style="color:#66d9ef">do</span>
  threads <span style="color:#f92672">&lt;&lt;</span> <span style="color:#66d9ef">Thread</span><span style="color:#f92672">.</span>new { (<span style="color:#ae81ff">1</span><span style="color:#f92672">..</span><span style="color:#ae81ff">100_000</span>)<span style="color:#f92672">.</span>each {<span style="color:#f92672">|</span>n<span style="color:#f92672">|</span> @array <span style="color:#f92672">&lt;&lt;</span> n} }
<span style="color:#66d9ef">end</span>
threads<span style="color:#f92672">.</span>each{<span style="color:#f92672">|</span>t<span style="color:#f92672">|</span> t<span style="color:#f92672">.</span>join }
puts @array<span style="color:#f92672">.</span>size
</code></pre></div><p>In the above example, I&rsquo;m creating an instance variable of Array type and I start 4 threads. Each of these threads adds 100,000 items to the array. We then wait for all the threads to be done and check the size of the array.</p>
<p>If you run this code in C Ruby the end result will be as expected:</p>
<pre><code>400000
</code></pre>
<p>Now if you switch to JRuby you might be surprised by the output. If you are lucky you will see the following:</p>
<pre><code>ConcurrencyError: Detected invalid array contents due to unsynchronized modifications with concurrent users
        &lt;&lt; at org/jruby/RubyArray.java:1147
  __file__ at demo.rb:3
      each at org/jruby/RubyRange.java:407
  __file__ at demo.rb:3
      call at org/jruby/RubyProc.java:274
      call at org/jruby/RubyProc.java:233
</code></pre>
<p>This is actually a good thing. JRuby detects that you are unsafely modifying an instance variable across threads and that data corruption will occur. However, the exception doesn&rsquo;t always get raised and you will potentially see results such as:</p>
<pre><code>335467
342397
341080
</code></pre>
<p>This is a sign that the data was corrupted but that JRuby didn&rsquo;t catch the unsynchronized modification. On the other hand MacRuby and Rubinius 2 (dev) won&rsquo;t raise any exceptions and will just corrupt the data, outputting something like:</p>
<pre><code>294278
285755
280704
279865
</code></pre>
<p>In other words, if not manually synchronized, shared data can easily be corrupted. You might have two threads modifying the value of the same variable and one of the two threads will step on top of the other leaving you with a race condition. You only need 2 threads accessing the same instance variable at the same time to get a race condition. My example uses more threads and more mutations to make the problem more obvious. Note that TDD wouldn&rsquo;t catch such an issue and even extensive testing will provide very little guarantee that your code is thread safe.</p>
<p> </p>
<h2 id="so-what-thread-safety-isnt-a-new-problem">So what? Thread safety isn&rsquo;t a new problem.</h2>
<p>That&rsquo;s absolutely correct, ask any decent Java developer out there, he/she will tell how locks are used to &ldquo;easily&rdquo; synchronize objects to make your code thread safe. They might also mention the deadlocks and other issues related to that, but that&rsquo;s a different story. One might also argue that when you write web apps, there is very little shared data and the chances of corrupting data across concurrent requests is very small since most of the data is kept in a shared data store outside of the process.</p>
<p>All these arguments are absolutely valid, the challenge is that you have a large community and a large amount of code out there that expects a certain behavior. And removing the GIL does change this behavior. It might not be a big deal for you because you know how to deal with thread safety, but it might be a big deal for others and C Ruby is by far the most used Ruby implementation. It&rsquo;s basically like saying that automatic cars shouldn&rsquo;t be made and sold, and everybody has to switch to stick shifts. They have better gas mileage, I personally enjoy driving then and they are cheaper to build. Removing the GIL is a bit like that. There is a cost associated with this decision and while this cost isn&rsquo;t insane, the people in charge prefer to not pay it.</p>
<p> </p>
<h2 id="screw-that-ill-switch-to-nodejs">Screw that, I&rsquo;ll switch to Node.js</h2>
<p>I heard a lot of people telling me they were looking into using Node.js because it has a better design and no GIL. While I like Node.js and if I were to implement a chat room or an app keeping connections for a long time, I would certainly compare it closely to EventMachine, I also think that this argument related to the GIL is absurd. First, you have other Ruby implementations which don&rsquo;t have a GIL and are really stable (i.e: JRuby) but then Node basically works the same as Ruby with a GIL. Yes, Node is evented and single threaded but when you think about it, it behaves the same as Ruby 1.9 with its GIL. Many requests come in and they are handled one after the other and because IO requests are non-blocking, multiple requests can be processed concurrently but not in parallel. Well folks, that&rsquo;s exactly how C Ruby works too, and unlike popular believe, most if not all the popular libraries making IO requests are non blocking (when using 1.9). So, next time you try to justify you wanting to toy with Node, please don&rsquo;t use the GIL argument.</p>
<p> </p>
<h2 id="what-should-i-do">What should I do?</h2>
<p>As always, evaluate your needs and see what makes sense for your project. Start by making sure you are using Ruby 1.9 and your code makes good use of threading. Then look at your app and how it behaves, is it CPU-bound or IO-bound. Most web apps out there are IO-bound (waiting for the DB, redis or API calls), and when doing an IO call, Ruby&rsquo;s GIL is released allowing another thread to do its work. In that case, not having a GIL in your Ruby implementation won&rsquo;t help you. However, if your app is CPU-bound, then switching to JRuby or Rubinius might be beneficial. However, don&rsquo;t assume anything until you proved it and remember that making such a change will more than likely require some architectural redesign, especially if using JRuby.  But, hey, it might totally be worth it as many proved it in the past.</p>
<p> </p>
<p>I hope I was able to clarify things a bit further. If you wish to dig further, I would highly recommend you read the many discussions the Python community had in the last few years.</p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
]]></content>
		</item>
		
		<item>
			<title>about management</title>
			<link>https://matt.aimonetti.net/posts/2011-10-about-management/</link>
			<pubDate>Tue, 11 Oct 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-10-about-management/</guid>
			<description>I decided to save myself a session to the shrink and instead just write down my reflection on management. Who knows, some of you might help me and/or challenge my thought process.
I recently read a great management book called the five dysfunctions of a team by Patrick Lencioni . Instead of telling you what to do, the author highlights behavior patterns that are related to each other and when aggregated result in dysfunctional teams.</description>
			<content type="html"><![CDATA[<p>I decided to save myself a session to the shrink and instead just write down my reflection on management. Who knows, some of you might help me and/or challenge my thought process.</p>
<p>I recently read a great management book called the <a href="https://www.amazon.com/dp/B000UCUX0K/ref=as_li_ss_til?tag=merbist-20&amp;camp=213381&amp;creative=390973&amp;linkCode=as4&amp;creativeASIN=B000UCUX0K&amp;adid=0BP6N5GHZD0EW2N7QVZR&amp;">five dysfunctions of a team by Patrick Lencioni</a> . Instead of telling you what to do, the author highlights behavior patterns that are related to each other and when aggregated result in dysfunctional teams. I really liked the book because instead of a being a cookbook/playbook, this is more a fail book, in other words, it illustrates what you don&rsquo;t want to do and explains why. It highlights very well the relation between various behaviors and nicely illustrates why teams of brilliant people can fail. The <a href="https://www.amazon.com/dp/B000UCUX0K/ref=as_li_ss_til?tag=merbist-20&amp;camp=213381&amp;creative=390973&amp;linkCode=as4&amp;creativeASIN=B000UCUX0K&amp;adid=0BP6N5GHZD0EW2N7QVZR&amp;">Kindle version is at less than $5, go get it</a> and read it on your iPhone/iPad/computer/browser…</p>
<p>So this book somewhat changed my perception of management and leadership. Interesting enough, at Sony, my previous employer, they make a distinction between management and leadership. While they hope managers can be leaders, they don&rsquo;t require them to be and to be honest very few are. I&rsquo;m not sure that&rsquo;s a good or a bad things, but I, for sure, was under different expectations. Finally, I spent a large amount of my life on the internet working on/with projects where meritocracy, respect and honor were key. The &ldquo;ranking&rdquo; is purely based on what your peers think of you and not based on your age/sex/origin/diploma/bank account. I do realize that this model has many pros but also some pretty major cons. My only point is that it did affect my worldview. In my world, seniority, a killer  job title or a fancy suit won&rsquo;t buy you my automatic respect. On the other hand, job well done, great vision, honesty, over achievement will!</p>
<p>Taking these few trains of thoughts in consideration, I started thinking about my own expectations for a good manager/leader. I figured that if I were able to do that, I could possibly be able to define a work environment where I could thrive and maybe one day become a good &ldquo;manager/leader&rdquo;.</p>
<p>I&rsquo;ve always questioned my ability to be a good leader. While most of the time, I have an opinion and can easily decide what I think should be done, I have a hard time relating to people who can&rsquo;t see the &ldquo;big picture&rdquo;. While I usually can get decent results, I&rsquo;m aware that it can unfortunately sometime be at the cost of a few bruised egos. I also know I have high expectations for myself and for others and I have a hard time understanding how some people can be ok with the &ldquo;status-quo&rdquo;. I&rsquo;m a perfectionist who is only happy when he outperforms his previous achievement. I was raised to challenge and always push myself further, focusing on concrete end-results and achieved goals. And to be honest, that&rsquo;s what I enjoy. But I also know for a fact, that many people are not like that and I can&rsquo;t blame them for looking at things from a different angle and not sharing the same motivations. Furthermore, I know that most people actually don&rsquo;t have the same driven temperament and that&rsquo;s why I&rsquo;ve questioned my abilities to lead others.</p>
<p>However, different temperaments can work together as long as there is respect. And by respect, I mean that everyone feel that they were being heard and know that their input was considered and addressed even though the outcome might not be as hoped for. But for respect to happen, you first need trust. And when people trust each other, Lencioni explains that <em>&ldquo;people don&rsquo;t hold back one with another. They are unafraid to air their dirty laundry. They admit their mistakes, their weaknesses, and their concerns without fear of reprisal&rdquo;</em>. I think that as simple as it seems, it is the key to a successful team. A good leader should be able to create such an atmosphere where people can trust each other. In fact, I think that if a manger/leader/executive can manage to build trust as defined earlier, his technical skills or lack of vision don&rsquo;t matter as much. He/she will be able to rely on people he trusts to help him make the right decisions. Of course, there is much more than to be a good leader, but I think that with this base, great things can be built, and without it, a much greater effort is required to get some good results.</p>
<p>Based on my findings, I think that I need to work on my communication so others don&rsquo;t feel that they have to hold back and make sure everyone feels that their opinions were considered and addressed. To do that a key element is to admit my mistakes and weaknesses and asking others to help me improve. That&rsquo;s it, sorry for the boring, not technical post. I promise the next one will have at least a code sample.</p>
]]></content>
		</item>
		
		<item>
			<title>about concurrency and the gil</title>
			<link>https://matt.aimonetti.net/posts/2011-10-about-concurrency-and-the-gil/</link>
			<pubDate>Mon, 03 Oct 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-10-about-concurrency-and-the-gil/</guid>
			<description>During RubyConf 2011, concurrency was a really hot topic. This is not a new issue, and the JRuby team has been talking about true concurrency for quite a while . The Global Interpreter Lock has also been in a subject alot of discussions in the Python community and it&amp;rsquo;s not surprising that the Ruby community experiences the same debates since the evolution of their implementations are somewhat similar. (There might also be some tension between EngineYard hiring the JRuby and Rubinius teams and Heroku which recently hired Matz (Ruby&amp;rsquo;s creator) and Nobu, the #1 C Ruby contributor)</description>
			<content type="html"><![CDATA[<p>During RubyConf 2011, concurrency was a really hot topic. This is not a new issue, and the JRuby team has been talking about true concurrency for quite a while . The Global Interpreter Lock has also been in a subject a<a href="https://wiki.python.org/moin/GlobalInterpreterLock"> lot of discussions in the Python community</a> and it&rsquo;s not surprising that the Ruby community experiences the same debates since the evolution of their implementations are somewhat similar. (There might also be some tension between <a href="https://engineyard.com">EngineYard</a> hiring the JRuby and Rubinius teams and <a href="https://heroku.com">Heroku</a> which <a href="https://blog.heroku.com/archives/2011/7/12/matz_joins_heroku/">recently hired Matz</a> (Ruby&rsquo;s creator) and <a href="https://github.com/nobu">Nobu</a>, the #1 C Ruby contributor)</p>
<p>The GIL was probably even more of a hot topic now that <a href="https://rubini.us/">Rubinius</a> is about the join <a href="https://jruby.org">JRuby</a> and <a href="https://macruby.org">MacRuby</a> in the realm of GIL-less Ruby implementations.</p>
<p>During my RubyConf talk (<a href="https://rubyconf11.merbist.com/">slides here</a>), I tried to explain how C Ruby works and why some decisions like having a GIL were made and why the Ruby core team isn&rsquo;t planning on removing this GIL anytime soon. The GIL is something a lot of Rubyists love to hate, but a lot of people don&rsquo;t seem to question why it&rsquo;s here and why Matz doesn&rsquo;t want to remove it. Defending the C Ruby decision isn&rsquo;t quite easy for me since I spend my free time working on an alternative Ruby implementation which doesn&rsquo;t use a GIL (MacRuby). However, I think it&rsquo;s important that people understand why the MRI team (C Ruby team) and some Pythonistas feels so strongly about the GIL.</p>
<p><strong>What is the GIL?</strong></p>
<p>Here is a quote from the <a href="https://wiki.python.org/moin/GlobalInterpreterLock">Python wiki</a>:</p>
<blockquote>
<p>In CPython, the <strong>global interpreter lock</strong>, or <strong>GIL</strong>, is a mutex that prevents multiple native threads from executing Python bytecodes at once. This lock is necessary mainly because CPython&rsquo;s memory management is not thread-safe. (However, since the GIL exists, other features have grown to depend on the guarantees that it enforces.) [&hellip;] The GIL is controversial because it prevents multithreaded CPython programs from taking full advantage of multiprocessor systems in certain situations. Note that potentially blocking or long-running operations, such as I/O, image processing, and <a href="https://wiki.python.org/moin/NumPy">NumPy</a> number crunching, happen <em>outside</em> the GIL. Therefore it is only in multithreaded programs that spend a lot of time inside the GIL, interpreting CPython bytecode, that the GIL becomes a bottleneck.</p>
</blockquote>
<p>The same basically applies to C Ruby. To illustrate the quote above, here is a diagram representing two threads being executed by C Ruby:</p>
<p><a href="https://rubyconf11.merbist.com/#44"><img src="https://rubyconf11.merbist.com/images/thread_scheduling.023.jpg" alt="Fair thread scheduling in Ruby by Matt Aimonetti"></a></p>
<p>Such a scheduling isn&rsquo;t a problem at all when you only have 1 cpu, since a cpu can only execute a piece of code at a time and context switching happens all the time to allow the machine to run multiple processes/threads in parallel. The problem is when you have more than 1 CPU because in that case, if you were to only run 1 Ruby process, then you would most of the time only use 1 cpu at a time. If you are running on a 8 cpu box, that&rsquo;s not cool at all! A lot of people stop at this explanation and imagine that their server can only handle one request at a time and they they rush to sign Greenpeace petitions asking Matz to make Ruby greener by optimizing Ruby and saving CPU cycles. Well, the reality is slightly different, I&rsquo;ll get back to that in a minute. Before I explain &ldquo;ways to achieve true concurrency with CRuby, let me explain why C Ruby uses a GIL and why each implementation has to make an important choice and in this case both CPython and C Ruby chose to keep their GIL.</p>
<p> </p>
<h3 id="why-a-gil-in-the-first-place">Why a GIL in the first place?</h3>
<ul>
<li>
<p>It makes developer&rsquo;s lives easier (it&rsquo;s harder to corrupt data)</p>
</li>
<li>
<p>It avoids race conditions within C extensions</p>
</li>
<li>
<p>It makes C extensions development easier (no write barriers..)</p>
</li>
<li>
<p>Most of the C libraries which are wrapped are not thread safe</p>
</li>
<li>
<p>Parts of Ruby&rsquo;s implementation aren&rsquo;t threadsafe (Hash for instance)</p>
</li>
</ul>
<p>Categories = [</p>
]]></content>
		</item>
		
		<item>
			<title>rubyconf 2011</title>
			<link>https://matt.aimonetti.net/posts/2011-10-rubyconf-2011/</link>
			<pubDate>Sat, 01 Oct 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-10-rubyconf-2011/</guid>
			<description>During RubyConf 2011 in New Orleans, LA Matt Aimonetti gave a talk entitled Complex Ruby concepts simplified.
##Description of the talk:
Programming languages, such as Ruby, are natural and elegant. But to achieve this elegance, things have to happen under the hood. Garbage Collection, concurrency, Global Interpreter Lock, metaprogramming, C extensions are just some of the things happening with or without our knowledge. Trying to understand these concepts, their implementations and their implications in daily coding might seem daunting.</description>
			<content type="html"><![CDATA[<p>During <a href="https://rubyconf.org/">RubyConf 2011</a> in New Orleans, LA Matt
Aimonetti gave a talk entitled <em>Complex Ruby concepts simplified</em>.</p>
<p>##Description of the talk:</p>
<p>Programming languages, such as Ruby, are natural and elegant. But to achieve this elegance, things have to happen under the hood. Garbage Collection, concurrency, Global Interpreter Lock, metaprogramming, C extensions are just some of the things happening with or without our knowledge. Trying to understand these concepts, their implementations and their implications in daily coding might seem daunting. However, having a good understanding of these topics will make you a better developer. No CS degree or PhD required to attend this talk.</p>
<p>At the end of the talk, Matz (Ruby&rsquo;s creator) came on stage to answer
some questions related to what was explained.</p>
<p>##Slides
[The HTML5 slides can be seen online]({{ page.slides}}) online.</p>
<p>##Video</p>
<p>{% video <a href="https://cdn.confreaks.com/system/assets/datas/2666/original/714-rubyconf2011-complex-ruby-concepts-dummified-small.mp4">https://cdn.confreaks.com/system/assets/datas/2666/original/714-rubyconf2011-complex-ruby-concepts-dummified-small.mp4</a> 640 360 /images/matt_aimonetti_presentation_ruby.jpg %}</p>
<p>##Presentation website</p>
<p>Matt&rsquo;s presentation was filmed by <a href="https://confreaks.com/">confreaks</a> and the dedicated page
for the talk is available [here]({{ page.video_page }}).</p>
<p>##Matt&rsquo;s articles related to this presentation</p>
<ul>
<li><a href="/posts/2011/10/03/about-concurrency-and-the-gil/">About concurrency and the GIL</a></li>
<li><a href="/posts/2011/10/18/data-safety-and-gil-removal/">Data safety and GIL removal</a></li>
<li><a href="/posts/2011/02/22/concurrency-in-ruby-explained/">Concurrency in Ruby explained</a></li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>how to cross domain ajax in a ruby app</title>
			<link>https://matt.aimonetti.net/posts/2011-09-how-to-cross-domain-ajax-in-a-ruby-app/</link>
			<pubDate>Wed, 14 Sep 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-09-how-to-cross-domain-ajax-in-a-ruby-app/</guid>
			<description>In some cases, you might have a bunch of apps running on different domains/subdomains and/or ports and you would like to make ajax requests between these services. The problem is that browsers wouldn&amp;rsquo;t let you make such requests because of the Same Origin Policy which only allowed them to make request to resources within the same domain.
However, most browsers (IE 8+, Firefox 3.5+, Safari 4+, Chrome) implement a simple way to allow cross domain requests as defined in this w3C document.</description>
			<content type="html"><![CDATA[<p>In some cases, you might have a bunch of apps running on different domains/subdomains and/or ports and you would like to make ajax requests between these services. The problem is that browsers wouldn&rsquo;t let you make such requests because of the Same Origin Policy which only allowed them to make request to resources within the same domain.</p>
<p>However, most browsers (IE 8+, Firefox 3.5+, Safari 4+, Chrome) implement a simple way to allow cross domain requests as defined in this <a href="https://www.w3.org/TR/cors/">w3C document</a>.</p>
<p>Of course, if your users have an old version of their browser, you  might have to look into jsonp or something else such as cheating by using iframes &amp; setting document.domain. Let&rsquo;s pretend for a minute that 100% of your users are on Chrome. The only thing you need to do is set a response header listing the accepted domains or &ldquo;*&rdquo; for all. A simple Rack middleware to do that would look like that.</p>
<p> </p>
<pre><code>class XOriginEnabler
  ORIGIN_HEADER = &quot;Access-Control-Allow-Origin&quot;

  def initialize(app, accepted_domain=&quot;*&quot;)
    @app = app
    @accepted_domain = accepted_domain
  end

  def call(env)
    status, header, body = @app.call(env)
    header[ORIGIN_HEADER] = @accepted_domain
    [status, header, body]
  end
end
</code></pre>
<p>And to use the middleware you would need to set it for use:</p>
<pre><code>use XOriginEnabler
</code></pre>
<p>To enable all requests from whatever origin, or pass the white listed domain(s) as shown below.</p>
<pre><code>use XOriginEnabler, &quot;demo.mysite.com demo.mysite.fr demo.techcrunch.com&quot;
</code></pre>
<p>For a full featured middleware, see <a href="https://github.com/cyu/rack-cors">this project</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>ruby optimization example and explaination</title>
			<link>https://matt.aimonetti.net/posts/2011-09-ruby-optimization-example-and-explaination/</link>
			<pubDate>Mon, 05 Sep 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-09-ruby-optimization-example-and-explaination/</guid>
			<description>Recently I wrote a small DSL that allows the user to define some code that then gets executed later on and in different contexts. Imagine something like Sinatra where each route action is defined in a block and then executed in context of an incoming request.
The challenge is that blocks come with their context and you can&amp;rsquo;t execute a block in the context of another one.
Here is a reduction of the challenge I was trying to solve:</description>
			<content type="html"><![CDATA[<p>Recently I wrote a small DSL that allows the user to define some code that then gets executed later on and in different contexts. Imagine something like Sinatra where each route action is defined in a block and then executed in context of an incoming request.</p>
<p>The challenge is that blocks come with their context and you can&rsquo;t execute a block in the context of another one.</p>
<p>Here is a reduction of the challenge I was trying to solve:</p>
<pre><code>class SolutionZero
  def initialize(origin, &amp;block;)
    @origin = origin
    @block = block
  end

  def dispatch
    @block.call
  end
end

SolutionZero.new(42){ @origin + 1 }.dispatch
# undefined method `+' for nil:NilClass (NoMethodError)
</code></pre>
<p>The problem is that the block refers to the @origin instance variable which is not available in its context.
My first workaround was to use instance_eval:</p>
<pre><code>class SolutionOne
  def initialize(origin, &amp;block;)
    @origin = origin
    @block = block
  end

  def dispatch
    self.instance_eval &amp;@block
  end
end

SolutionOne.new(40){ @origin + 2}.dispatch
# 42
</code></pre>
<p>My workaround worked fine, since the block was evaluated in the context of the instance and therefore the @origin ivar is made available to block context. Technically, I was good to go, but I wasn&rsquo;t really pleased with this solution. First using instance_eval often an indication that you are trying to take a shortcut. Then having to convert my block stored as a block back into a proc every single dispatch makes me sad. Finally, I think that this code is probably not performing as well as it could, mainly due to unnecessary object allocations and code evaluation.
I did some benchmarks replacing <a href="https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1323">instance_eval</a> by <a href="https://github.com/ruby/ruby/blob/trunk/vm_eval.c#L1355">instance_exec</a> since looking at the C code, instance_exec should be slightly faster. Turns out, it is not so I probably missed something when reading the implementation code.</p>
<p>I wrote some more benchmarks and profiled a loop of 2 million dispatches (only the #disptach method call on the same object). The GC profiler report showed that the GC was invoked 287 times and each invocation was blocking the execution for about 0.15ms.
Using Ruby&rsquo;s <a href="https://ruby-doc.org/core/classes/ObjectSpace.html#M001526">ObjectSpace</a> and <a href="https://ruby-doc.org/core/classes/GC.html#M001373">disabling the GC</a> during the benchmark, I could see that each loop allocates an object of type T_NODE which is more than likely our @block ivar converted back into a block. This is quite a waste. Furthermore, having to evaluate our block in a different context every single call surely isn&rsquo;t good for performance.</p>
<p>So instead of doing the work at run time, why not doing it at load time? By that I mean that we can optimize the #dispatch method if we could &ldquo;precompile&rdquo; the method body instead of &ldquo;proxying&rdquo; the dispatch to an instance_eval call. Here is the code:</p>
<pre><code>class SolutionTwo
  def initialize(origin, &amp;block;)
    @origin = origin
    implementation(block)
  end

  private

  def implementation(block)
    mod = Module.new
    mod.send(:define_method, :dispatch, block)
    self.extend mod
  end
end

SolutionTwo.new(40){ @origin + 2}.dispatch
# 42
</code></pre>
<p>This optimization is based on the fact that the benchmark (and the real life usage) creates the instance once and then calls #dispatch many times. So by making the initialization of our instance a bit slower, we can drastically improve the performance of the method call. We also still need to execute our block in the right context. And finally, each instance might have a different way to dispatch since it is defined dynamically at initialization. To work around all these issues, we create a new module on which we define a new method called dispatch and the body of this method is the passed block. Then we simply our instance using our new module.</p>
<p>Now every time we call #dispatch, a real method is dispatched which is much faster than doing an eval and no objects are allocated. Running the profiler and the benchmarks script used earlier, we can confirm that the GC doesn&rsquo;t run a single time and that the optimized code runs 2X faster!</p>
<p> </p>
<p>Once again, it&rsquo;s yet another example showing that you <a href="https://merbist.com/2010/07/29/object-allocation-why-you-should-care/">should care about object allocation</a> when dealing with code in the critical path. It also shows how to work around the block bindings. Now, it doesn&rsquo;t mean that you have to obsess about object allocation and performance, even if my last implementation is 2X faster than the previous, we are only talking about a few microseconds per dispatch. That said microseconds do add up and creating too many objects will slow down even your faster code since the GC will stop-the-world as its cleaning up your memory. In real life, you probably don&rsquo;t have to worry too much about low level details like that, unless you are working on a framework or sharing your code with others. But at least you can learn and understand why one approach is faster than the other, it might not be useful to you right away, but if you take programming as a craft, it&rsquo;s good to understand how things work under the hood so you can make educated decisions.
 </p>
<h3 id="update">Update:</h3>
<p>@apeiros in the comments suggested a solution that works &amp; performs the same as my solution, but is much cleaner:</p>
<pre><code>class SolutionTwo
  def initialize(origin, &amp;block;)
    @origin = origin
    define_singleton_method(:dispatch, block) if block_given?
  end
end
</code></pre>
]]></content>
		</item>
		
		<item>
			<title>deploying a rails 3 1 app gotchas</title>
			<link>https://matt.aimonetti.net/posts/2011-08-deploying-a-rails-3-1-app-gotchas/</link>
			<pubDate>Tue, 30 Aug 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-08-deploying-a-rails-3-1-app-gotchas/</guid>
			<description>Recently I had to build a new app as part of my research &amp;amp; development job at LivingSocial. My goal was to get the app up and running in just a few weeks, solid application architecture and graphic design included. When you need to build an app quickly and you want it to have some solid foundations, Rails is quite useful. I used Rails 3.1RCx so if we would to keep my app and push it to production, the engineering team wouldn&amp;rsquo;t have to update it and the transition should be seamless.</description>
			<content type="html"><![CDATA[<p>Recently I had to build a new app as part of my research &amp; development job at <a href="https://livingsocial.com">LivingSocial</a>. My goal was to get the app up and running in just a few weeks, solid application architecture and graphic design included.
When you need to build an app quickly and you want it to have some solid foundations, Rails is quite useful.
I used Rails 3.1RCx so if we would to keep my app and push it to production, the engineering team wouldn&rsquo;t have to update it and the transition should be seamless. I also quite like <a href="https://jashkenas.github.com/coffee-script/">CoffeeScript</a> and the app being quite heavy on JavaScript, the choice was easy. Furthermore, my coworker <a href="https://codefluency.com/">Bruce Williams</a> is a fan of <a href="https://sass-lang.com/">SCSS</a> and he&rsquo;s writing a <a href="https://pragprog.com/">PragProg</a> book called &ldquo;The Rails View&rdquo; with other LivingSocialist: <a href="https://www.boboroshi.com/">John Athayde</a>. So you got the point, I&rsquo;m using Rails3.1, but this post is about the challenges I faced when it was time to deploy and the solutions I found.</p>
<p>I&rsquo;ll skip the intro to Rails 3.1 and how to use the new asset pipeline, refer to the <a href="https://guides.rubyonrails.org/asset_pipeline.html">Rails guide</a> or one of the mainly posts referenced in t<a href="https://jasonrudolph.com/blog/2011/06/06/helpful-resources-for-upgrading-to-rails-3-1/">his post</a> (if I had properly read the <a href="https://guides.rubyonrails.org/asset_pipeline.html">guide</a>, it would have saved me some valuable time, trust me, read it carefuly).</p>
<p>At that point last night, I had my app working great locally, Bruce created some awesome scss code using mixins and nested rules, the HTML was clean and working great, my <a href="https://jashkenas.github.com/coffee-script/">CoffeeScript</a> was brewing nicely, all was great until I tried to deploy to our QA environment.</p>
<h3 id="javascript-runtime-dependency">JavaScript runtime dependency</h3>
<p>The first thing you will notice is that you need the proper JavaScript runtime so the asset pipeline works properly. Not a big deal, you&rsquo;ll find a lot of documentation about that. The problem is that you need to update your production environment or use depend on gem that will compile the required runtime (sounds dirty to me). So if you are deploying to many machines and you are using an image solution (EC2 AMI or other), you will need to update your image or spin new instances via updated chef/puppet recipes. In this case, the awesome team at LivingSocial had an image ready for me, so that wasn&rsquo;t a big deal, but still, you need to take that in consideration as you are planning to update.</p>
<p>So the asset pipeline optimizes your asset management by processing/compiling asset files for you and optimizing their delivery. Instead of serving static files directly via public/images or public/javascripts you know serve them via the asset pipeline which will take care of compiling your CoffeeScript, grouping and minifying your JS and preprocessing all sorts of format. It also optimizes the caching process by giving a unique filename to each file based on the file metadata and gziping files. This is great, but you really, really, really don&rsquo;t want to have your apps take care of that in production. Why wasting precious resources to serve assets when they can be prepared ahead of time. (by making Rails serve static assets, you are seriously reducing the throughput of  your app, please think of the children (or the dolphins/trees if you don&rsquo;t like children))</p>
<h3 id="capistrano">Capistrano</h3>
<p>Rails obviously has a preprocessor available as a rake task and you should update your deployment recipe to use that new feature. Here is my Capistrano code:</p>
<pre><code>after 'deploy:update_code', 'deploy:compile_assets'
namespace :deploy do
  task :compile_assets do
    run &quot;cd #{release_path}; RAILS_ENV=production rake assets:precompile&quot;
  end
end
</code></pre>
<p>Well, my real code doesn&rsquo;t hardcode the RAILS_ENV constant value, it&rsquo;s in fact set in each env file, but I simplified it since most people only use 1 env outside of dev &amp; test.</p>
<p>What that will do is compile all the files and dump them in public/assets/. But the file I had called bubble.png now becomes bubble-27543c671a3ab45141ee0d3216085009.png which means that my app is totally broken because images use in Bruce SCSS don&rsquo;t load, my js files don&rsquo;t load and the app is totally broken. Now this is least fun part, that I wish I had known before. This is where you go back and change your code so it uses magic to get the right file names.</p>
<h3 id="images">Images</h3>
<p>Fixing images was actually quite simple, in all my views, I just had to make sure I was using the image_tag helper everywhere.</p>
<h3 id="css">CSS</h3>
<p>SCSS files were a bit more tricky, I had to use the new scss preprocessor helpers you will find in the <a href="https://guides.rubyonrails.org/asset_pipeline.html">Rails guide</a> (image_path and image_url). I first looked into using erb, but turned out it wasn&rsquo;t needed and the end result is much cleaner.</p>
<h3 id="javascriptcoffeescript">Javascript/CoffeeScript</h3>
<p>For the CoffeeScript files, I was referring to image assets in the code and of course all the links were broken. So I had to use ERB in my coffee which looked funky but it worked.</p>
<p>But to get that to work, you need to rename your coffee script and append erb at the end. For instance my feature.js.coffee script had to be renamed feature.js.coffee.erb. That made me cry a little inside, but oh well, at least its not a XML config file. Maybe soon we will start seeing code in filenames or filenames called my_feature.js.compressed.minified.coffee.erb.from_rails.mattetti.org
Also, be careful about the order of the file extensions, otherwise it won&rsquo;t work. I thought I was done, ready to deploy my apps and this time the assets will show up properly. Turns out I was wrong :(</p>
<h3 id="rails-asset-precompilation-env-specificconfiguration">Rails asset precompilation env specific configuration.</h3>
<p>My css looked good, the precompiling task had run fine but I was missing some js files. I scratched my head as I could only see some of my js files. I then realized that all my JS files were there but some of my CoffeeScript files were missing. The answer was given to me by Bruce who asked me if I had updated my &ldquo;config.assets.precompile&rdquo; setting. Sometimes I feel that Rails is trying to compete with Struts and here I was really surprised that by default Rails, in production mode only precompiles all static JS and application.js files, but none of the other dynamic js files. Now it does precompile all the scss files, but for a reason I just don&rsquo;t understand, it&rsquo;s not the case for the JS files. So, you have to go edit production.rb in the config/environments folder and add the other js files you would like Rails to precompile for you.</p>
<p>After making all these changes, I was able to redeploy my app and everything was working again. (you might want to tweak your apache/nginx config as explained in the <a href="https://guides.rubyonrails.org/asset_pipeline.html">Rails guide</a>)</p>
<p> </p>
<h3 id="conclusion">Conclusion</h3>
<p>Don&rsquo;t be fooled like me and expect that because you have an app running locally, deployment will work right away. Make sure to read about the new features and what&rsquo;s needed. Overall, I think that the asset pipeline is a nice addon to Rails and if you don&rsquo;t feel like using it, just can put/leave all your files in the public folder and everything will work just like before. I do have to say that I was surprised to see that even in a brand new Rails 3.1 project, Rails isn&rsquo;t running in threaded mode by default. But that&rsquo;s a different (old) story and I guess people still get more excited about asset management than framework raw performance ;)</p>
<p> </p>
<p> </p>
<p> </p>
]]></content>
		</item>
		
		<item>
			<title>first step in scaling a web site http caching</title>
			<link>https://matt.aimonetti.net/posts/2011-07-first-step-in-scaling-a-web-site-http-caching/</link>
			<pubDate>Mon, 11 Jul 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-07-first-step-in-scaling-a-web-site-http-caching/</guid>
			<description>Today my friend Patrick Crowley and I were talking about scaling his website: https://cinematreasures.org since an article covering his work will soon be published in a very popular newspaper. Patrick&amp;rsquo;s site is hosted on Heroku which comes by default with Varnish caching enabled.
The challenge is that a lot of people using the Rails framework are used to doing page caching instead of relying on HTTP caching, even though this feature was added a long time ago.</description>
			<content type="html"><![CDATA[<p>Today my friend <a href="https://twitter.com/mokolabs">Patrick Crowley</a> and I were talking about scaling his website: <a href="https://cinematreasures.org/">https://cinematreasures.org</a> since an article covering his work will soon be published in a very popular newspaper. Patrick&rsquo;s site is hosted on <a href="https://www.heroku.com/">Heroku</a> which comes by default with <a href="https://www.varnish-cache.org/">Varnish caching</a> enabled.</p>
<p>The challenge is that a lot of people using the Rails framework are used to doing page caching instead of relying on HTTP caching, even though this feature was added a long time ago. The major problem with page caching is that it doesn&rsquo;t scale that well as soon as you run more than one server. Indeed you would need to store the page content to a shared drive between your servers or use memcached and do some work to avoid hitting your app every single time. On the other hand, HTTP caching is extremely easy to handle at the application level and it will dramatically reduce the amount of requests hitting your app. Let me explain a little more about HTTP caching.</p>
<p>Ryan Tomako wrote an <a href="https://tomayko.com/writings/things-caches-do">excellent post</a> about the details of caching, I strongly recommend you <a href="https://tomayko.com/writings/things-caches-do">read it</a>. In a nutshell, the HTTP caching layer (usually) seats before your application layer and allows you, the developer to store some responses that can be send back to the users based on optional conditions. That might still seem vague, let&rsquo;s take a concrete example. If you look at <a href="https://cinematreasures.org">https://cinematreasures.org</a>&rsquo;s home page you can see that it&rsquo;s an agglomerate of various information:</p>
<p><a href="https://cinematreasures.org"><img src="https://img.skitch.com/20110709-dnxjhikxr14tdr7e35n97madhn.jpg" alt="CinemaTreasures homepage"></a></p>
<p>And the bottom of the page contains even more dynamic data such as the popular movie theater photos, latest movie theater videos and latest tweets. One might look at that and say that this page can&rsquo;t really be cached and that the caching should be done at the model layer (i.e. cache the data coming from the database). I would certainly agree that caching the data layer is probably a good idea, but you shouldn&rsquo;t start by that. In fact without caching, this page renders fast enough. The problem is when someone like <a href="https://rogerebert.suntimes.com/">Roger Ebert</a> tweets about <a href="https://twitter.com/#!/ebertchicago/status/85912164648497152">CinemaTreasures</a> the load on the app peaks significantly. At the point, the amount of concurrent connections your app can handle gets put to the challenge. Even though your page load is &ldquo;fast enough&rdquo;, requests will queue up and some will eventually time out. That&rsquo;s actually a perfect case of HTTP caching.</p>
<p>What we want to do in that case is to cache a version of the home page in Varnish for 60 seconds. During that time, all requests coming to the site, will be served by Varnish and will all get the same cached content. That allows our servers to handle the non cached requests and therefore increase our throughput. What&rsquo;s even better, is that if a user refreshes the home page in his/her browser during the first 60 seconds the requests won&rsquo;t even make it all the way to our servers. All of that thanks to conditions set on the response. The first user hitting the HTTP cache layer (Varnish in this case) won&rsquo;t find a fresh cached response, so varnish will forward the request to our application layer which will send back the homepage to varnish and tell Varnish that this content is good for a full minute so please don&rsquo;t ask for it again until a minute from now. Varnish serves this response to the users' browser and let the browser know that the server said that the response was good enough for a minute so don&rsquo;t bother asking for it again. But now, if during these 60 seconds another user comes in, he will hit Varnish and Varnish will have the cached response from the first user and because the cache is still fresh (it&rsquo;s not been 60 seconds since the first request) and the cache is public, then the same response will be sent to the second user.</p>
<p>As you can see, the real strength of HTTP caching is the fact that it&rsquo;s a conditional caching. It&rsquo;s based on the request&rsquo;s URL and some &ldquo;flags&rdquo; set in the request/response headers.</p>
<p>Setting these conditions in your app is actually very simple since you just need to set the response&rsquo;s headers. If you are using a Ruby framework you will more than likely have access to the request object via the &ldquo;request&rdquo; method and you can set the headers directly like that: &ldquo;response.headers[&lsquo;Cache-Control&rsquo;] = &lsquo;public, max-age=60&rsquo;&rdquo;.
In Rails, you can actually use a helper method instead: expires_in 1.minute, :public =&gt; true.</p>
<p>You might have a case where you HAVE TO serve fresh content if available and can&rsquo;t serve stale cached content even for a few seconds. In this case, you can rely on the Etag header value. The Etag is meant to validate the freshness of a cached response. Think of it as a signature (unique ID) that is set on the response and used by the client (or cache layer) to see if the server response has changed or not. The way it works is that the client keeps track of the Etag received for each request (attached to the cached response) and then sends it with the next requests. The HTTP layer or application sees the Etag in the request and can check if it is still valid and the content didn&rsquo;t change. If that&rsquo;s the case, an empty response can be sent with a special HTTP status code (304) to let know the client that the old cached value is still good to be used.  Rails has a helper called &ldquo;stale?&rdquo; that helps you do the Etag/last modified check and allows you to not fetch all the objects from the database by doing a cheap check on an attribute (For instance you can check the updated_at value and use that as a condition to pull an object and its relationships).</p>
<p>So I explain HTTP caching, I often hear people telling me: &ldquo;that&rsquo;s great Matt, but you know what, that won&rsquo;t work for us because we have custom content that we display specifically to our users&rdquo;. So in that case, you can always set the Cache-Control header to private which will only cache the response in the client&rsquo;s browser and not the cache layer. That&rsquo;s good to some extent, but it can definitely be improved by rethinking a bit your view layer. In most web apps, the page content is rendered by server side code (Rails, Django, node.js, PHP..) and sent to the user all prepared for him. There are a few challenges with this approach, the biggest one is that the server has to wait until everything is ready (all data fetched, view rendered etc&hellip;) before sending back a response and before the client&rsquo;s browser can start rendering (there are ways to chunk the response but that&rsquo;s besides the scope of this post). The other is that the same expensive content has to be calculated/rendered for two different users because you might be inserting the username of the current user at the top of the page for instance. A classic way to deal with that is often to use fragment caching, where the expensive rendering is cached and reused by different requests. That&rsquo;s good but if the only reason to do that is because we are displaying some user specific data, there is a simpler way: async page rendering. The concept is extremely simple: remove all user specific content from the rendered page and then inject the user content in a second step once the page is displayed. The advantage is that now the full page can be cached in Varnish (or Squid or whatever you use for HTTP caching). To inject the user content, the easiest way is to use JavaScript.</p>
<p>Let&rsquo;s stay on CinemaTreasures, when you&rsquo;re logged in, the username is shown on the top of each page:</p>
<p>[caption id=&quot;&quot; align=&ldquo;aligncenter&rdquo; width=&ldquo;574&rdquo; caption=&ldquo;Once logged in, the username is displayed on all pages&rdquo;]<img src="https://img.skitch.com/20110710-mh5tqxuw1txf9kppn1smkkarrs.jpg" alt="">[/caption]</p>
<p>The only things that differs from the page rendered when the user is not logged in and when he is, are these 2 links and an avatar. So let&rsquo;s write some code to inject that after rendering the page.</p>
<p>In Rails, in the sessions controller or whatever code logs you in, you need to create a new cookie containing the username:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby">cookies<span style="color:#f92672">[</span><span style="color:#e6db74">:username</span><span style="color:#f92672">]</span> <span style="color:#f92672">=</span> {
         <span style="color:#e6db74">:value</span> <span style="color:#f92672">=&gt;</span> session<span style="color:#f92672">[</span><span style="color:#e6db74">:username</span><span style="color:#f92672">]</span>,
         <span style="color:#e6db74">:expires</span> <span style="color:#f92672">=&gt;</span> <span style="color:#ae81ff">2</span><span style="color:#f92672">.</span>days<span style="color:#f92672">.</span>from_now,
         <span style="color:#e6db74">:domain</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;.cinematreasures.org&#34;</span>
       }
</code></pre></div><p>As you can see, we don&rsquo;t store the data in the session cookie and the data won&rsquo;t be encrypted. You need to be careful that someone changing his cookie value can&rsquo;t access data he/should shouldn&rsquo;t. But that&rsquo;s a different discussion. Now that the cookie is set, we can read it from JavaScript when the page is loaded.</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-javascript" data-lang="javascript">document.<span style="color:#a6e22e">observe</span>(<span style="color:#e6db74">&#34;dom:loaded&#34;</span>, <span style="color:#66d9ef">function</span>() {
  <span style="color:#a6e22e">displayLoggedinUserLinks</span>();
});

<span style="color:#66d9ef">function</span> <span style="color:#a6e22e">readCookie</span>(<span style="color:#a6e22e">name</span>) {
     <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">nameEQ</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">name</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;=&#34;</span>;
     <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">ca</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">cookie</span>.<span style="color:#a6e22e">split</span>(<span style="color:#e6db74">&#39;;&#39;</span>);
     <span style="color:#66d9ef">for</span>(<span style="color:#66d9ef">var</span> <span style="color:#a6e22e">i</span><span style="color:#f92672">=</span><span style="color:#ae81ff">0</span>;<span style="color:#a6e22e">i</span> <span style="color:#f92672">&lt;</span> <span style="color:#a6e22e">ca</span>.<span style="color:#a6e22e">length</span>;<span style="color:#a6e22e">i</span><span style="color:#f92672">++</span>) {
          <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">c</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">ca</span>[<span style="color:#a6e22e">i</span>];
          <span style="color:#66d9ef">while</span> (<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">charAt</span>(<span style="color:#ae81ff">0</span>)<span style="color:#f92672">==</span><span style="color:#e6db74">&#39; &#39;</span>) <span style="color:#a6e22e">c</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">substring</span>(<span style="color:#ae81ff">1</span>,<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">length</span>);
          <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">indexOf</span>(<span style="color:#a6e22e">nameEQ</span>) <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>) <span style="color:#66d9ef">return</span> <span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">substring</span>(<span style="color:#a6e22e">nameEQ</span>.<span style="color:#a6e22e">length</span>,<span style="color:#a6e22e">c</span>.<span style="color:#a6e22e">length</span>);
     }
     <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">null</span>;
}

<span style="color:#66d9ef">function</span> <span style="color:#a6e22e">displayLoggedinUserLinks</span>() {
  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">username</span>            <span style="color:#f92672">=</span> <span style="color:#a6e22e">readCookie</span>(<span style="color:#e6db74">&#39;username&#39;</span>);
  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">loginLink</span>           <span style="color:#f92672">=</span> <span style="color:#a6e22e">$</span>(<span style="color:#e6db74">&#39;login&#39;</span>);
  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">logout</span>              <span style="color:#f92672">=</span> <span style="color:#a6e22e">$</span>(<span style="color:#e6db74">&#39;logout&#39;</span>);
  <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">username</span> <span style="color:#f92672">==</span> <span style="color:#66d9ef">null</span>){
    <span style="color:#a6e22e">loginLink</span>.<span style="color:#a6e22e">show</span>();
    <span style="color:#a6e22e">logout</span>.<span style="color:#a6e22e">hide</span>();
  }<span style="color:#66d9ef">else</span>{
    <span style="color:#75715e">// user is logged in and we have his/her username
</span><span style="color:#75715e"></span>    <span style="color:#a6e22e">loginLink</span>.<span style="color:#a6e22e">hide</span>();
    <span style="color:#66d9ef">if</span>(<span style="color:#a6e22e">userGreetings</span>){ <span style="color:#a6e22e">userGreetings</span>.<span style="color:#a6e22e">update</span>(<span style="color:#e6db74">&#34;&lt;span id=&#34;</span><span style="color:#a6e22e">username</span><span style="color:#e6db74">&#34;&gt;username&lt;/span&gt;&#34;</span>); }
    <span style="color:#a6e22e">logout</span>.<span style="color:#a6e22e">show</span>();
    <span style="color:#a6e22e">showAvatar</span>(<span style="color:#a6e22e">username</span>);
  };
  <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">true</span>;
}
</code></pre></div><p>The code above doesn&rsquo;t do much, once the DOM is loaded, the displayLoggedinUserLinks() function gets trigger. This function reads the cookie via the readCookie() function and if a username is found, the login link is hidden, the user name is displayed, as well as the logout link and the avatar. (You can also use a jQuery cookie plugin to handle the cookie, but this is an old example using Prototype, replace the code accordingly)
When the user logs out, we just need to delete the username cookie and the cached page will be rendered properly. In Rails, you would do delete the cookie like that: cookies.delete(&lsquo;username&rsquo;).
Quite often you might even want to make an Ajax call to get some information such as the number of user messages or notifications. Using jQuery or whatever JS framework you fancy you can do that once the page is rendered. Here is an example, on this page, you can see the learderboards for MLB The Show. The leaderboards don&rsquo;t change that often, especially the overall leaderboards so they can be cached for a little while, however the player&rsquo;s presence can change anytime. The smart way to deal with that, would be to cache the  leaderboards for a few seconds/minutes and make an ajax call to a presence service passing it a list of user ids collected from the DOM. The service called via Ajax could also be cached  depending on the requirements.</p>
<p>Now there is one more problem that people using might encouter: flash notices. For those of you not familiar with Rails, flash notices are messages set in the controller and passed to the view via the session (at least last time I checked). The problem happens if I&rsquo;m the home page isn&rsquo;t cached anymore and I logged in which redirects me to the home page with a flash message like so:</p>
<p><img src="https://img.skitch.com/20110710-1u6dn8rrc6r62rsg6niphhd2pi.jpg" alt=""></p>
<p>The problem is that the message is part of the rendered page and now for 60 seconds, all people hitting the home page will get the same message. This is why you would want to write a helper that would put this message in a custom cookie that you&rsquo;d pull JS and then delete once displayed. You could use a helper like that to set the cookie:</p>
<div class="highlight"><pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-ruby" data-lang="ruby"><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">flash_notice_cookie</span>(msg, expiration<span style="color:#f92672">=</span><span style="color:#66d9ef">nil</span>)
  cookies<span style="color:#f92672">[</span><span style="color:#e6db74">:flash_notice</span><span style="color:#f92672">]</span> <span style="color:#f92672">=</span> {
    <span style="color:#e6db74">:value</span> <span style="color:#f92672">=&gt;</span> msg,
    <span style="color:#e6db74">:expires</span> <span style="color:#f92672">=&gt;</span> expiration <span style="color:#f92672">||</span> <span style="color:#ae81ff">1</span><span style="color:#f92672">.</span>minutes<span style="color:#f92672">.</span>from_now,
    <span style="color:#e6db74">:domain</span> <span style="color:#f92672">=&gt;</span> <span style="color:#e6db74">&#34;.cinematreasures.com&#34;</span>
   }
<span style="color:#66d9ef">end</span>
</code></pre></div><p>And then add a function called when the DOM is ready which loads the message and injects it in the DOM. Once the cookie read, delete it so the message isn&rsquo;t displayed again.</p>
<p> </p>
<p>So there you have it, if you follow these few steps, you should be able to handle easily 10x more traffic without increasing hardware or making any type of crazy code change. Before you start looking into memcached, redis, cdns or whatever, consider HTTP caching and async DOM manipulation. Finally, note that if you can&rsquo;t use Varnish or Squid, you can very easily setup <a href="https://rtomayko.github.com/rack-cache/">Rack-Cache</a> locally and share the cache via memcached. It&rsquo;s also a great way to test locally.</p>
<hr>
<p><strong>Update:</strong> CinemaTreasures was updated to use HTTP caching as described above. The hosting cost is now half of what it used to be and the throughput is actually higher which offers a better protection against peak traffic.</p>
<hr>
<p> </p>
<p>External resources:</p>
<ul>
<li>
<p><a href="https://tomayko.com/writings/things-caches-do">https://tomayko.com/writings/things-caches-do</a></p>
</li>
<li>
<p><a href="https://devcenter.heroku.com/articles/http-caching">HTTP Caching at Heroku</a></p>
</li>
<li>
<p><a href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html">W3 caching protocol </a></p>
</li>
<li>
<p><a href="https://rtomayko.github.com/rack-cache/">Rack-Cache middleware</a></p>
</li>
<li>
<p><a href="https://www.nolanevans.com/2011/03/optimizing-your-rails-site-with-http.html">Blog post covering HTTP Caching/Varnish/Rails</a></p>
</li>
<li>
<p><a href="https://plugins.jquery.com/project/Cookie">jQuery cookie plugin</a></p>
</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>golang reflection exampl</title>
			<link>https://matt.aimonetti.net/posts/2011-06-golang-reflection-exampl/</link>
			<pubDate>Mon, 27 Jun 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-06-golang-reflection-exampl/</guid>
			<description>Note: This was one of my first blog posts on Go and well, I won&amp;rsquo;t make any excuses, it&amp;rsquo;s pretty terrible. It&amp;rsquo;s a good example of what not to do, that is, trying to force the concepts of a different language (in this case Ruby) to Go. I almost never use reflection and the following code is the kind of code you should avoiding writing. I&amp;rsquo;m leaving this post up as a testimony of my past mistakes and so you hopefully others won&amp;rsquo;t make the same :)</description>
			<content type="html"><![CDATA[<p><strong>Note:</strong> This was one of my first blog posts on Go and well, I won&rsquo;t make
any excuses, it&rsquo;s pretty terrible. It&rsquo;s a good example of what not to
do, that is, trying to force the concepts of a different language (in this case Ruby)
to Go. I almost never use reflection and the following code is the kind
of code you should avoiding writing. I&rsquo;m leaving this post up as a
testimony of my past mistakes and so you hopefully others won&rsquo;t make the
same :)</p>
<p>The <a href="https://golang.org/">Go Programming language</a> is really cool language by Google. According to the sales pitch, it&rsquo;s a <strong><em>&ldquo;fast, statically typed, compiled language that feels like a dynamically typed, interpreted language&rdquo;</em></strong>. Well, if you are like me, you don&rsquo;t trust sales pitches because you know that people writing them don&rsquo;t care about you, they care about their product. However cynical you are, you still have to check the facts. So here is a quick demonstration showing how to use Go&rsquo;s reflection feature.</p>
<p>Installing Go is actually really straight forward on a Mac, and slightly harder on Linux, check <a href="https://golang.org/doc/install.html">this guide </a>to see how to build Go in a few minutes.</p>
<p>Once all setup, you might want to read the documentation to see how to code in Go. Go is actually a kind of nice version of C with a<a href="https://golang.org/doc/go_spec.html"> simplified syntax</a>, no header files, really fast compilation time, a garbage collector and a <a href="https://golang.org/doc/effective_go.html?#interfaces_and_types">simple way to approach object inheritance</a> without turning in the complicated mess C++ is. The language is designed around the concept of <a href="https://golang.org/doc/effective_go.html?h=goroutines#concurrency">goroutines, a very nice way to handle concurrency</a>. It also has some features that Rubyists, Pythonistas and Javascripters wouldn&rsquo;t want to live without such as closures and some they probably wish they had such as <a href="https://golang.org/doc/effective_go.html?#defer">defer</a>. But of the things we are used to with dynamic languages is the concept of reflection. In a nutshell, at runtime, your code can reflect on the type of a given object and let the developer act accordingly. Depending on your programming background that might be obvious or you might not see the value. To be honest, that&rsquo;s not the question here. What I&rsquo;m interested in showing you is how it works.</p>
<p>For the sake of this demo, let&rsquo;s pretend we want to have a &ldquo;Dish&rdquo; data model, each instance of the &ldquo;Dish&rdquo; type will have a few attributes, an id, a name, an origin and a custom query which really is a function that we store as an attribute. Here is how we would represent that model in Go:</p>
<pre><code>// Data Model
type Dish struct {
  Id  int
  Name string
  Origin string
  Query func()
}
</code></pre>
<p>This is more or less the equivalent of the following Ruby code:</p>
<pre><code>class Dish
  attr_accessor :id, :name, :origin, :query
end
</code></pre>
<p>Ruby works slightly differently in the sense that defining attribute accessors create getters and setter methods but doesn&rsquo;t technically create instance variables until they are used. Here is what I mean:</p>
<pre><code>shabushabu = Dish.new
shabushabu.instance_variables # =&gt; []
shabushabu.name = &quot;Shabu-Shabu&quot;
shabushabu.instance_variables # =&gt; [&quot;@name&quot;]
shabushabu.origin = &quot;Japan&quot;
shabushabu.instance_variables # =&gt; [&quot;@name&quot;, &quot;@origin&quot;]
</code></pre>
<p>Another way of checking on the accessors is to check the methods defined on the object:</p>
<pre><code>shabushabu.methods - Object.new.methods
=&gt; [&quot;name&quot;, &quot;name=&quot;, &quot;origin&quot;, &quot;origin=&quot;, &quot;id=&quot;, &quot;query&quot;, &quot;query=&quot;]
</code></pre>
<p>But anyway, this post isn&rsquo;t about Ruby, it&rsquo;s about Go and what we would like is to reflect on an object of &ldquo;Dish&rdquo; type and see its attributes. The good news is that the Go language ships with a <a href="https://golang.org/pkg/reflect/">package to do just that</a>. Here is the full implementation:</p>
<pre><code>package main

import(
  &quot;fmt&quot;
  &quot;reflect&quot;
)

func main(){
  // iterate through the attributes of a Data Model instance
  for name, mtype := range attributes(&amp;Dish;{}) {
    fmt.Printf(&quot;Name: %s, Type %s\n&quot;, name, mtype.Name())
  }
}

// Data Model
type Dish struct {
  Id  int
  Name string
  Origin string
  Query func()
}

// Example of how to use Go's reflection
// Print the attributes of a Data Model
func attributes(m interface{}) (map[string]reflect.Type) {
  typ := reflect.TypeOf(m)
  // if a pointer to a struct is passed, get the type of the dereferenced object
  if typ.Kind() == reflect.Ptr{
    typ = typ.Elem()
  }

  // create an attribute data structure as a map of types keyed by a string.
  attrs := make(map[string]reflect.Type)
  // Only structs are supported so return an empty result if the passed object
  // isn't a struct
  if typ.Kind() != reflect.Struct {
    fmt.Printf(&quot;%v type can't have attributes inspected\n&quot;, typ.Kind())
    return attrs
  }

  // loop through the struct's fields and set the map
  for i := 0; i &lt; typ.NumField(); i++ {
    p := typ.Field(i)
      if !p.Anonymous {
        attrs[p.Name] = p.Type
      }
     }

  return attrs
}
</code></pre>
<p>Unfortunately, my code highlighter doesn&rsquo;t support the Go syntax, but GitHub does, so here is a <a href="https://gist.github.com/1009629">pretty version</a>.</p>
<p>There are ways of running Go source code like Ruby or Python scripts but in this case, we&rsquo;ll use the compiler &amp; linker provided with Go. I named my source file &ldquo;example.go&rdquo;, and here is how I compiled, linked and run it:</p>
<pre><code>$ 6g example.go &amp;&amp; 6l example.6 &amp;&amp; ./6.out
Name: Origin, Type string
Name: Id, Type int
Name: Query, Type
Name: Name, Type string
</code></pre>
<p>As you can see each attribute is printed out with its name and type. The code might seem a bit odd if you never looked at Go before.
Here is a quick rundown of the code:</p>
<p>In our main function, we create a new instance of type Dish on which we call attributes on. The call returns a map on which we iterate through and print the attribute name (key) and type (value).
The attributes function is defined a bit below and and it takes any type of objects (empty interface) and returns a map, which is like a Hash or a Dictionary. The map has keys of String type and values of &ldquo;Type&rdquo; type. The &ldquo;Type&rdquo; type is defined in the reflect package. Inside the function, 23 then use the previously mentioned reflect package to check on the type and the name of each attribute and assign it to a map object. (note that I&rsquo;m explicitly returning the map, but I could have done it in a more implicit way)</p>
<p>So there you go, that&rsquo;s how you use reflection in Go. Pretty nifty and simple.</p>
<p> </p>
]]></content>
		</item>
		
		<item>
			<title>sayonara sony</title>
			<link>https://matt.aimonetti.net/posts/2011-06-sayonara-sony/</link>
			<pubDate>Fri, 10 Jun 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-06-sayonara-sony/</guid>
			<description>It&amp;rsquo;s now official, I have resigned from Sony Computer Entertainment America.

I was planning on posting this a bit later but since I was politely escorted out of the building by HR/security, I have more free time to let you know of my decision. Before you ask: No, my decision isn&amp;rsquo;t directly related to the recent PSN/Sony security breach events and no, I don&amp;rsquo;t have your credit card number. More seriously, my decision boils down to something much simpler &amp;amp; concrete: drive and passion.</description>
			<content type="html"><![CDATA[<p>It&rsquo;s now official, I have resigned from Sony Computer Entertainment America.</p>
<p><a href="https://merbist.com/wp-content/uploads/2011/06/playstation-logo.png"><img src="https://merbist.com/wp-content/uploads/2011/06/playstation-logo-150x150.png" alt=""></a></p>
<p>I was planning on posting this a bit later but since I was politely escorted out of the building by HR/security, I have more free time to let you know of my decision. Before you ask: No, my decision isn&rsquo;t directly related to the recent PSN/Sony security breach events and no, I don&rsquo;t have your credit card number. More seriously, my decision boils down to something much simpler &amp; concrete: drive and passion.</p>
<p>The concept of drive is very well explained <a href="https://www.youtube.com/watch?v=u6XAPnuFjJc">in this talk</a> by <a href="https://www.danpink.com/">Dan Pink</a> and illustrated by <a href="https://www.thersa.org/">RSA</a>:</p>
<p>As explained, it is proven that when doing cognitive tasks, there are 3 factors that lead to better performance &amp; personal satisfaction:</p>
<ul>
<li>
<p>Autonomy: engagement vs compliance</p>
</li>
<li>
<p>Mastery: get better at stuff</p>
</li>
<li>
<p>Purpose: be disruptive but make the world a better place</p>
</li>
</ul>
<p> </p>
<p>The challenge is that when you work for a big corporation, you rarely see these factors applied. The amount of red tape, management overhead, lack of recognition and accountability result in a low drive by most employees. I think it was the first time in my entire career that I was told by a <a href="https://nateware.com">manager</a> to care less about the quality and end result of our products.</p>
<p>The second important concept that I think is critical when looking at your career is passion. This topic is very well covered in <a href="https://chadfowler.com/">Chad Fowler</a>&rsquo;s book: <a href="https://pragprog.com/titles/cfcar2/the-passionate-programmer">The Passionate Programmer</a>.</p>
<p><a href="https://pragprog.com/titles/cfcar2/the-passionate-programmer"><img src="https://imagery.pragprog.com/products/137/cfcar2_xlargecover.jpg?1298589825" alt=""></a>Here is a quote from Chad&rsquo;s book:</p>
<blockquote>
<p>Fulfillment and happiness don’t (often) come by chance. They require thought, intention, action, and a willingness to change course when you’ve made mistakes. [&hellip;] It might be a technology or business domain that gets you excited. Or, on the other hand, it might be a specific technology or business domain that drags you down. Or a type of organization. Maybe you’re meant for small teams or big teams. Or rigid processes. Or agile processes. Whatever the mix, take some time to find yours. You can fake it for a while, but a lack of passion will catch up with you and your work.</p>
</blockquote>
<p> </p>
<p>It&rsquo;s hard to summarize Chad&rsquo;s book into just a few sentences, but what I got from his book is that if, for whatever reason, you lose your passion for your job, you should move on to another place where you can be passionate and excel. In my case, I&rsquo;m still very much passionate about video game development but I find my passion seriously affected by an unhealthy work environment, bad communication and a lack of desire to change things in concrete ways. As the saying goes, <a href="https://www.google.com/search?q=people+don't+leave+jobs">&ldquo;People don&rsquo;t leave jobs&hellip;&quot;</a></p>
<p> </p>
<h3 id="whats-next-for-me">What&rsquo;s next for me?</h3>
<p>If you are in the software industry you know that everybody is hiring and that there is a real shortage of talent out there. You probably also receive half a dozen emails per week from recruiters offering you &ldquo;the best job ever&rdquo; with an obscene salary. Well, I receive them too. But in this market, you and I can allow ourselves to be picky and to choose the right job for ourselves. By choosing the right job, we are going to be more passionate, more driven, more efficient and bring a lot more value to our employers, who, in return, will hopefully do everything they can to make sure we grow within the company with a strong desire to do even better. As I was considering what I would want to do if I were to leave Sony, I came up with a few ideas about a job:</p>
<ul>
<li>
<p>I don&rsquo;t want to live to work, but rather, work to live. (kind of an European cliché sentence)</p>
</li>
<li>
<p>It&rsquo;s not about the job title.</p>
</li>
<li>
<p>It&rsquo;s not about the pay check.</p>
</li>
<li>
<p>It&rsquo;s not about how glamourous an industry  is.</p>
</li>
<li>
<p>What matters is :</p>
<ul>
<li>
<p>the company culture.</p>
</li>
<li>
<p>the passion coming from the leaders.</p>
</li>
<li>
<p>the company&rsquo;s ambitions.</p>
</li>
<li>
<p>how the company rewards and respects its employees.</p>
</li>
<li>
<p>the autonomy/trust given to the employees.</p>
</li>
<li>
<p>the purpose of the company and its potential to disrupt a market/change the world.</p>
</li>
<li>
<p>personal growth within the company.</p>
</li>
</ul>
</li>
</ul>
<p> </p>
<p>Writing this list helped me realize that I was definitely not in the right place and helped me create a list of criteria to define what kind of job I should be doing instead. As I was thinking about all that, I was reminded of this quote:</p>
<blockquote>
<p>&ldquo;One should not pursue goals that are easily achieved. One must develop an instinct for what one can just barely achieve through one&rsquo;s greatest efforts.&rdquo; —Albert Einstein</p>
</blockquote>
<p>This is probably a personality trait, but I like/need to be at the edge of my confort zone. I need to learn new things, experience new challenges. I need to try to solve unsolved problems. So part of me needs a company with a rich culture, a great a vision and leadership, but another part also needs to be allowed to think creatively, to push the existing boundaries, to challenge myself and to try to achieve things through my greatest efforts.</p>
<p>The challenge is that over the last 5-7 years I have become a Ruby specialist. I have learned to understand and master the language, learning its pros/cons and what goes on &ldquo;under the hood&rdquo;. I have built small and huge solutions for various domain spaces on top of Ruby. I have shared my knowledge giving talks, books, blog posts. I have also spent a lot of time expanding my own computer science knowledge, looking into other programming languages, frameworks, designs. My job at Sony was interesting due to the fact that Ruby is used in a quite singular way with very specific problems and a lot of C/C++ interaction. So while it is true that I am a Ruby specialist, I don&rsquo;t like that label. I don&rsquo;t like it because it&rsquo;s very limiting. My goal is to solve problems and quite often Ruby is a great tool for that, but for some problems, it is not. So I need a job where my expertise is helpful but would not limit my desire to learn new approaches, languages and skills.</p>
<p>And this is why I will soon start working as a <em>Code Alchemist in the LivingSocial R&amp;D&rsquo;s lab</em>.</p>
<p><a href="https://merbist.com/2011/06/10/sayonara-sony/livingsocial-2/"><img src="https://merbist.com/wp-content/uploads/2011/06/livingsocial1.png" alt=""></a></p>
<p>That might be a shocker at first glance. Going from working on video games to working for a daily-deal startup? It doesn&rsquo;t seem like a very smart career move. To be honest, that was my first reaction. But LivingSocial&rsquo;s VP of engineering is <a href="https://twitter.com/#!/chadfowler">Chad Fowler</a> (the author of The Passionate Programmer, mentioned earlier) and its VP of R&amp;D is <a href="https://en.wikipedia.org/wiki/Richard_Kilmer_(programmer)">Rich Kilmer</a>, InfoEther&rsquo;s cofounder and recognized mad-scientist-coder. I&rsquo;ve known Chad and Rich for many years, meeting at tech conferences that they organized or were invited to give talks to, and even getting to hack on some projects with Rich. So when they approached me to join them at LivingSocial, I wanted to know more about their own motivations, why I would be a good fit and how the company/job would rate against my list of criteria. We had long and honest discussions and the result is that I am excited to soon be working with one of the best teams I know of. More concretely, I will be working with <a href="https://twitter.com/#!/rich_kilmer">Rich</a>, <a href="https://twitter.com/#!/wbruce">Bruce</a> and <a href="https://twitter.com/#!/go">Michael</a> in helping LivingSocial revolutionize the local market. LivingSocial is a fast growing and successful company with a strong focus on creating a great experience for both customers and merchants. The company&rsquo;s vision is well defined and the desire to change the world the way we know it is palpable. Most of the founders have a technical background, they value good engineering practices and have created a nice, positive company culture. Chad has some really awesome, passionate and talented engineers on his team (too many to mention), for whom I have a lot of respect and with whom I look forward to working with.  I also value the fact that LivingSocial trusts and values me enough to let me work remotely. This is very important for me because it shows that my new employer really wants to work with me, trusts me but also is willing to embrace the challenges of having a remote team if that&rsquo;s what&rsquo;s needed to create the &ldquo;right team&rdquo;. After looking more deeply at what I need and what LivingSocial is, I believe that I can assist LivingSocial in making a very positive change to the way small businesses around the world are run. And I am looking forward to this.</p>
<p> </p>
]]></content>
		</item>
		
		<item>
			<title>video game web framework design</title>
			<link>https://matt.aimonetti.net/posts/2011-04-video-game-web-framework-design/</link>
			<pubDate>Thu, 14 Apr 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-04-video-game-web-framework-design/</guid>
			<description>In this post I will do my best to explain why and how I reinvented the wheel and wrote a custom web framework for some of Sony&amp;rsquo;s AAA console titles. My goal is to reflect on my work by walking you through the design process and some of the implementation decisions. This is not about being right or being wrong, it&amp;rsquo;s about designing a technical solution to solve concrete business challenges.</description>
			<content type="html"><![CDATA[<p>In this post I will do my best to explain why and how I reinvented the wheel and wrote a custom web framework for some of Sony&rsquo;s <a href="https://www.gameproducer.net/2006/05/26/what-are-aaa-titles/">AAA console titles</a>. My goal is to reflect on my work by walking you through the design process and some of the implementation decisions. This is not about being right or being wrong, it&rsquo;s about designing a technical solution to solve concrete business challenges.</p>
<h2 id="problem-domain">Problem Domain</h2>
<p>The video game industry is quite special, to say the least. It shares a lot of similarities with the movie industry. The big difference is that  the movie industry hasn&rsquo;t evolved as quickly as the video game  industry has. But the concept is the same, someone comes up with a great  idea, finds a team/studio to develop the game and finds a publisher. The  development length and budget depends on the type of game, but for a AAA  console game, it usually takes a least a <a href="https://www.joystiq.com/2010/03/09/god-of-war-3-has-44-million-dollar-budget/">few million</a> and a minimum of a year of work once the project has received the green light. The creation of such a game involves various teams, designers, artists, animators, audio teams, developers, producers, QA, marketing, management/overhead etc.. Once the game gets released, players purchase the whole game for a one time fee and the studio moves  on to their next game. Of course things are not that simple, with the latest platforms, we now have the option to patch games, add <a href="https://en.wikipedia.org/wiki/Downloadable_content">DLC</a> etc.. But historically, a console game is considered done when it ships, exactly like a movie, and very little work is scheduled post release.</p>
<p>Concretely such an approach exposes a few challenges when trying to implement online features for a <a href="https://www.gameproducer.net/2006/05/26/what-are-aaa-titles/">AAA console title</a>:</p>
<ul>
<li>
<p>Communication with the game client network team</p>
</li>
<li>
<p>Scalability, performance</p>
</li>
<li>
<p>Insane deadlines, unstable design (constant change of requirements)</p>
</li>
<li>
<p>Can&rsquo;t afford to keep on working on the system once released (time delimited projects)</p>
</li>
</ul>
<p> </p>
<h2 id="communication">Communication</h2>
<p>As in most situations, communication is one of the biggest challenges. Communication is even harder in the video game industry since you have so many teams and experts involved. Each team speaks its own jargon, has its own expertise and its own deadlines. But all focus on the same goal: releasing the best game ever. The team I&rsquo;m part of has implementing online features as its goal. That&rsquo;s the way we bring business value to our titles. Concretely, that means that we provide the game client developers with a C++ SDK which connects to custom web APIs written in Ruby. The API implementations rely on various data stores (<a href="https://www.mysql.com/">MySQL</a>, <a href="https://redis.io/">Redis</a>, <a href="https://memcached.org/">Memcached</a>, memory) to store and retrieve all sorts of game data.</p>
<p>Nobody but our team should care about the implementation details, after all, the whole point of providing an API is to provide a simple interface so others can do their part of the job in the easiest way possible. This is exactly where communication becomes a problem. The design of these APIs should be the result of the work of two teams with two different domains of expertise and different concerns. One team focuses on client performance, memory optimization and making the online resources available to the game engine without affecting the game play. The other, focuses on server performance, latency, scalability, data storage and system contention under load. Both groups have to come together to find a compromise making each other&rsquo;s job doable. Unfortunately, things are not that simple and game designers (who are usually not technical people) have a hard time <em>not</em> changing their designs and requirements every other week (usually for good reasons) making API design challenging and creating tension between the teams.</p>
<p>From this perspective, the API is the most important deliverable for our team and it should communicate the design goal while being very explicit about how it works, why it works the way it does, and how to implement it client side. This is a very good place where we can improve communication by making sure that we focus on making clear, well designed, well documented, flexible APIs.</p>
<p> </p>
<h2 id="scalability-performance">Scalability, performance</h2>
<p>On the server side, the APIs need to perform and scale to handles tends of thousands of concurrent requests. Web developers often rely on aggressive <a href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html">HTTP caching</a> but in our case, the web client (our SDK) has a limited amount of memory available and 90% of the requests are user specific (can&rsquo;t use full page HTTP cache) and a lot of these are POST/DELETE requests (can&rsquo;t be cached). That means that, to scale, we have to focus on what most developers don&rsquo;t often have to worry too much about: all the small details which, put together with a high load, end up drastically affecting your performance.</p>
<p>While Ruby is a great language, a lot of the libraries and frameworks are not optimized for performance, at least not the type of performance needed for our use case. However, the good news is that this is easily fixable and many alternatives exist (lots of async, non-blocking drivers for i.e). When obsessed with performance, you quickly learn to properly load test, profile, and monitor your code to find the bottlenecks and the places where you should focus your attention. The big, unique challenge though, is that a console game will more than likely see its peak traffic in the first few weeks, not really giving the chance to the online team to iteratively handle the prod issues. The only solution is to do everything possible before going live to ensure that the system will perform as expected. Of course if we were to write the same services in a more performant language, we would need to spend less time optimizing. But we are gaining so much flexibility by using a higher level programming language that, in my mind, the trade off is totally worth it (plus you still need to spend a lot of time optimizing your code path, even if your code is written in a very fast language).</p>
<p> </p>
<h2 id="deadlines-requirement-changes">Deadlines, requirement changes</h2>
<p>That&rsquo;s just part of the way the industry works. Unless you work for <a href="https://blizzard.com">Blizzard</a> and you can afford to spend a crazy amount of time and money on the development of a title; you will have to deal with sliding deadlines, requirement changes, scope changes etc&hellip; The only way I know how to protect myself from such things is to plan for the worst. Being a non-idealistic (read pessimistic) person helps a lot. When you design your software, make sure your design is sound but flexible enough to handle any major change that you know could happen at any time. Pick your battles and make sure your assumptions are properly thought through, communicated and documented so others understand and accept them. In a nutshell, this is a problem we can&rsquo;t avoid, so you need to embrace it.</p>
<p> </p>
<h2 id="limited-reusability">Limited reusability</h2>
<p>This topic has a lot to do with the previous paragraph. Because scopes can change often and because the deadlines are often crazy, a lot of the time, engineers don&rsquo;t take the time to think about reusability. They slap some code together, pray to the <a href="https://en.wikipedia.org/wiki/Lords_of_Kobol">lords of Kobol</a> and hope that they won&rsquo;t have to look at their code ever again (I&rsquo;m guilty of having done that too). The result is a lot of throw away code. This is actually quite frequent and normal in our industry. But it doesn&rsquo;t mean that it the right thing to do! The assumption/myth is that each game is different and therefore two games can&rsquo;t be using the same tech solution. My take on that is that it&rsquo;s partly true. But some components are the same for 80% of the games I work on. So why not design them well and reuse the common parts? (A lot of games share the same engines, such as <a href="https://www.unrealengine.com/">Unreal</a> for example, and there is no reason why we can&rsquo;t build a core online engine extended for each title)</p>
<p> </p>
<h2 id="my-approach">My approach</h2>
<p>When I joined Sony, I had limited experience with the console video game industry and my experience was not even related to online gaming. So even though I had (strong) opinions (and was often quite (perhaps even too) vocal about them), I did my best to improve existing components and work with the existing system. During that time, the team shipped 4 AAA titles on the existing system. As we were going through the game cycles, I did my best to understand the problem domain, the reasons behind some of the design decisions and finally I looked at what could be done differently to improve our business value. After releasing a title with some serious technical difficulties, I spent some time analyzing and listing the problems we had and their root causes. I asked our senior director for a mission statement and we got the team together to define the desiderata/objectives of our base technology. Here is what we came up with:</p>
<ol>
<li>
<p>Stability</p>
</li>
<li>
<p>Performance / Scalability</p>
</li>
<li>
<p>Encapsulation / Modularity</p>
</li>
<li>
<p>Documentation</p>
</li>
<li>
<p>Conventions</p>
</li>
<li>
<p>Reusability / Maintainability</p>
</li>
</ol>
<p>These objectives are meant to help us objectively evaluate two options. The legacy solution was based on Rails, or more accurately: Rails was used in the legacy solution. Rails had been hacked in so many different ways that it was really hard to update anything without breaking random parts of the framework. The way to do basic things kept being changed, there was no consistent design, no entry points, no conventions and each new game would duplicate the source code of the previously released game and make the game specific changes. Patches were hard to back port and older titles were often not patched up. The performance was atrocious under load, mainly due to hacked-up Rails not performing well. (Rails was allocating so many objects per request that the GC was taking a huge amount of the request cycles, the default XML builder also created a ton load of objects etc&hellip;) This was your typical <a href="https://en.wikipedia.org/wiki/Broken_windows_theory">broken windows scenario</a>. Engineers were getting frustrated, motivation was fainting, bugs were piling up and nobody felt ownership over the tech.</p>
<p>Now, to be fair, it is important to explain that the legacy system was hacked up together due to lack of time, lack of resources and a lot of pressure to release something ASAP. So, while the end result sounds bad, the context is very important to note. This is quite common in software engineering and when you get there, the goal is not to point fingers but to identify the good and the bad parts of the original solution. You then use this info to decide what to do: fix the existing system or rewrite, porting the good parts.</p>
<p>Our report also came up with a plan. A plan to redesign our technology stack to match the desiderata previously mentioned. To put it simply, the plan was to write a new custom web framework focusing on stability, performance, modularity and documentation. Now, there are frameworks out there which already do that or value these principles. But none of them focus on web APIs and none of them are specific to game development. Finally, the other issue was that we had invested a lot of time on game specific code and we couldn&rsquo;t throw away all that work, so the new framework had to support a good chunk of legacy code but had to make it run much faster.</p>
<h2 id="design-choices">Design choices</h2>
<p><strong>Low conversion cost</strong></p>
<p>Using <a href="https://nodejs.org/">node.js</a> &amp; <a href="https://jashkenas.github.com/coffee-script/">coffee script</a>/<a href="https://www.scala-lang.org/">Scala</a>/<a href="https://weblocks.viridian-project.de/">whatever</a> <a href="https://code.google.com/p/v8cgi/">new</a> <a href="https://github.com/tenderlove/phuby">fancy tech</a> was not really an option. We have a bunch of games out there which are running on the old system and some of these games will have a sequel or a game close enough that we could reuse part of the work. We don&rsquo;t want to have to rewrite the existing code. I therefore made sure that we could reuse 90% of the business logic by adding an abstraction layer doing the heavy lifting at boot time and therefore not affecting the runtime performance. Simple conversion scripts were also written to import the core of the existing code over.</p>
<p><em>Lessons learned:</em> It is very tempting to just redo everything and start from scratch. However, the business logic implementation wasn&rsquo;t the main cause of our problems. Even though I wish we could have redesigned that piece of the puzzle, it didn&rsquo;t make sense from a business perspective. A lot of thought had to be put into how to obtain the expected performance level while keeping the optional model/controller/view combos. By having full control of the &ldquo;web engine&rdquo;, we managed to isolate things properly without breaking the old paradigms. We also got rid of a lot of assumptions allowing us to design new titles a bit differently while being backward compatible and have our code run dramatically faster.</p>
<p><strong>Web API centric</strong></p>
<p>This is probably the most important design element. If I had to summarize what our system does in just a few words, I would say: a game web API. Of course, it&rsquo;s much more than that. We have admin interfaces, producer dashboards, community websites, lobbies, p2p, BI reports, async processing jobs etc&hellip; But at the end of the day, the only one piece you can&rsquo;t remove is the game web API. So I really wanted the design to focus on that aspect. When a developer starts implementing a new online game feature, I want him/her to think about the API. But I also want this API to be extremely well documented so the developer working client-side understands the purpose of the API, how to use it, and what the expected response is right away. I also wanted to be able to automatically test our APIs at a very basic level so we could validate that there are discrepancies between what the client expects and what the server provides. To do that, I created a standalone API DSL with everything needed to describe your API but without any implementation details whatsoever. The API DSL lets the developer define a route (url), the HTTP verb expected, if the request should be authenticated or not, SSL or not, the param rules, default values and finally a response description (which was quite a controversial choice). All of these settings can be documented by the developer. This standalone DSL can then be consumed by different tools. For instance we have a tool extracting all the info into nicely formatted HTML doc for the game client developers. This tool doesn&rsquo;t need to load the framework to just render the documentation. We also use this description at boot time to compile the validation rules and routes, allowing for a much faster request dispatch. And we also use these API description to generate some low level data for the client. Finally, we used the service description DSL to help create mocked service responses allowing the client team to test service designs without having to wait for the implementation streamlining the process.</p>
<p><em>Lessons learned:</em> We had a lot of internal discussions about the need to define the response within the service description. Some argued that it&rsquo;s a duplication since we already had a view and we could parse that to get most of what we needed (which is what the old system was doing). We ended up going with the response description DSL for a few critical reasons: testing and implementation simplicity. <em>Testing:</em> we need to have an API expectation reference and to keep this reference sane so we can see if something is changed. If we were to magically parse the response, we couldn&rsquo;t test the view part of the code against a frame of reference. <em>Implementation simplicity</em>: magically parsing a view template is more tricky that it sounds, you would need to render the template with the right data to make it work properly. Furthermore, you can&rsquo;t document a response easily in the view, and if you do, you arguably break the separation of concern between the description and the implementation. Finally, generated documentation isn&rsquo;t enough and that&rsquo;s why we decided to write English documentation, some being close to the code and some being just good old documentation explaining things outside of the code context.</p>
<p><strong>Modularity</strong></p>
<p>In order to make our code reusable we had to isolate each component and limit the dependencies. We wrote a very simple extension layer allowing each extension to registers itself once detected. The extension interface exposes the path of the extension, its type, models, services, controllers, migrations, seed data, dependencies etc.. Each extension is contained in a folder. (The extension location doesn&rsquo;t matter much but as part of the framework boot sequence, we check a few default places.) The second step of the process is to check a manifest/config file that is specific to each title. The manifest file lists the extensions that should be activated for the title. The framework then activates the marked extensions and has access to libs, models, views, migrations, seed data and of course to load services (DSL mentioned earlier) etc&hellip;</p>
<p>Even though we designed the core extensions the best we could, there are cases where some titles will need to extend these extensions. To do that, we added a bunch of hooks that could be implemented on the title side if needed (Ruby makes that super easy and clean to do!). A good example of that is the login sequence or the player data.</p>
<p><em>Lessons learned:</em> The challenge with modularity is to keep things simple and highly performing yet flexible. A key element to manage that is to stay as consistent as possible. Don&rsquo;t implement hooks three different ways, try to keep method signatures consistent, keep it simple and organized.</p>
<p> </p>
<h2 id="conclusion">Conclusion</h2>
<p>It&rsquo;s a bit early to say if this rewrite is a success or not and there are still lots of optimizations and technology improvements we are looking forward to doing. Only time will give us enough retrospect to evaluate our work. But because we defined the business value (mission statement) and the technical objectives, it is safe to say that the new framework meets the expectations quite well. On an early benchmark we noted a 10X speed improvement and that&rsquo;s before drilling into the performance optimizations such as making all the calls non-blocking, using better connection pools, cache write through layer&hellip; However, there is still one thing that we will have to monitor: how much business value will this framework generate. And I guess that&rsquo;s where we failed to define an agreed upon evaluation grid. I presume that if our developers spend more time designing and implementing APIs and less time debugging that could be considered business value. If we spend less time maintaining or fighting with the game engine, that would also be a win. Finally, if the player experience is improved we will be able to definitely say that we made the right choice.</p>
<p>To conclude, I&rsquo;d like to highlight my main short coming: I failed to define metrics that would help us evaluate the real business value added to our products. What I consider a technical success might not be a business success. How do you, in your own domain, find ways to define clear and objective metrics?</p>
]]></content>
		</item>
		
		<item>
			<title>hey apple please be nice and share</title>
			<link>https://matt.aimonetti.net/posts/2011-03-hey-apple-please-be-nice-and-share/</link>
			<pubDate>Mon, 07 Mar 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-03-hey-apple-please-be-nice-and-share/</guid>
			<description>My name is Matt Aimonetti, and in my free time I work on Apple&amp;rsquo;s open source Ruby implementation named MacRuby. I&amp;rsquo;m also the author of O&amp;rsquo;Reilly&amp;rsquo;s MacRuby book. As you can imagine, I&amp;rsquo;m very thankful that Apple initiated the MacRuby project a few years ago and have been an avid supporter. MacRuby is awesome to develop OS X native applications using the Ruby language and even allows you to compile down your apps to machine code.</description>
			<content type="html"><![CDATA[<p>My name is Matt Aimonetti, and in my free time I work on Apple&rsquo;s open source <a href="https://www.ruby-lang.org">Ruby</a> implementation named <a href="https://macruby.org">MacRuby</a>. I&rsquo;m also the author of <a href="https://oreilly.com/catalog/0636920000723">O&rsquo;Reilly&rsquo;s MacRuby book</a>. As you can imagine, I&rsquo;m very thankful that Apple initiated the MacRuby project a few years ago and have been an avid supporter. MacRuby is awesome to develop OS X native applications using the Ruby language and even allows you to compile down your apps to machine code. It&rsquo;s a great alternative to Objective-C.</p>
<p><a href="https://www.apple.com/macosx/lion/"><img src="https://img.skitch.com/20111012-kyiy9nhx5n9h9wafucyh8p3knx.jpg" alt=""></a></p>
<p>MacRuby is so awesome that Apple is even <a href="https://twitter.com/GeorgeBellos/status/41595085179203584">using it in its upcoming OS</a>. The only problem is that Apple apparently decided to not share MacRuby with other OS X developers and put <a href="https://yfrog.com/h8hhlydj">MacRuby in the OS private frameworks</a>. While this doesn&rsquo;t affect the project itself, it does affect OS X developers like myself who can&rsquo;t link to <a href="https://www.apple.com/macosx/lion/">Lion</a>&rsquo;s private MacRuby framework and are forced to embed MacRuby with their applications.</p>
<p>That&rsquo;s why I have opened a <a href="https://bugreporter.apple.com/">ticket on Apple radar system</a> to ask that MacRuby be made a public framework.</p>
<p>If you also want Apple to make this change, <a href="https://bugreporter.apple.com/">please take a minute and let them know</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>concurrency in ruby explained</title>
			<link>https://matt.aimonetti.net/posts/2011-02-concurrency-in-ruby-explained/</link>
			<pubDate>Tue, 22 Feb 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-02-concurrency-in-ruby-explained/</guid>
			<description>Concurrency is certainly not a new problem but it&amp;rsquo;s getting more and more attention as machines start having more than 1 core, that web traffic increases drastically and that some new technologies show up saying that they are better because they handle concurrency better. If that helps, think of concurrency as multitasking. When people say that they want concurrency, they say that they want their code to do multiple different things at the same time.</description>
			<content type="html"><![CDATA[<p>Concurrency is certainly <a href="https://en.wikipedia.org/wiki/Petri_Net">not a new problem</a> but it&rsquo;s getting more and more attention as machines start having more than 1 core, that web traffic increases drastically and that some new technologies show up saying that they are better because they handle concurrency better.
If that helps, think of concurrency as multitasking. When people say that they want concurrency, they say that they want their code to do multiple different things at the same time. When you are on your computer, you don&rsquo;t expect to have to choose between browsing the web and listening to some music. You more than likely want to run both concurrently. It&rsquo;s the same thing with your code, if you are running a webserver, you probably don&rsquo;t want it to only process one request at a time.
The aim of this article is to explain as simply as possible the concept of concurrency in Ruby, the reason why it&rsquo;s a complicated topic and finally the different solutions to achieve concurrency.</p>
<p>First off, if you are not really familiar with concurrency, take a minute to <a href="https://en.wikipedia.org/wiki/Concurrency_%28computer_science%29">read the wikipedia article on the topic</a> which is a great recap on the subject. But now, you should have noticed that my above example was more about parallel programming than concurrency, but we&rsquo;ll come back to that in a minute.</p>
<blockquote>
<p><strong>The real question at the heart of the quest for concurrency is: &ldquo;how to increase code throughput&rdquo;.</strong></p>
</blockquote>
<p>We want our code to perform better, and we want it to do more in less time. Let&rsquo;s take two simple and concrete examples to illustrate concurrency. First, let&rsquo;s pretend you are writing a twitter client, you probably want to let the user scroll his/her tweets while the latest updates are  being fetched. In other words, you don&rsquo;t want to block the main loop and interrupt the user interaction while your code is waiting for a response from the Twitter API. To do that, a common solution is to use multiple <strong>threads</strong>. Threads are basically processes that run in the same memory context. We would be using one thread for the main event loop and another thread to process the remote API request. Both threads share the same memory context so once the Twitter API thread is done fetching the data it can update the display. Thankfully, this is usually transparently handled by asynchronous APIs (provided by the OS or the programming language std lib) which avoid blocking the main thread.</p>
<p>The second example is a webserver. Let&rsquo;s say you want to run a Rails application. Because you are awesome, you expect to see a lot of traffic. Probably more than 1 QPS (query/request per second). You benchmarked your application and you know that the average response time is approximately 100ms. Your Rails app can therefore handle 10QPS using a single process (you can do 10 queries at 100ms in a second).</p>
<p>But what happens if your application gets more than 10 requests per second? Well, it&rsquo;s simple, the requests will be backed up and will take longer until some start timing out. This is why you want to improve your concurrency. There are different ways to do that, a lot of people feel really strong about these different solutions but they often forget to explain why they dislike one solution or prefer one over the other. You might have heard people conclusions which are often one of these: <a href="https://canrailsscale.com/">Rails can&rsquo;t scale</a>, you only get concurrency with <a href="https://jruby.org/">JRuby</a>, <a href="https://adam.heroku.com/past/2009/8/13/threads_suck/">threads suck</a>, the only way to concurrency is via threads, we should switch to <a href="https://www.erlang.org/">Erlang</a>/<a href="https://nodejs.org/">Node.js</a>/<a href="https://www.scala-lang.org/">Scala</a>, use<a href="https://www.rubyinside.com/fibers-eventmachine-rack-performance-gains-3395.html"> fibers</a> and you will be fine, add more machines, <a href="https://tomayko.com/writings/unicorn-is-unix">forking &gt; threading</a>.  Depending on who said what and how often you heard it on twitter, conferences, blog posts, you might start believing what others are saying. But do you really understand why people are saying that and are you sure they are right?</p>
<p>The truth is that this is a complicated matter. The good news is that it&rsquo;s not <em>THAT</em> complicated!</p>
<p>The thing to keep in mind is that the concurrency models are often defined by the programming language you use. In the case of Java, <a href="https://download.oracle.com/javase/tutorial/essential/concurrency/index.html">threading is the usual solution</a>, if you want your Java app to be more concurrent, just run every single request in its own thread and you will be fine (kinda). In PHP, you simply don&rsquo;t have threads, instead you will start a new process per request. Both have pros and cons, the advantage of the Java threaded approach is that the memory is shared between the threads so you are saving in memory (and startup time), each thread can easily talk to each other via the shared memory. The advantage of PHP is that you don&rsquo;t have to worry about locks, deadlocks, threadsafe code and all that mess hidden behind threads. Described like that it looks pretty simple, but you might wonder why PHP doesn&rsquo;t have threads and why Java developers don&rsquo;t prefer starting multiple processes. The answer is probably related to the language design decisions. PHP is a language designed for the web and for short lived processes. PHP code should be fast to load and not use too much memory. Java code is slower to boot and to warm up, it usually uses quite a lot of memory. Finally, Java is a general purpose programming language not designed primarily for the internet. Others programming languages like <a href="https://www.erlang.org/">Erlang</a> and <a href="https://www.scala-lang.org/">Scala</a> use a third approach: <a href="https://en.wikipedia.org/wiki/Actor_model">the actor model</a>. The actor model is somewhat a bit of a mix of both solutions, the difference is that actors are a like threads which don&rsquo;t share the same memory context. Communication between actors is done via exchanged messages ensuring that each actor handles its own state and therefore avoiding corrupt data (two threads can modify the same data at the same time, but an actor can&rsquo;t receive two messages at the exact same time). We&rsquo;ll talk about that design pattern later on, so don&rsquo;t worry if you are confused.</p>
<p>What about Ruby? Should Ruby developers use threads, multiple processes, actors, something else? The answer is: <strong>yes</strong>!</p>
<h2 id="threads">Threads</h2>
<p>Since version 1.9, Ruby has native threads (before that <a href="https://en.wikipedia.org/wiki/Green_threads">green threads</a> were used). So in theory, if we would like to, we should be able to use threads everywhere like most Java developers do. Well, that&rsquo;s almost true, the problem is that Ruby, like Python uses a <a href="https://en.wikipedia.org/wiki/Global_Interpreter_Lock">Global Interpreter Lock</a> (aka GIL). This GIL is a locking mechanism that is meant to protect your data integrity. The GIL only allows data to be modified by one thread at time and therefore doesn&rsquo;t let threads corrupt data but also it doesn&rsquo;t allow them to truly run concurrently. That is why some people say that Ruby and Python are not capable of (true) concurrency.</p>
<p><img src="https://img.skitch.com/20110223-kk58iq5yjdpmyswf7nuya4c4kp.jpg" alt="Global Interpreter Lock by Matt Aimonetti"></p>
<p>However these people often don&rsquo;t mention that the GIL makes single threaded programs faster, that multi-threaded programs are much easier to develop since the data structures are safe and finally that a lot of C extensions are not thread safe and without the GIL, these C extensions don&rsquo;t behave properly. These arguments don&rsquo;t convince everyone and that&rsquo;s why you will hear some people say you should look at another Ruby implementation without a GIL, such as <a href="https://jruby.org/">JRuby</a>, <a href="https://rubini.us/">Rubinius</a> (hydra branch) or <a href="https://macruby.org">MacRuby</a> (Rubinius &amp; MacRuby also offer other concurrency approaches). If you are using an implementation without a GIL, then using threads in Ruby has exactly the same pros/cons than doing so in Java. However, it means that now you have to deal with the nightmare of threads: making sure your data is safe, doesn&rsquo;t deadlock, check that your code, your libs, plugins and gems are thread safe. Also, running too many threads might affect the performance because your OS doesn&rsquo;t have enough resources to allocate and it ends up spending its time context switching. It&rsquo;s up to you to see if it&rsquo;s worth it for your project.</p>
<h2 id="multiple-processes--forking">Multiple processes &amp; forking</h2>
<p>That&rsquo;s the most commonly used solution to gain concurrency when using Ruby and Python. Because the default language implementation isn&rsquo;t capable of true concurrency or because you want to avoid the challenges of thread programming, you might want to just start more processes. That&rsquo;s really easy as long as you don&rsquo;t want to share states between running processes. If you wanted to do so, you would need to use <a href="https://segment7.net/projects/ruby/drb/introduction.html">DRb</a>, a message bus like <a href="https://www.rabbitmq.com/">RabbitMQ</a>, or a shared data store like memcached or a DB. The caveat is that you now need to use a LOT more memory. If want to run 5 Rails processes and your app uses 100Mb you will now need 500Mb, ouch that&rsquo;s a lot of memory! That is exactly what happens when you use a Rails webserver like Mongrel. Now some other servers like <a href="https://www.modrails.com/">Passenger</a> and <a href="https://unicorn.bogomips.org/">Unicorn</a> found a workaround, they rely on <a href="https://en.wikipedia.org/wiki/Fork_%28operating_system%29">unix forking</a>. The advantage of forking in an unix environment implementing the copy-on-write semantics is that we create a new copy of the main process but they both &ldquo;share&rdquo; the same physical memory. However, each process can modify its own memory without affecting the other processes. So now, Passenger can load your 100Mb Rails app in a process, then fork this process 5 times and the total footprint will be just a bit more than 100Mb and you can now handle 5X more concurrent requests. Note that if you are allocating memory in your request processing code (read controller/view) your overall memory will grow but you can still run many more processes before running out of memory. This approach is appealing because really easy and pretty safe. If a forked process acts up or leaks memory, just destroy it and create a new fork from the master process. Note that this approach is also used in <a href="https://github.com/defunkt/resque">Resque</a>, the async job processing solution by <a href="https://github.com">GitHub</a>.</p>
<p>This solution works well if you want to duplicate a full process like a webserver, however it gets less interesting when you just want to execute some code &ldquo;in the background&rdquo;. Resque took this approach because by nature async jobs can yield weird results, leak memory or hang. Dealing with forks allows for an external control of the processes and the cost of the fork isn&rsquo;t a big deal since we are already in an async processing approach.</p>
<p><img src="https://s3.amazonaws.com/cogit8-org/img/hardcore-forking-action.png" alt=""></p>
<h2 id="actorsfibers">Actors/Fibers</h2>
<p>Earlier we talked a bit about the <a href="https://en.wikipedia.org/wiki/Actor_model">actor model</a>. Since Ruby 1.9, developers now have access to a new type of &ldquo;lightweight&rdquo; threads called <a href="https://www.ruby-doc.org/core-1.9/classes/Fiber.html">Fibers</a>. Fibers are not actors and Ruby doesn&rsquo;t have a native Actor model implementation but some people wrote <a href="https://doc.revactor.org/files/README.html">some actor libs</a> on top of fibers. A fiber is like a simplified thread which isn&rsquo;t scheduled by the VM but by the programmer. Fibers are like blocks which can be paused and resumed from the outside of from within themselves. Fibers are faster and use less memory than threads as demonstrated in <a href="https://oldmoe.blogspot.com/2008/08/ruby-fibers-vs-ruby-threads.html">this blog post</a>. However, because of the GIL, you still cannot truly run more than one concurrent fiber by thread and if you want to use multiple CPU cores, you will need to run fibers within more than one thread. So how do fibers help with concurrency? The answer is that they are part of a bigger solution. Fiber allow developers to manually control the scheduling of &ldquo;concurrent&rdquo; code but also to have the code within the fiber to auto schedule itself. That&rsquo;s pretty big because now you can wrap an incoming web request in its own fiber and tell it to send a response back when it&rsquo;s done doing its things. In the meantime, you can move on the to next incoming request. Whenever a request within a fiber is done, it will automatically resume itself and be returned. Sounds great right? Well, the only problem is that if you are doing any type of blocking IO in a fiber, the entire thread is blocked and the other fibers aren&rsquo;t running. Blocking operations are operations like database/memcached queries, http requests&hellip; basically things you are probably triggering from your controllers. The good news is that the &ldquo;only&rdquo; problem to fix now is to avoid blocking IOs. Let&rsquo;s see how to do that.</p>
<p><img src="https://img.skitch.com/20110223-8wkfs2g12p15ku18rm7aq9negf.jpg" alt="fiber"></p>
<h2 id="non-blocking-iosreactor-pattern">Non blocking IOs/Reactor pattern.</h2>
<p>The reactor pattern is quite simple to understand really. The heavy work of making blocking IO calls is delegated to an external service (reactor) which can receive concurrent requests. The service handler (reactor) is given callback methods to trigger asynchronously based on the type of response received. Let me take a limited analogy to hopefully explain the design better. It&rsquo;s a bit like if you were asking someone a hard question, the person will take a while to reply but his/her reply will make you decide if you raise a flag or not. You have two options, or you choose to wait for the response and decide to raise the flag based on the response, or your flag logic is already defined and you tell the person what to do based on their answer and move on without having to worry about waiting for the answer. The second approach is exactly what the reactor pattern is. It&rsquo;s obviously slightly more complicated but the key concept is that it allows your code to define methods/blocks to be called based on the response which will come later on.</p>
<p><img src="https://img.skitch.com/20110223-xkit6utnty1sdt84n15w7dgtnh.jpg" alt="Reactor from Matt Aimonetti&rsquo;s blog"></p>
<p>In the case of a single threaded webserver that&rsquo;s quite important. When a request comes in and your code makes a DB query, you are blocking any other requests from being processed. To avoid that, we could wrap our request in a fiber, trigger an async DB call and pause the fiber so another request can get processed as we are waiting for the DB. Once the DB query comes back, it wakes up the fiber it was trigger from, which then sends the response back to the client. Technically, the server can still only send one response at a time, but now fibers can run in parallel and don&rsquo;t block the main tread by doing blocking IOs (since it&rsquo;s done by the reactor).</p>
<p>This is the approach used by <a href="https://twistedmatrix.com/trac/">Twisted</a>, <a href="https://eventmachine.rubyforge.org/EventMachine/Deferrable.html">EventMachine</a> and <a href="https://nodejs.org/">Node.js</a>. Ruby developers can use EventMachine or an EventMachine based webserver like <a href="https://code.macournoyer.com/thin/">Thin</a> as well as <a href="https://github.com/igrigorik/em-synchrony">EM clients/drivers</a> to make non blocking async calls. Mix that with some Fiber love and you get Ruby concurrency. Be careful though, using Thin, non blocking drivers and Rails in threadsafe mode doesn&rsquo;t mean you are doing concurrent requests. Thin/EM only use one thread and you need to let it know that it&rsquo;s ok to handle the next request as we are waiting. This is done by <a href="https://eventmachine.rubyforge.org/EventMachine/Deferrable.html">deferring the response</a> and let the reactor know about it.</p>
<p>The obvious problem with this approach is that it forces you to change the way you write code. You now need to set a bunch of callbacks, understand the Fiber syntax, and use deferrable responses, I have to admit that this is kind of a pain. If you look at some Node.js code, you will see that it&rsquo;s not always an <a href="https://howtonode.org/control-flow-part-ii/file-write.js">elegant approach</a>. The good news tho, is that this process can be wrapped and your code can be written as it if was processed synchronously while being handled asynchronously under the covers. This is a bit more complex to explain without showing code, so this will be the topic of a future post. But I do believe that things will get much easier soon enough.</p>
<h2 id="conclusion">Conclusion</h2>
<p>High concurrency with Ruby is doable and done by many. However, it could made easier. Ruby 1.9 gave us fibers which allow for a more granular control over the concurrency scheduling, combined with non-blocking IO, high concurrency can be achieved. There is also the easy solution of forking a running process to multiply the processing power. However the real question behind this heated debate is what is the future of the Global Interpreter Lock in Ruby, should we remove it to improve concurrency at the cost of dealing with some new major threading issues, unsafe C extensions, etc..? Alternative Ruby implementers seem to believe so, but at the same time Rails still ships with a default mutex lock only allowing requests to be processed one at a time, the reason given being that a lot of people using Rails don&rsquo;t write thread safe code and a lot of plugins are not threadsafe. Is the future of concurrency something more like <a href="https://libdispatch.macosforge.org/">libdispatch</a>/<a href="https://www.macruby.org/documentation/gcd.html">GCD</a> where the threads are handled by the kernel and the developer only deals with a simpler/safer API?</p>
<p>Further reading:</p>
<ul>
<li>
<p><a href="https://www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby/">Concurrency is a myth in Ruby</a></p>
</li>
<li>
<p><a href="https://oldmoe.blogspot.com/2008/08/ruby-fibers-vs-ruby-threads.html">Ruby fibers vs Ruby threads</a></p>
</li>
<li>
<p><a href="https://www.igvita.com/2010/08/18/multi-core-threads-message-passing/">Multi-core, threads, passing messages</a></p>
</li>
<li>
<p><a href="https://adam.heroku.com/past/2009/8/13/threads_suck/">Threads suck</a></p>
</li>
<li>
<p><a href="https://www.igvita.com/2010/04/15/non-blocking-activerecord-rails/">Non blocking Active Record and Rails</a></p>
</li>
<li>
<p><a href="https://www.mikeperham.com/2010/01/27/scalable-ruby-processing-with-eventmachine/">Scalable Ruby processing with EventMachine</a></p>
</li>
<li>
<p><a href="https://on-ruby.blogspot.com/2008/01/ruby-concurrency-with-actors.html">Ruby concurrency with actors</a></p>
</li>
<li>
<p><a href="https://www.engineyard.com/blog/2010/concurrency-real-and-imagined-in-mri-threads/">Concurrency in MRI; threads</a></p>
</li>
<li>
<p><a href="https://www.infoq.com/news/2007/08/ruby-1-9-fibers">Ruby 1.9 adds fibers for lightweight concurrency</a></p>
</li>
<li>
<p><a href="https://yehudakatz.com/2010/08/14/threads-in-ruby-enough-already/">Threads in Ruby, enough already</a></p>
</li>
<li>
<p><a href="https://www.igvita.com/2010/03/22/untangling-evented-code-with-ruby-fibers">Untangling Evented Code with Ruby Fibers</a></p>
</li>
<li>
<p><a href="https://www.slideshare.net/ehuard/concurrency-5615029">Elise Huard&rsquo;s RubyConf Concurrency talk slides</a></p>
</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>bridgesupport build</title>
			<link>https://matt.aimonetti.net/posts/2011-02-bridgesupport-build/</link>
			<pubDate>Sat, 19 Feb 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-02-bridgesupport-build/</guid>
			<description>Today I was helping someone write an Objective-C framework around cocos2d.
C/Objective-C code can be called directly from MacRuby. However the Obj-C code you would like to use might be using some ANSI C symbols that are non-object-oriented items such as constants, enumerations, structures, and functions. To make these items available to our MacRuby code, you need to generate a BridgeSupport file as explained in this section of my book.</description>
			<content type="html"><![CDATA[<p>Today I was helping someone write an Objective-C framework around <a href="https://cocos2d.org/">cocos2d</a>.</p>
<p>C/Objective-C code can be called directly from MacRuby. However the Obj-C code you would like to use might be using some ANSI C symbols that are non-object-oriented items such as constants, enumerations, structures, and functions. To make these items available to our MacRuby code, you need to generate a <a href="https://ofps.oreilly.com/titles/9781449380373/ch03.html#_using_objective_c_or_c_code">BridgeSupport file as explained in this section of my book</a>.</p>
<p>In our case, we were working on the framework and I didn&rsquo;t feel like manually having to regenerate the BridgeSupport file every single time I would compile our code. So instead I added a new build phase in our target.</p>
<p>[caption id=&quot;&quot; align=&ldquo;aligncenter&rdquo; width=&ldquo;741&rdquo; caption=&ldquo;Adding a new step to our build&rdquo;]<img src="https://img.skitch.com/20110220-b685ag2cef8qm69uwn73e3equ4.png" alt="">](<a href="https://img.skitch.com/20110220-b685ag2cef8qm69uwn73e3equ4.png)%5B/caption%5D">https://img.skitch.com/20110220-b685ag2cef8qm69uwn73e3equ4.png)[/caption]</a></p>
<p>And I added the following script to run at the end of the build:</p>
<p>`</p>
<h1 id="this-step-generated-the-bridgesupport-file-for-the-framework">This step generated the bridgesupport file for the framework</h1>
<p>PATH=&quot;$PATH:/usr/local/bin&quot;
mkdir -p $TARGET_BUILD_DIR/$PROJECT_NAME.framework/Resources/BridgeSupport/
gen_bridge_metadata &ndash;64-bit -f $TARGET_BUILD_DIR/$PROJECT_NAME.framework/ -o $TARGET_BUILD_DIR/$PROJECT_NAME.framework/Resources/BridgeSupport/$PROJECT_NAME.bridgesupport
`</p>
<p>Th<code>e script just executes the steps required to add the BridgeSupport file to your framework. I can now rebuild my framework without having to worry about BridgeSupport.</code></p>
]]></content>
		</item>
		
		<item>
			<title>designing for scalability</title>
			<link>https://matt.aimonetti.net/posts/2011-01-designing-for-scalability/</link>
			<pubDate>Mon, 31 Jan 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-01-designing-for-scalability/</guid>
			<description>Designing beautiful and scalable software is hard. Really hard.
It&amp;rsquo;s hard for many reasons. But what makes it even harder is that software scalability is a relatively new challenge, something only really done in big companies, companies that are not really keen on sharing their knowledge. The amount of academic work done on software design is quite limited compared to other types of design, but shared knowledge about scalable design is almost nonexistent (Don&amp;rsquo;t expect to find detailed information about scaling online video games either, the industry is super secretive.</description>
			<content type="html"><![CDATA[<p>Designing beautiful and scalable software is hard. Really hard.</p>
<p>It&rsquo;s hard for many reasons. But what makes it even harder is that software scalability is a relatively new challenge, something only really done in big companies, companies that are not really keen on sharing their knowledge. The amount of academic work done on software design is quite limited compared to other types of design, but shared knowledge about scalable design is almost nonexistent <em>(Don&rsquo;t expect to find detailed information about scaling online video games either, the industry is super secretive. And even if this is a niche market where finding skilled/experienced developers is really challenging, information is not shared outside a game project).</em></p>
<p>I don&rsquo;t pretend to have the required knowledge to cover this topic at length. However, I do have some exposure and figured I should share what I learned so others can benefit from my experience and push the discussion further.</p>
<p>Designing scalable software is just like any other type of software design, with a few unique constraints. If I had to define the key requirements of a great design I would have to quote Frederick P. Brooks:</p>
<blockquote>
<p>&ldquo;Great designs have conceptual integrity - unity, economy, clarity&rdquo;</p>
</blockquote>
<p>This is true for any type of design and one should always start by that.
Don&rsquo;t just jump on your keyboard and start writing tests/code right away. Take a minute to think about your design.
That will save you hours of refactoring and headaches.</p>
<h2 id="youre-a-designer-and-might-not-even-know-it">You&rsquo;re a designer and might not even know it</h2>
<p>You might not be designing the next NASA engine but you are more than likely designing an API that you and others will use. As a matter of fact, unless you write code that will never be seen again, you are writing an Application Programming Interface (API). Every single class, method, function you write is an API that you and others will use. Remember that every time you write code, you are the implementer of a design, and therefore you are a designer.</p>
<p>[caption id=&ldquo;attachment_916&rdquo; align=&ldquo;alignright&rdquo; width=&ldquo;150&rdquo; caption=&ldquo;Giana and I, discussing design patterns&rdquo;]<a href="https://merbist.com/2011/01/31/designing-for-scalability/giana_and_moi_lowres/"><img src="https://merbist.com/wp-content/uploads/2011/01/giana_and_moi_lowres-150x150.jpg" alt="Giana and Matt Aimonetti"></a>[/caption]</p>
<p>When thinking about your design, focus on design concepts instead of implementation details. A design concept must be clear, simple to both explain with words and draw on a whiteboard. If you can&rsquo;t draw and explain your design on a whiteboard, you have failed one of the great design requirement: clarity. If you work alone, or your coworkers are tired of hearing you, try rubber ducking your design ideas. It&rsquo;s the same concept as rubber ducking debugging, where a programmer would force himself to explain his code, line-by-line, to a rubber duck on his desk but instead of talking about the code, explain your design and why it&rsquo;s awesome (I&rsquo;ve recently done this with my baby girl and it&rsquo;s been really helpful).</p>
<h2 id="keeping-the-design-integrity">Keeping the design integrity</h2>
<p>One of the challenges of designing scalable software is that your constraints are often very unique to your product. Off the shelf solutions don&rsquo;t work for you, and the specific solution used by another project can&rsquo;t be transposed to your project because the cause and the effect of what you need to scale are different. The problem is that you really quickly lose design integrity.</p>
<p>Let&rsquo;s take a look at a concrete example to see how the design integrity can be lost or even not defined at all.
Let&rsquo;s pretend we want to write a suite of web APIs for video games.</p>
<p>We can look at this task from different perspectives:<a href="https://merbist.com/2011/01/31/designing-for-scalability/the-shout-2/"><img src="https://merbist.com/wp-content/uploads/2011/01/the-shout1-150x150.jpg" alt="the shout posted by Matt Aimonetti"></a></p>
<ul>
<li>
<p>Video game deadlines are crazy, let&rsquo;s find a way to release as many APIs ASAP.</p>
</li>
<li>
<p>We&rsquo;re going to get a huge amount of traffic, let&rsquo;s make sure we don&rsquo;t crash and burn.</p>
</li>
<li>
<p>We need to make sure our APIs are simple to use for the dev teams integrating them.</p>
</li>
</ul>
<p>Each of these perspectives reflects a facet of the challenge. Other facets exist that I didn&rsquo;t mention but that a business person might have listed right away, one of which being: How can we do that for the least amount of money?</p>
<p>To design our API suite, we first need to understand the different perspectives. Gaining this understanding will help us design something better but it will also help us communicate better with the different stakeholders. Once we have a decent understanding of the constraints and expectations, someone needs to explicitly define the design values and their priorities. This is a crucial step in the design process. Systems nowadays are too complicated to be handled by only one person and keeping design integrity requires clear communication.</p>
<h2 id="design-goal-and-values">Design goal and values</h2>
<p>The best way to communicate the design is to write a simple sentence defining the primary goal:
&ldquo;Build a robust, efficient and flexible middleware solution leveraged by external teams to develop online video game features.&rdquo;</p>
<p>This is a bit like the mission statement of your project, or the elevator pitch you give someone that asks you what you are working on.</p>
<p>Associated with the primary goal are a host of desiderata, or secondary objectives. These are the key objectives used to weigh technical decisions. It&rsquo;s important for the design to highlight a scale of values so one can refer to them to decide if his/her idea fits the design or not. Here is an example:</p>
<ol>
<li>
<p>Stability</p>
</li>
<li>
<p>Performance / Scalability</p>
</li>
<li>
<p>Encapsulation / Modularity</p>
</li>
<li>
<p>Conventions</p>
</li>
<li>
<p>Documentation</p>
</li>
<li>
<p>Reusability / Maintainability</p>
</li>
</ol>
<p>Often these desiderata are applied to most of your projects and reflect your team/company&rsquo;s technical values. The list might seem simple and unnecessary but, believe me, it will reduce the arguments where John tells Jane that her idea sucks but his is better because he &ldquo;knows better&rdquo;. Having an objective reference to refer to when trying to decide which is the best way to go is greatly valuable and will reduce the amount of office drama.</p>
<h2 id="constraints">Constraints</h2>
<p>Finally, make sure to explicitly define all the major constraints and to acknowledge the team&rsquo;s concerns. Here is a small example of what could be listed (which also reflect the previously mentioned perspectives):</p>
<ul>
<li>
<p>hard deadlines</p>
</li>
<li>
<p>external teams involved</p>
</li>
<li>
<p>huge load expected</p>
</li>
<li>
<p>limited support available</p>
</li>
<li>
<p>requirements changing quickly</p>
</li>
<li>
<p>limited budget</p>
</li>
<li>
<p>unknown hosting architecture/constraints</p>
</li>
<li>
<p>&hellip;</p>
</li>
</ul>
<p>Remember that design is always iterative because the constraints keep changing. That&rsquo;s just the way it is and a lot of technical constraints only appear as you implement or test your design. That&rsquo;s also why the design needs to be clear but the implementation needs to be flexible.</p>
<h2 id="reads-vs-writes">Reads vs writes</h2>
<p>Most of the web apps out there are read heavy, meaning that the stored data gets more accessed than modified. Scaling these type of systems is easier as one can introduce a cache layer, an intermediary storage, which acts as a fast buffer that avoids putting load on the backends. The cost reduction is huge because if you architected your app properly, the data is read from the data store only once (or once every X minutes) after being created/modified.</p>
<p>Caching is so important that it&rsquo;s even built into the HTTP protocol, making caching trivial.
Speaking of HTTP, a common problem I often see when serving http content to a browser is that even though the backend calls are the same, some information needs to be customized for the current visitor. This prevents it from caching the entire page. An easy solution in this case is to still cache the entire page but to use javascript to fetch the custom data from the backend and to modify the cached http at the client&rsquo;s browser level directly. As part of your design, you will more than likely need to implement multiple layers of caching and use technologies such as query caching, Varnish, Squid, Memcached, memoization, etc&hellip;</p>
<p>The problem is that, as your system gets more traffic, you will notice that the volume of DB/network writes becomes your bottleneck. You will also notice a reduction of your cache/hit ratio because only a small part of your cached data is often retrieved by many clients. At this point, you will need to denormalize to avoid contention, shard your data in silos, or write to cache and flush from cache when the data store is available and not overwhelmed.</p>
<h2 id="asynchronous-processing">Asynchronous processing</h2>
<p>One way to avoid write contention is to use async processing. The concept is simple. Instead of directly writing to your datastore after your backend receives a request, you put a message in a queue with all the information needed to run the operation later. On the other side, you have a set number of workers receiving messages and operating on them one after the other.</p>
<p>The advantage of such an approach is that you control the amount of workers and therefore the amount of maximum concurrent writes to your datastore. You can also process the queue before it gets worked and and maybe coalesce some messages or remove outdated/duplicated message. Finally, you can assign more workers to some message types, making sure the important messages get processed first.</p>
<p>Another advantage of this design includes not letting the client hang while you&rsquo;re processing the data and potentially timeout. You can also process a long queue faster by starting more workers to catch up and retire them later.
You app is more resilient to errors and failed async jobs can be restarted.</p>
<h2 id="load-test-monitor-and-be-proactive">Load test, monitor and be proactive</h2>
<p>Even the best designs have weak spots and will have to be improved once they are released. Don&rsquo;t wait for your system to fall apart before looking for solutions. Monitor your app. Every single part of your app. Look for patterns showing signs of potential problems and imagine what you could do to resolve them if they would start manifesting.</p>
<p>Of course before getting there, you will need to understand each part of your system and benchmark/load test/profile your app so you can be ready to face the storm.</p>
<p>Benchmarks and load tests are both super important and, too often, not reflective of what you will really face later on. They are usually great at identifying major problems that should be resolved right away, but fail to show the one big problem you will see on day one when you have to deal with 20k concurrent requests. Use them as indicators, rely on your experience and learn about problems other have faced. This will help you build a knowledge of scalability challenges, their root causes, and their potential solutions.</p>
<p>For benchmarking Ruby code, I use the<a href="https://ruby-doc.org/stdlib/libdoc/benchmark/rdoc/classes/Benchmark.html"> built-in benchmark tool available in the standard lib</a>.
For simple load testing, I use <a href="https://www.hpl.hp.com/research/linux/httperf/">httperf</a>/<a href="https://www.xenoclast.org/autobench/">autobench</a> and <a href="https://freshmeat.net/projects/siege/">siege</a>.
For anything more complicated, I use <a href="https://jakarta.apache.org/jmeter/">JMeter</a>.
In the video game industry, we also often use sims using the client&rsquo;s code to create load.</p>
<p>Benchmarking without profiling is often useless. Unlike other programming languages, Ruby doesn&rsquo;t yet have awesome profiling tools easy to use, but things are evolving quickly. Here are some tools I use regularly.</p>
<p>The <a href="https://github.com/tmm1/perftools.rb">Ruby wrapper</a> around <a href="https://code.google.com/p/google-perftools/">google perftools</a> is really good.
Before using perftools as often as I do now, I frequently used <a href="https://ruby-prof.rubyforge.org/">ruby-prof</a> with <a href="https://kcachegrind.sourceforge.net/html/Home.html">kcachegrind</a>.
Ruby 1.9 lets you inspect its garbage collector as explained in a <a href="https://merbist.com/2010/07/29/object-allocation-why-you-should-care/">previous post</a>.
And when using <a href="https://macruby.org">MacRuby</a>, I often use <a href="https://en.wikipedia.org/wiki/DTrace">DTrace</a>.</p>
<h2 id="other-misc-things-i-learned">Other misc. things I learned</h2>
<h3 id="documentation">Documentation</h3>
<p>Documentation is critical. It doesn&rsquo;t matter how you do it but you need to make sure you document what you want to build, how you build it, and why you build it. Documenting will help you and the others working on the project, and will keep you in check. I have started documenting an API and then realized that the design was flawed. Maybe it&rsquo;s just the way you name a method, or a class, or it can be a weird method signature or even the entire workflow being wrong, but when you document things, design errors appear more obviously.</p>
<p>To document Ruby code, I use <a href="https://yardoc.org/">yard</a> which is quite similar to <a href="https://en.wikipedia.org/wiki/Javadoc">javadoc</a>. Code documentation, when writing <a href="https://en.wikipedia.org/wiki/Duck_typing">duck typed language</a>, is, for me, very important since it makes the API designer&rsquo;s expectations much clearer. I also often add English documentation, written in markdown files and compiled by yard. If you say that your code is simple and that it doesn&rsquo;t require documentation because anyone can just read it and understand &hellip; then you have totally miss the point. Yes, it&rsquo;s more work to keep documentation and code in sync. But people using web APIs don&rsquo;t have access to the implementation details. The people distributing compiled APIs don&rsquo;t give access to their implementation. And honestly, the API should be decoupled from the implementation. I shouldn&rsquo;t have to guess how to use your API based on how you implemented the code underneath, otherwise my assumptions might be totally wrong.</p>
<h3 id="simplicity">Simplicity</h3>
<p>With great power comes great responsibility. The law of system entropy says that systems become more disorganized over time, so don&rsquo;t start with complicated code if you can avoid it! It&rsquo;s not because your programming language lets you do crazy stuff that you have to use it. In 90+% of the time, your code can be written without voodoo and be easier to read, easier to understand, easier to maintain and faster to execute.</p>
<p>If you can&rsquo;t figure out how to <em><strong>not</strong></em> use metaprogramming or weird patterns, take a step back and look at your design, did you miss something?
Also, don&rsquo;t reinvent the wheel. Use the language the way it was designed to be used. Keep your APIs as small as possible, don&rsquo;t expose too much as it will be virtually impossible to remove it later on.</p>
<p>As an example, look to what extent Rails modified the Ruby language:</p>
<p>In Rails' console (Rails 2, Ruby 1.8.7)</p>
<pre><code>&gt;&gt; Array.ancestors
=&gt; [Array, ActiveSupport::CoreExtensions::Array::RandomAccess,
 ActiveSupport::CoreExtensions::Array::Grouping, ActiveSupport::CoreExtensions::Array::ExtractOptions,
 ActiveSupport::CoreExtensions::Array::Conversions, ActiveSupport::CoreExtensions::Array::Access,
 Enumerable, Object, ERB::Util, ActiveSupport::Dependencies::Loadable, Base64::Deprecated, Base64,
 Kernel]
&gt;&gt; [].methods.size
=&gt; 233
</code></pre>
<p>In irb:</p>
<pre><code>&gt;&gt; Array.ancestors
=&gt; [Array, Enumerable, Object, Kernel]
&gt;&gt; [].methods.size
=&gt; 149
</code></pre>
<p>Removing any of these added methods is virtually impossible since some piece of code somewhere might rely on it.</p>
<h3 id="abstraction--its-dangers">Abstraction &amp; its dangers</h3>
<p>Often when designing an API, it&rsquo;s preferable to offer a well defined  public API which will delegate the work to a private implementation shared between  multiple public APIs. This approach avoids duplication, makes maintenance easy, and  allows for more flexibility. As an example, we can have a public  matchmaking API which will delegate most of the work to a private  matchmaking interface. If required, swapping the private interface would be  totally transparent to the public API. This approach has a downside, however. Having a shared private implementation does create a duplication of APIs. It leaves us with both a public and a private API because we need an API for public access and a private API for the public API to connect to. But when we weigh the  benefits and look at what is duplicated, we realize that this trade off  is worth it.</p>
<p>Keeping a certain level of abstraction is important to maintaining the separation of concerns as clear as possible. You want to layer your design so that each  layer is responsible for itself, only knows about itself, and has limited  interactions with other layers. By factoring/isolating the different  modules, you can keep a simple, elegant, easy to maintain system. This  is a key element of design but one needs to be careful not to obfuscate  the design by over abstracting his/her code. This is particularly important when designing a scalable app because you will often need to be able to easily swap parts  to optimize each part of your system.</p>
<p>That said, a lot of code out there is unnecessarily complicated. I sometime wonder if the authors of such code try to show that they know some cool language tricks. Or maybe this is due to the fact that, too often, people are impressed by code they don&rsquo;t understand. The problem with overly complicated or magical code is that it creates yet another abstraction layer between the end user and API. It makes the API more opaque, and that&rsquo;s a cost you have to take into consideration. Every time you abstract something you have a cost associated with the abstraction. This cost can be calculated in terms of performance loss, clarity loss and maintainability cost.</p>
<p>This is exactly the same problem encountered when trying to normalize data in a database.
Normalizing is a great concept which makes a lot of sense &hellip; until you realize that the cost of keeping your data normalized is too great and it becomes a major bottleneck, not letting you scale your application.
At this moment (and probably only then) that you need to denormalize your data.</p>
<p>It&rsquo;s the same thing with code abstraction. It&rsquo;s fine to abstract, unless the abstraction is such that it requires too much work to understand what is going on. A bit of duplication is often worth it, but be careful to not abuse it.</p>
<h3 id="debugging">Debugging</h3>
<p>Ruby has a decent debugger called <a href="https://bashdb.sourceforge.net/ruby-debug.html">ruby-debug</a> and I&rsquo;m amazed by the amount of people who haven&rsquo;t heard about it.
I don&rsquo;t know what I would do if I couldn&rsquo;t use breakpoints and get an interactive shell to debug Ruby code.
Please people! This is 2011, stop using print statement as a means of debugging!</p>
<h2 id="conclusion">Conclusion</h2>
<p>That&rsquo;s is for this post. It was longer than expected and I feel I didn&rsquo;t really cover anything in depth, but hopefully you learned something new or at least read something that piqued your interest. I look forward to reading your comments and, hopefully, your blog posts sharing your experience in designing scalable software.</p>
]]></content>
		</item>
		
		<item>
			<title>causality of scalability</title>
			<link>https://matt.aimonetti.net/posts/2011-01-causality-of-scalability/</link>
			<pubDate>Tue, 18 Jan 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-01-causality-of-scalability/</guid>
			<description>Part of my job at Sony PlayStation is to architect scalable systems which can handle a horde of excited players eager to be the first to play the latest awesome game and who would play for 14-24 hours straight. In other words, I need to make sure a system can &amp;ldquo;scale&amp;rdquo;. In my case, a scalable system is a system that can go from a few hundred concurrent users/players to hundreds of thousands of concurrent users/players and stay stable for months.</description>
			<content type="html"><![CDATA[<p>Part of my job at <a href="https://us.playstation.com/">Sony PlayStation</a> is to architect scalable systems which can handle a horde of excited players eager to be the first to play the latest awesome game and who would play for 14-24 hours straight. In other words, I need to make sure a system can &ldquo;scale&rdquo;. In my case, a scalable system is a system that can go from a few hundred concurrent users/players to hundreds of thousands of concurrent users/players and stay stable for months.</p>
<p>One can achieve scalability in many ways, and if you expect me to provide you with a magical formula you will be disappointed. I actually believe that you can scale almost anything if you have the adequate resources. So saying that X or Y doesn&rsquo;t scale is for me a sign that people are taking shortcuts in their explanations (X or Y are really hard to scale so they don&rsquo;t scale) or that they don&rsquo;t understand the causality of scaling. However what I am exploring in this post is the relationship between cause and effect when trying to make a system scalable. We will see that the scalability challenge is not new and not exclusive to the tech world. We will study the traditional approach to scaling and as well as the challenge of scaling in relation to the web and what to be aware of when planning to make a solution scalable.</p>
<h2 id="scaling-outside-of-the-tech-world">Scaling outside of the tech world</h2>
<p>Trying to scale isn&rsquo;t new. It goes back to well before technology was invented. Scaling something up or increasing something in size or number is a goal businesses have aimed for ever since the oldest profession in the world was invented. <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/4/49/EN_BESKYTTERINDE_AF_INDUSTRIEN.gif/180px-EN_BESKYTTERINDE_AF_INDUSTRIEN.gif" alt="">A prostitute wanting to scale up her business was limited by her own time and body. She would reach a point where she couldn&rsquo;t take more clients. (Independent contractors surely know what I am talking about!) So a prostitute wanting to scale up would usually become a madam/Mama-san and scale the business by having girls work for her.</p>
<p>Another simple example would be a restaurant. A restaurant can handle up to a certain amount of covers/clients at once, after that, customers have to wait in line. The restaurant example is interesting because you can clearly see that opening a huge restaurant with a capacity of 1,000 covers might not be a good idea. First because the cost of running such a restaurant might be much more than the income generated. But also because even though the restaurant does 1,000 covers at peak time, it doesn&rsquo;t mean that the restaurant will stay that busy during the entire time it&rsquo;s open. So now you have to deal with waiter/waitresses, busboys and other staff who won&rsquo;t have anything to do. As you probably have understood already, scaling a restaurant means that the scaling has to be done in a cost effective manner.  And what&rsquo;s even more interesting is that what we could have thought was the bottleneck (the amount of concurrent covers) can be easily scaled up but it wouldn&rsquo;t provide real scalability. In fact this choice would cascade into other areas of management like staffing and the building size. Often, the scaling solution for restaurants is to open new locations which can result in keeping the lines shorter, targeting new markets and reducing risks since one failing branch won&rsquo;t dramatically affect the others.</p>
<p><img src="https://upload.wikimedia.org/wikipedia/en/thumb/4/4a/Nighthawks.jpg/400px-Nighthawks.jpg" alt="posted by Matt Aimonetti"></p>
<h2 id="scaling-in-the-traditional-tech-world">Scaling in the traditional tech world</h2>
<p>If you&rsquo;ve ever done console development or worked on embedded devices, you know that they are restricted by some key elements. <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d3/PS3Versions.png/220px-PS3Versions.png" alt="posted by Matt Aimonetti">It can be memory, CPU, hard drive space etc&hellip; You have to &ldquo;cram&rdquo; as many features as you can into the device, working around the fixed limitations of the hardware. In the console industry, what&rsquo;s interesting to note is that the hardware doesn&rsquo;t change often but people expect than a new game on the same platform will do things better than the previous game, even though the limitations are exactly the same. This is quite a challenging problem because you have to fight against the hardware limitations by optimizing your code to be super efficient. That&rsquo;s exactly the reason why console video game developers manage memory manually instead of relying on a garbage collector. This way they can squeeze every resource they can from the console.</p>
<p>The great advantage of this type of development is that you can reproduce and accurately anticipate issues. The bottlenecks/limitations are well known and immutable! If you find a way around in your lab, you know that the solution will work for everyone. Console video game developers (and to some extent, iOS developers) don&rsquo;t have to wonder how their game will behave if the player has an old graphic card or not enough RAM.</p>
<p>But ever since we started distributing the processing power, scaling technology has become more challenging.</p>
<h2 id="scaling-on-the-web">Scaling on the web</h2>
<p>Scaling a web based solution might actually seem quite like scaling a restaurant, except that you can&rsquo;t easily open multiple locations since the concept of proximity in web browsing isn&rsquo;t really as concrete as in real life. So the solution can&rsquo;t be directly transposed. Most people will only have to scale up by optimizing their code running on one server, or maybe two. That&rsquo;s because their service/app is not, and won&rsquo;t be, generating high traffic. Scaling such systems is common and one can rely on work done in the past decades for good examples of solutions.</p>
<p>However some web apps/games are or will become high traffic. But because every single entrepreneur I&rsquo;ve met believes that their solution will be high traffic, they think they need to be able to scale and therefore should be engineered like that from the beginning. (This is, by the way, the reason scalability is a buzzword and you can sell almost anything technical saying that it scales.) The problem with this approach is that people want scalability but don&rsquo;t understand its causality. In other words, they don&rsquo;t understand the relationship between cause and effect related to making a solution scalable.</p>
<p>Basically we can reduce the concept of causality of scalability to something like this: you change a piece of the architecture to handle more traffic, but this part has an effect on other parts that also need to change and the pursuit of scalability almost never ends (just ask Google). <strong>Making a system scalable needs to have well a defined cause and expected effect, otherwise it&rsquo;s a waste</strong>. In other words, the effect of scaling engenders the need for solutions which themselves have complex effects on a lot of aspects of a system. Let&rsquo;s make it clearer by looking at a simple example:</p>
<p><a href="https://merbist.com/2011/01/18/causality-of-scalability/simplestarchitecture/"><img src="https://merbist.com/wp-content/uploads/2011/01/simplestarchitecture-300x269.png" alt="Simple Architecture by Matt Aimonetti"></a>We have an e-commerce website and this website uses a web application with a database to store products and transactions. Your system is made of 1 webserver handling the requests and one database storing the data. Everything goes well until Black Friday, Christmas or Mother&rsquo;s Day arrives and now some customers are complaining that they can&rsquo;t access your website or that it&rsquo;s too slow. This is also sometimes referred to as the digg/slashdot/reddit effect. All of a sudden you have a peak of traffic and your website can&rsquo;t handle it. This is actually a very simple use case, but that&rsquo;s also the only use case most people on the web need to worry about.</p>
<p>The causality of wanting this solution to scale is simple, you want to scale so you can sell more and have happy customers. The effect is that the system needs to become more complex.</p>
<p>To scale such a system, you need to find the root cause of the problem. You might have a few issues, but start by focusing on the main one. In this case, it&rsquo;s more than likely that your webserver (frontend) cannot handle more than x requests/second. Interestingly enough, the amount of reqs/s might not match the result of your load tests. That&rsquo;s probably because you didn&rsquo;t expect the usage pattern that you are seeing, but that&rsquo;s a whole different topic. At this point you need to understand why you can&rsquo;t go above the x reqs/s limit you&rsquo;re hitting. Where is the bottleneck? Is it that your application code is too slow? Is it the database has been brought to its knees? Or maybe the webserver serves as many requests as technically possible but it&rsquo;s still not enough based on the traffic you are getting.</p>
<p>If we stop right here, we can see that the reasons why the solution doesn&rsquo;t scale can be multiple. But what&rsquo;s even more interesting is that the root cause this time depends on the usage pattern and that it is really hard to anticipate all patterns. If we wanted to make this system scale we could do it different ways.</p>
<p>To give you some canned answers, if the bottleneck is that your code is too slow, you should check if the code is slow because of the DB queries made (too many, slow queries etc..). Is it slow because you are doing something complex that can&rsquo;t be easily improved or is it because you are relying on solutions that are known to not support concurrent traffic easily? More than likely, you will end up going for the easy caching approach. By caching some data (full responses, chunk of data, partial responses etc..) you avoid hitting your application layer and therefore can handle more traffic.</p>
<p>[caption id=&ldquo;attachment_879&rdquo; align=&ldquo;aligncenter&rdquo; width=&ldquo;300&rdquo; caption=&ldquo;Caching avoids data processing &amp; DB access &ldquo;]<a href="https://merbist.com/2011/01/18/causality-of-scalability/simplestarchitecture3/"><img src="https://merbist.com/wp-content/uploads/2011/01/simplestarchitecture3-300x201.png" alt="More complex Architecture by Matt Aimonetti"></a>[/caption]</p>
<p>If your code is as fast as it can be, then a solution is to add more application servers or to async some processes. But now that means that you need to change the topology of your system, the way you deploy code and the way you route traffic. You will also increase the load on the database by opening more connections and maybe the database will now becoming the new bottleneck. You might also start seeing race conditions and you are certainly increasing the maintenance and complexity aka cost of your system (caching might end up having the same effect depending on the caching solution chosen).</p>
<p>[caption id=&ldquo;attachment_876&rdquo; align=&ldquo;aligncenter&rdquo; width=&ldquo;297&rdquo; caption=&ldquo;One way of scaling it to load balance the traffic&rdquo;]<a href="https://merbist.com/2011/01/18/causality-of-scalability/simplestarchitecture2/"><img src="https://merbist.com/wp-content/uploads/2011/01/simplestarchitecture2-297x300.png" alt="load balanced approach by Matt Aimonetti"></a>[/caption]</p>
<p>Just looking at these possible causes and the various solutions (we didn&rsquo;t even mention DB replication, sharding, NoSQL etc..), we can clearly see that making a system scalable has some concrete effects on system complexity/maintenance which directly translate in cost increase.</p>
<p>If you are an engineer, you obviously want your system to be super scalable and handle millions of requests per second. But if you are a business person, you want to be realistic and evaluate the causality of not scaling after a certain point and convert that as loss. Then you weigh the cost of not scaling with the cost of &ldquo;maybe&rdquo; scaling and you make a decision.</p>
<p>The problem here though is that scaling is a bit like another buzzword: SEO (Search Engine Optimization). A lot of people/solutions will promise scaling capabilities without really understanding the big picture. Simple systems can easily scale up using simple solutions but only up to a certain level. After that, what you need to do to scale becomes so complex than anyone promising you the moon probably doesn&rsquo;t know what they are talking about. If there was a one-size-fits-all, easy solution for scaling, we would all be using it, from your brother for his blog, to Google without forgetting Amazon.</p>
<p><img src="https://awsmedia.s3.amazonaws.com/logo_aws.gif" alt="AWS logo posted by Matt Aimonetti">Speaking of Amazon, I hear a lot of people saying that Amazon AWS services is &ldquo;THE WAY&rdquo; (i.e: the only way) to scale your applications. I agree that it&rsquo;s a compelling solution for a lot of cases but it&rsquo;s far from being a silver bullet. Remember that the cause and effect of why you need to scale are probably different than anyone else.</p>
<h2 id="amazon-web-services">Amazon Web Services</h2>
<p>Let me give you a very concrete example of where <a href="https://aws.amazon.com/">AWS services</a> might_ not_ be a good idea: high traffic sites with lots of database writes and low latency.</p>
<p><a href="https://zynga.com">Zynga</a>, the famous social game company behind Farmville, Mafia Wars etc., is using AWS and it seems that they might have found themselves in the same scenario as above<img src="https://www.zynga.com/img/logo.png" alt="">. And that would be almost correct. Zynga games have huge traffic and they do a ton of DB writes. However I don&rsquo;t think they need low latency since their game clients are browsers and Flash clients and that their games are mainly async so they just need to be able to handle unstable latency. We&rsquo;ll see in a second how they manage to perform on the AWS cloud.</p>
<p>The major problem with AWS when you have a high traffic site is IO: IO reliability, IO latency, IO availability. By IO, I&rsquo;m referring to network connection (internal/external) and disk access. Put differently, when you design your system and you know you are going to run on AWS, you need to take into consideration that your solution should survive with zero or limited IO because you will more than likely be IO bound. This means that your traditional design won&rsquo;t work because your database hard drive won&rsquo;t be available for 30s or will be totally saturated. You also need to have a super redundant system because you are going to randomly lose machines. Point number one, moving your existing application from a dedicated hosting solution to AWS might not help you scale if you didn&rsquo;t architect to be resilient to bad IO. Simply put, and to only pick one example: if you were expecting your database to be able to always properly write to disk you will have problems.</p>
<p>[caption id=&rdquo;&rdquo; align=&ldquo;alignleft&rdquo; width=&ldquo;184&rdquo; caption=&ldquo;Octocat, the GitHub mascot&rdquo;]<img src="https://tctechcrunch.files.wordpress.com/2010/07/github-logo.png" alt="">[/caption]</p>
<p>The solution depends on how you want to look at it and where you are at in your project. You can go the <a href="https://highscalability.com/blog/2010/2/8/how-farmville-scales-to-harvest-75-million-players-a-month.html">Zynga route and design/redesign your entire architecture to be highly redundant, not rely on disk access</a> (everything is kept in memory and flushed to disk when available) and tolerate a certain % of data loss. Or you can go with the<a href="https://github.com/blog/493-github-is-moving-to-rackspace"> GitHub approach</a><a href="https://github.com/blog/493-github-is-moving-to-rackspace"> and mix dedicated hardware for IO and &ldquo;cloud&rdquo; front end servers all on the same network</a>. One solution isn&rsquo;t better than the other, they are just different and depend on your needs. <a href="https://github.com">GitHub</a> and <a href="https://www.zynga.com/">Zynga</a> both need to scale but they have different requirements.</p>
<p>When it comes to scaling, things are not black or white. To stay on the AWS topic, let&rsquo;s take another example: Amazon Relational Database Service (RDS). Earlier today, I was complaining on Twitter that RDS doesn&rsquo;t and probably won&rsquo;t let you use the <a href="https://yoshinorimatsunobu.blogspot.com/2010/10/using-mysql-as-nosql-story-for.html">MySQL HandlerSocket plugin</a> any time soon, even though it&rsquo;s been released for almost 6 months and used in prod by many. Then someone asked me if using this plugin would offset the scalability cost-saving. The quick and wrong answer  is yes. By using the plugin, you can potentially get rid of your Memcached servers, probably your Redis/MongoDB/CouchDB servers or whatever NoSQL solution you write and just keep the database servers you currently have. You might have to beef up your DB servers a bit but it would certainly be a huge cost reduction and your system would be simpler, easier to maintain and the data would be more consistent. Sounds good right? After all the biggest online social game company designed it and uses it.</p>
<p>The only problem is that RDS is an AWS service and like every AWS service, it suffers from poor IO. So, if you were deciding to not use RDS and run your own MySQL servers with the HandlerSocket plugin, it wouldn&rsquo;t bring you much improvement <em>(1)</em>. Actually, if you are already IO bound, it would make things worse, because you are centralizing your system around the most unreliable part of your architecture. Based on that premise, RDS won&rsquo;t support HandlerSocket because RDS runs on the same AWS architecture and has to deal with the same IO constraints. What&rsquo;s the solution, you might ask? Amazon already went through these scaling problems and they offer a custom, non-relational, data storage solution working around their own issues called SimpleDB. But why would they improve RDS and fix a really hard problem when they already offer an alternative solution? Easy. SimpleDB forces you to redesign your architecture to work with their custom solution and, guess what? You are now locked-in to that vendor!</p>
<p>So the answer is yes, you can offset scalability costs if you don&rsquo;t use AWS or any other providers with bad IO. Now you should look at the cost of moving away from AWS and see if it&rsquo;s worth it. How much of your code and of your system is vendor specific? Is that something you can easily change? The <a href="https://github.com/geemus/fog">fog library</a>, for instance, supports multiple cloud providers. Are you using something similar? Can you transition to that?  Can you easily deploy to another hosting company? (<a href="https://opscode.com/chef">Opscode chef</a> makes that task much easier) But if, for one reason or another, you have to stick with AWS/<other cloud provider>, make sure that the business people in charge understand the consequences and the cost related to that choice.</p>
<h2 id="conclusion">Conclusion</h2>
<p>My point is not to tell you to not design a scalable solution, or not to use AWS, or that RDS sucks. My point is to show that making a system scale is hard and has some drastic effects that are not always obvious. There aren&rsquo;t any silver bullet solutions and you need to be really careful about the consequences (and costs) involved with trying to scale. Make sure it&rsquo;s worth it and you have a plan. Define measurable goals for your scalability even though it&rsquo;s really hard, don&rsquo;t try to scale to infinity and beyond, that won&rsquo;t work. Having to redesign later on to handle even more traffic, is a good problem to have, don&rsquo;t over engineer.</p>
<p>Finally, be careful to understand the consequences of your decisions. What seems to be an almost trivial scaling move such as moving your app from dedicated hosting to a specific cloud provider might end up getting you in a vendor lock in situation!</p>
<hr>
<p><em>1: I assume that you are IO bound. If you are not and your DB data fits in memory/cache, then HS on AWS is fine but if that&rsquo;s the case what&rsquo;s your bottleneck? ;)</em></p>
]]></content>
		</item>
		
		<item>
			<title>macruby book update</title>
			<link>https://matt.aimonetti.net/posts/2011-01-macruby-book-update/</link>
			<pubDate>Sat, 15 Jan 2011 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2011-01-macruby-book-update/</guid>
			<description></description>
			<content type="html"><![CDATA[]]></content>
		</item>
		
		<item>
			<title>rubyconf 2010 macruby talk</title>
			<link>https://matt.aimonetti.net/posts/2010-11-rubyconf-2010-macruby-talk/</link>
			<pubDate>Fri, 12 Nov 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-11-rubyconf-2010-macruby-talk/</guid>
			<description>##Description of the talk:
This year I gave the traditional Apple&amp;rsquo;s MacRuby talk at RubyConf. My presentation focused on 2 axis:
 What&amp;rsquo;s new since last RubyConf Show some examples of how fun it is to hack with MacRuby  ##Video
{% video https://cdn.confreaks.com/system/assets/datas/768/original/448-rubyconf2010-macruby-why-and-how-small.mp4 640 360 /images/matt_aimonetti_rubyconf2010.jpeg %}
Other video formats are available here
##Slides
 Presentation slides available on Speakerdeck
##Details of the talk content
MacRuby is currently at version 0.</description>
			<content type="html"><![CDATA[<p>##Description of the talk:</p>
<p>This year I gave the traditional Apple&rsquo;s MacRuby talk at RubyConf.
My presentation focused on 2 axis:</p>
<ul>
<li>What&rsquo;s new since last RubyConf</li>
<li>Show some examples of how fun it is to hack with MacRuby</li>
</ul>
<p>##Video</p>
<p>{% video <a href="https://cdn.confreaks.com/system/assets/datas/768/original/448-rubyconf2010-macruby-why-and-how-small.mp4">https://cdn.confreaks.com/system/assets/datas/768/original/448-rubyconf2010-macruby-why-and-how-small.mp4</a> 640 360 /images/matt_aimonetti_rubyconf2010.jpeg %}</p>
<p>Other video formats are available <a href="https://www.confreaks.com/videos/448-rubyconf2010-macruby-why-and-how">here</a></p>
<p>##Slides</p>
<script async class="speakerdeck-embed" data-id="4f90697149bc25001f023143" data-ratio="1.299492385786802" src="https://speakerdeck.com/assets/embed.js"></script>
<p><strong><a href="https://speakerdeck.com/u/matt_aimonetti/p/rubyconf-2010-macruby-why-and-how">Presentation slides available on Speakerdeck</a></strong></p>
<p>##Details of the talk content</p>
<p>MacRuby is currently at version 0.7.1 and version 0.8 is in preparation.
Since last new a lot of things happened, here is a quick summary:</p>
<ul>
<li>
<p>Cocoa dev is now considered stable.  Apple gave its seal of approval, most of the bugs are fixed and it&rsquo;s currently used on production projects and some apps were even submitted to the Mac App Store.</p>
</li>
<li>
<p>Ahead of Time compilation. This is quite a major improvement with many repercussions. Being to compile your Ruby source code means faster boot time and source obfuscation. Two major things to consider when you want to ship a desktop app.</p>
</li>
<li>
<p>Debugger. MacRuby now ships with its own debugger. Of course you can still use GDB and DTrace, but MacRuby&rsquo;s debugger is really easy to use and very powerful.</p>
</li>
<li>
<p>Grand Central Dispatch support and wrapper API. Having to manage threads can be hard for both developers and for the machines having to run the developer code. GCD is an abstraction layer allowing developers to only focus on business logic without having to worry about the underlying details if you don&rsquo;t want to. The end result is an optimum use of all the cores available on a machine and truly concurrent code. Two important notions when writing desktop apps.</p>
</li>
<li>
<p>ControlTower - A webserver for Rack apps written in MacRuby and using GCD for concurrency.</p>
</li>
<li>
<p>New rewritten and more efficient dispatcher. Practically that means that the dispatcher is now thread safe with a per thread cache.</p>
</li>
<li>
<p>RegExp lib switch from Oniguruma to ICU. This was quite a big change and it was required because Oniguruma isn&rsquo;t thread safe and while C Ruby uses a Global Interpreter Lock. MacRuby on the other hand uses native POSIX threads running on their own non-locking, reentrant VM making thread safety critical.</p>
</li>
<li>
<p>More solid foundations - Some key classes we rewritten to improve performance and flexibility.</p>
</li>
<li>
<p>Support for C blocks - Objective-C has been supporting C blocks for a while and some Cocoa APIs require the use of blocks. MacRuby now allows you to use Ruby blocks and to pass them as C blocks. (new BridgeSupport required)</p>
</li>
<li>
<p>Sandboxing - For safety reasons, MacRuby allows you to now sandbox your applications. You can restrict your app from doing some potential dangerous things such as writing to disk, calling the system, accessing internet etc&hellip;</p>
</li>
<li>
<p>Mac App Store - This is not something done by the MacRuby team. But it directly affects MacRuby developers wanting to distribute their applications. Think about the exposure that you can app can have. Even if you have a web app, you can use WebKit to wrap it up, hook up a notification, add to that a local backup solution and geo location. Brilliant way to provide an even better user experience and better product exposure. All that really easily if you already know Ruby.</p>
</li>
</ul>
<p>To give an idea of what can be done I showed some code samples hopefully showing the cool hacking things one can play with:</p>
<ul>
<li>
<p>The first demo shows how to use the speech recognizer. The example is really sample you speak the name of someone and his/her picture shows up on screen. Just a few lines of code and you can start screaming commands to your TV to get it to change channel.</p>
</li>
<li>
<p>The second demo is an extremely simple Gowala client using CoreLocation. Yes, Mac desktop and laptops support geo location.</p>
</li>
<li>
<p>Another example of what you do is a sample letting you import all your twitter followers to your address book.</p>
</li>
<li>
<p>You can also use some of the low level OS features such as the Tokenizer. The next example showed how to extend Ruby and use a C function to detect the language of a string.</p>
</li>
<li>
<p>Finally, the last demo shows how to integrate a bluetooth device to control a HTML view via MacRuby and Javascript. All that in just a few lines of code!</p>
</li>
</ul>
<p>Basically, MacRuby is now mature and it&rsquo;s time for hackers and people trying to get exposure to give it a try.</p>
<p>##Presentation&rsquo;s website</p>
<p>A page was setup on the confreaks website and available <a href="https://www.confreaks.com/videos/448-rubyconf2010-macruby-why-and-how">here</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>macruby webkit and js</title>
			<link>https://matt.aimonetti.net/posts/2010-10-macruby-webkit-and-js/</link>
			<pubDate>Tue, 19 Oct 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-10-macruby-webkit-and-js/</guid>
			<description>I was working on a piece of code using MacRuby, Webkit and JavaScript. Calling JS from MacRuby is really straight forward but calling Ruby from JS is a but tricky. There is actually a known bug in MacRuby which was giving me a hard time. The bug should be fixed in 0.8 if everything goes according to plan. In the mean time here is a quick run down:
The JS bridge only works when using WebKit so we need to create a tiny browser to test our code.</description>
			<content type="html"><![CDATA[<p>I was working on a piece of code using MacRuby, Webkit and JavaScript. Calling JS from MacRuby is really straight forward but calling Ruby from JS is a but tricky. There is actually a known bug in MacRuby which was giving me a hard time. The bug should be fixed in 0.8 if everything goes according to plan. In the mean time here is a quick run down:</p>
<p>The JS bridge only works when using WebKit so we need to create a tiny browser to test our code. What we are going to do is to make an object available via JS and also trigger some JS to test the bridge both ways. Here is the full code:</p>
<p>On the object we want to make available via JS (instance of Cat), we have to make the methods available by defining def self.isSelectorExcludedFromWebScript(sel); false end</p>
<p>To trigger JS from Ruby, we use #evaluateWebScript on windowScriptObject. In our example we are using JQuery since it&rsquo;s already loaded in the DOM. We also go full loop by printing out the result of JS calling a method on our Ruby object.</p>
<p>Here is the thing, MacRuby doesn&rsquo;t have the age method compiled/registered yet so JS can&rsquo;t call it. To fix this problem we force the registration of the method by doing: @kitty.respondsToSelector(&ldquo;age&rdquo;).  Note that if #age was taking arguments, we would have to use @kitty.respondsToSelector(&ldquo;age:&quot;) and then evaluate the JS like that: @js_engine.evaluateWebScript(&lsquo;animal.age_(12)')</p>
<p>Hopefully by the time you need to do something like that, MacRuby 0.8 will be released and you won&rsquo;t have to worry about that :)</p>
<p>For more information about calling Obj-C/Ruby from JavaScript, <a href="https://developer.apple.com/library/mac/#documentation/AppleApplications/Conceptual/SafariJSProgTopics/Tasks/ObjCFromJavaScript.html#//apple_ref/doc/uid/30001215-BBCBFJCD">read this doc</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>the ruby movement art programming</title>
			<link>https://matt.aimonetti.net/posts/2010-09-the-ruby-movement-art-programming/</link>
			<pubDate>Mon, 27 Sep 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-09-the-ruby-movement-art-programming/</guid>
			<description>I wrote a guest blog post for Satish Talim over at RubyLearning.org
You can read it there.</description>
			<content type="html"><![CDATA[<p>I wrote a guest blog post for <a href="https://rubylearning.com/blog/about/">Satish Talim</a> over at <a href="https://rubylearning.com/blog/">RubyLearning.org</a></p>
<p>You can read it <a href="https://rubylearning.com/blog/2010/09/28/the-ruby-movement/">there</a>.</p>
<p><a href="https://rubylearning.com/blog/2010/09/28/the-ruby-movement/"><img src="/images/posts/the-ruby-movement.jpg" alt="The Ruby Movement by Matt Aimonetti" title="The Ruby Movement by Matt Aimonetti"></a></p>
]]></content>
		</item>
		
		<item>
			<title>discussion with a java switcher</title>
			<link>https://matt.aimonetti.net/posts/2010-08-discussion-with-a-java-switcher/</link>
			<pubDate>Sun, 22 Aug 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-08-discussion-with-a-java-switcher/</guid>
			<description>For the past 6 months, I have had regular discussions with an experienced Java developers who switched to Ruby a couple years ago. Names have been changed to protect the guilty but to help you understand my friend &amp;lsquo;Duke&amp;rsquo; better, you need to know that he has been a developer for 10 years and lead many complicated, high traffic projects. He recently released two Ruby on Rails projects and he has been fighting with performance issues and scalability challenges.</description>
			<content type="html"><![CDATA[<p>For the past 6 months, I have had regular discussions with an experienced Java developers who switched to Ruby a couple years ago. Names have been changed to protect the guilty but to help you understand my friend &lsquo;Duke&rsquo; better, you need to know that he has been a developer for 10 years and lead many complicated, high traffic projects. He recently released two Ruby on Rails projects and he has been fighting with performance issues and scalability challenges.</p>
<p>Duke is a happy Ruby developer but he sometimes has a hard time understanding why things are done in a certain way in the Ruby community. Here are some extracts from our conversations. My answers are only based on my own experience and limited knowledge. They are probably not shared by the entire  community, feel free to use the comment section if you want to add more or share your own answers.</p>
<h2 id="threads--concurrency">Threads / Concurrency</h2>
<p><strong>Duke:</strong> Why does the Ruby community hate threads so much. It seems to be a taboo discussion and the only answer I hear is that threads are hard to deal with and that Ruby does not have a good threading implementation. What&rsquo;s the deal there? If you want concurrent processing, threads are important!</p>
<p><strong>Me:</strong> This is a very good question and I think there are two main reasons why threads and thread safety are not hot topics in the Ruby world. First, look at Ruby&rsquo;s main implementation itself. If you are using an old version of Ruby (pre Ruby 1.9) you don&rsquo;t use native threads but green threads mapping to only 1 native thread. Ilya has a great (yet a bit old) <a href="https://www.igvita.com/2008/11/13/concurrency-is-a-myth-in-ruby/">blog post explaining the difference</a>, why it matters and also the role and effect of the Global Interpreter Lock (GIL). Also, even though Rubyists like to say that they live in the edge, most of them still use Ruby 1.8 and therefore don&rsquo;t really see the improvements in Ruby 1.9 nor yet understand the potential of <a href="https://ruby-doc.org/core-1.9/classes/Fiber.html">fibers</a>.</p>
<p>The other part of the explanation is that the Rails community never really cared until recently. Yehuda Katz recently wrote a <a href="https://yehudakatz.com/2010/08/14/threads-in-ruby-enough-already/">good article on thread safety</a> in Ruby and if you read his post and <a href="https://dpaste.de/5xyG/raw/">Zed Shaw&rsquo;s comment</a> you will understand a bit better the historical background. As a matter of fact, the current version of Rails is not multi-threaded by default and developers interested in handling concurrent requests in one process should <a href="https://api.rubyonrails.org/classes/Rails/Configuration.html#M002069">turn on this option</a>. Thread safety appeared for the first time in Rails 2.2 but from what I saw, most people still don&rsquo;t enable this option. There are many reasons for that. First, enabling thread safety disables some Rails features like automatic dependency loading after boot and code reloading. A lot of Rails developers take these two features for granted and don&rsquo;t understand that they are technically &ldquo;hacks&rdquo; to make their lives easier. I do believe a lot of Rails developers don&rsquo;t understand how threads, thread safety, concurrency, blocking IO and dependencies work. They care about getting their app done and meet their deadlines. They usually use and know Rails without paying too much attention to how Rails extends Ruby. Imagine what would happen if their code wasn&rsquo;t thread safe and Rails wasn&rsquo;t not using a global lock by default. Now you see why things are not exactly as you expect and also why some Rubyists are getting excited about new projects like <a href="https://nodejs.org/">node.js</a> which takes a different approach.</p>
<p>The other thing to keep in mind is that at least 90 to 95% of the Rails apps out there don&rsquo;t get more than a dozen requests/second (a million requests/day). You can scale that kind of load pretty easily using simple approaches like caching,  optimize your DB queries, load balancing to a couple servers. As a matter of fact, compared to the amount of people using Rails on a daily basis, only a very little amount of people are struggling with performance and scalability like you do. This is not an excuse but that explains why these people don&rsquo;t care about the things you care about.</p>
<h2 id="rails-is-slow">Rails is slow</h2>
<p><strong>Duke:</strong> I don&rsquo;t understand why Rails developers are not more concerned about the speed/performance penalty induced by Rails.</p>
<p><strong>Me:</strong> Again, Rails is fast enough for the large majority of developers out there. As you know, as a developer you have to always make compromises. The Rails team always said that development time is more expensive than servers and therefore the focus is on making development easier, faster and more enjoyable. However to get there, they have to somewhat sacrifice some performance. What can be totally unacceptable for you is totally fine for others and your contribution is always welcome. This is probably the root cause of the things you don&rsquo;t like in Rails. Rails was built for startups, by startup developers and you don&rsquo;t fall in this category. People contributing new features and fixes are the people using Rails for what it is designed to do. There is no real &lsquo;Enterprise&rsquo; support behind Rails and that might be why you feel the way you feel. Since you find yourself questioning some key Rails conventions and you are struggling with missing features, it looks  to me that you chose the wrong tool for the job since you don&rsquo;t even use 70% of the Rails features and are dreaming of things such 3 tier architecture. <a href="https://sinatrarb.com">Sinatra</a> might be a better fit for you if you want lower level control, less conventions and less built-in features.</p>
<h2 id="object-allocation--garbage-collection">Object allocation / Garbage Collection</h2>
<p><strong>Duke:</strong> I recently read that Twitter was spending <a href="https://blog.evanweaver.com/articles/2009/10/21/object-allocations-on-the-web/">20% of its request cycles in the GC</a>, am I the only finding that concerning?</p>
<p><strong>Me:</strong> Most people don&rsquo;t realize how the GC works and what it means to allocate objects since Ruby does that automatically. But at the same time, most of these people don&rsquo;t really see the affect of the Garbage Collection since they don&rsquo;t have that much traffic or they scale in ways that just skips their Ruby stack entirely. (Or they just blame Ruby for being slow)</p>
<p>If you are app deals with mainly reads/GET requests, using HTTP caching (Rails has that built-in) and something like Varnish/<a href="https://rtomayko.github.com/rack-cache/">Rack-cache</a> will dramatically reduce the load on your server apps. Others don&rsquo;t investigate their issues and just add more servers. As mentioned in a <a href="https://merbist.com/2010/07/29/object-allocation-why-you-should-care/">previous post</a>, some libraries like Builder are allocating LOTS more objects than others (Nokogiri), use the existing debugging tools to see where your object allocations occur and try to fix/workaround these. In other words, Ruby&rsquo;s GC isn&rsquo;t great but by ignoring its limitations, we made things even worse. My guess is that the GC is going to improve (other implementations already have better GCs) and that people will realize that Ruby is not magic and critical elements need to be improved.</p>
<h2 id="tools">Tools</h2>
<p><strong>Duke:</strong> I really have a hard time finding good tools to help scale my apps better and understand where I should optimize my code.</p>
<p>**Me: **It is true that we area lacking tools but things are changing. On top of the built-in tools like <a href="https://ruby-doc.org/core-1.9/classes/ObjectSpace.html">ObjectSpace</a>, <a href="https://ruby-doc.org/core-1.9/classes/GC/Profiler.html">GC::Profiler</a>, people interested in performance/debugging are working to provide the Ruby community with their expertise, look at <a href="https://memprof.com/">memprof</a> and <a href="https://rubyforge.org/projects/ruby-debug/">ruby-debug</a> for instance. Of course you can also use tools such as <a href="https://ruby-prof.rubyforge.org/">Ruby-prof</a>, <a href="https://kcachegrind.sourceforge.net/html/Home.html">Kcachegrind</a>, <a href="https://valgrind.org/">Valgrind</a> and <a href="https://www.gnu.org/software/gdb/">GDB</a>. (1.9.2 was <a href="https://github.com/yugui/ruby/tree/feature/dtrace">scheduled to have DTrace support</a> but I did not check yet). Maybe you should be more explicit about what tools you miss and how we could solve the gap.</p>
<h2 id="activerecord">ActiveRecord</h2>
<p><strong>Duke:</strong> ActiveRecord doesn&rsquo;t do what I need. How come there is no native support for master/slave DBs, sharding, DB view support is buggy,  suggested indexes on queries is not built-in and errors are not handled properly (server is gone, out of sync etc..)?</p>
<p><strong>Me:</strong> You don&rsquo;t have to use ActiveRecord, you could use any ORM such as <a href="https://sequel.rubyforge.org/">Sequel</a>, <a href="https://datamapper.org/">DataMapper</a> or your own. But to answer your question, I think that AR doesn&rsquo;t do everything you want because nobody contributed these features to the project and the people maintaining ActiveRecord don&rsquo;t have the need for these features.</p>
<h2 id="what-can-we-do">What can we do?</h2>
<p>We, as a community, need to realize that we have to learn from other communities and other programming languages, this kind of humorous graph is unfortunately not too far from reality.</p>
<p><img src="https://i.imgur.com/G7WyP.gif" alt=""></p>
<p>Bringing your expertise and knowledge to the Ruby community is important. Looking further than just our own little will push us to improve and fulfill the gaps. Let the community know what tools you are missing, the good practices you think we should be following etc&hellip;</p>
<p>Take for instance <a href="https://nodejs.org/">Node.js</a>, it&rsquo;s a port of <a href="https://wiki.github.com/eventmachine/eventmachine/">Ruby&rsquo;s EventMachine</a> / <a href="https://twistedmatrix.com/trac/">Python&rsquo;s twisted</a>. There is no reasons why the Ruby or Python versions could not do what the Javascript version does. However people are getting excited and are jumping ship. What do we do about that? One way would be to identify what makes node more attractive than EventMachine and what needs to be done so we can offer what people are looking for. I asked this question a few weeks ago and the response was that a lot of the Ruby libraries are blocking and having to check is too bothersome. Maybe that&rsquo;s something that the community should be addressing. Node doesn&rsquo;t have that many libraries and people will have to write them, in the mean time we can make our libs non-blocking. Also, let&rsquo;s not forget that this is not a competition and people should choose the best tool for their projects.</p>
<p>Finally, things don&rsquo;t change overnight, as more people encounter the issues you are facing, as we learn from others, part of the community will focus on the problems you are seeing and things will get better. Hopefully, <strong>you</strong> will also be able to contribute and influence the community to build an even better Ruby world.</p>
]]></content>
		</item>
		
		<item>
			<title>object allocation why you should care</title>
			<link>https://matt.aimonetti.net/posts/2010-07-object-allocation-why-you-should-care/</link>
			<pubDate>Thu, 29 Jul 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-07-object-allocation-why-you-should-care/</guid>
			<description>Recently I was tasked with finding how to optimize a web application with heavy traffic. The application (a Rails 2.3.x app) gets about 3 million requests per hour and most of these requests cannot really be easily cached so they go through the entire stack.
This is probably not the case of most web apps out there. None the less, my findings my help you understand Ruby better and maybe think differently about memory management.</description>
			<content type="html"><![CDATA[<p>Recently I was tasked with finding how to optimize a web application with heavy traffic. The application (a Rails 2.3.x app) gets about 3 million requests per hour and most of these requests cannot really be easily cached so they go through the entire stack.</p>
<p>This is probably not the case of most web apps out there. None the less, my findings my help you understand Ruby better and maybe think differently about memory management.</p>
<p>This is certainly not an advanced GC blog post, I will try to keep it as simple as possible. My goal is to show you how Ruby memory allocation works and why it can affect your app performance and finally, how can you avoid to allocate to many objects.</p>
<h2 id="ruby-memory-management">Ruby memory management.</h2>
<p>Rubyists are quite lucky since they don&rsquo;t have to manage the memory themselves. Because developers are lazy and Matz developed his language for people and not machine, memory is managed &ldquo;magically&rdquo;. Programming should be fun and managing memory isn&rsquo;t really considered fun (ask video game developers or iOS programmers ;)).</p>
<p>So in Ruby, the magical memory management is done by a Garbage Collector. The GC&rsquo;s job is to run and free objects that were previously allocated but not used anymore. Without a GC we would saturate the memory available on the host running the program or would have to deallocate the memory manually. Ruby&rsquo;s GC uses a conservative, stop the world, mark-and-sweep collection mechanism.  More simply, the garbage collection runs when the allocated memory for the process is maxed out. The GC runs and blocks all code from being executed and will free unused objects so new objects can be allocated.</p>
<p>Joe Damato did a great talk on that matter during last RailsConf</p>
<p><a href="https://www.scribd.com/doc/32718051/Garbage-Collection-and-the-Ruby-Heap">Garbage Collection and the Ruby Heap</a></p>
<p>The problem is that Ruby&rsquo;s GC was not designed to support hundred thousand objects allocation per second. Unfortunately, that&rsquo;s exactly what frameworks like Ruby on Rails do, and you might contribute to the problem too without even knowing it.</p>
<h2 id="does-it-really-matter">Does it really matter?</h2>
<p>I believe it does. In my case improving the object allocation means much better response time, less servers, less support and less headaches. You might think that servers are cheaper than developers. But more servers mean more developer time spent fixing bugs and more IT support. That&rsquo;s why I think, memory management is something Ruby developers should be aware of and should take in consideration, especially the ones writing frameworks, libraries or shared code.</p>
<p>I am using Ruby 1.9 so I could not profile my Rails 2.x app using <a href="https://memprof.com/">memprof</a>, instead I wrote a <a href="https://github.com/mattetti/GC-stats-middleware">simple and basic middleware</a> that keeps track of the memory allocation/deallocation and GC cycles during a web request (Ruby1.9 only). One of my simple Rails2 actions (1 DB call, simple view) is allocating 170,000 objects per requests. Yes, you read right: 170k objects every single request. At 3 million requests/hour, you can imagine that we are spending a LOT of time waiting for the GC. This is obviously not 100% Rails fault as I am sure our code is contributing to the problem. I heard from the memprof guys that Rails was allocating 40k objects. I decided to check Rails3.</p>
<p>After warming up, a basic Rails3 &lsquo;hello world&rsquo; app clocks at about <strong>8,500 objects allocated per request</strong>, forcing the GC to run more or less every 6 requests. On my machine (mac pro) the GC takes about 20ms to free the objects. A Rack &lsquo;hello world&rsquo; app clocks at <strong>7 objects</strong> per request and a Sinatra app at <strong>181 objects</strong>. Of course you can&rsquo;t really compare these different libraries/frameworks but that gives you an idea of the price you pay to get more features.</p>
<p>One thing to remember is that the more objects you allocate, the more time you &ldquo;lose&rdquo; at code execution. For more developers, it probably doesn&rsquo;t matter much, but if you should still understand that concept especially if you decide to contribute to the OSS community and offer patches, libraries, plugins etc&hellip;</p>
<h1 id="what-can-i-do">What can I do?</h1>
<p>Be aware that you are allocating  objects, for instance something as simple as 100.times{ &lsquo;foo&rsquo; } allocates 100 string objects (strings are mutable and therefore each version requires its own memory allocation).</p>
<p>Make sure to evaluate the libraries you use, for instance switching a Sinatra XML rendering action from Builder to Nokogiri XML Builder saved us about 12k object allocations (Thanks Aaron Patterson). Make sure that **if **you are using a library allocating a LOT of objects, that other alternatives are not available and your choice is worth paying the GC cost. (you might not have a lot of requests/s or might not care for a few dozen ms per requests). You can use memprof or one of the many existing tools to check on the GC cycles using load tests or in dev mode. Also, be careful to analyze the data properly and to not only look at the first request. <a href="https://twitter.com/akeem">Someone</a> sent me <a href="https://memprof.com/dump/4c52503c7fdeb62cff000001">this memory dump</a> from a Rails3 &lsquo;hello world&rsquo; with Ruby 1.8.7 and it shows that Rails is using <a href="https://memprof.com/dump/4c52503c7fdeb62cff000001/detail?where=%7B%7D">331973 objects</a>.  While this is totally true, it doesn&rsquo;t mean that 330k objects are created per request. Instead that means that 330k objects are currently in memory. Rubygems loading already allocate a lot of objects, Rails even more but these objects won&rsquo;t be GC&rsquo;d and don&rsquo;t matter as much as the ones allocated every single request. The total amount of memory used by a Ruby process isn&rsquo;t that important, however the fluctuation forcing the GC to run often is. This is why my middleware only cares about the allocation change during a request. (The GC should still traverse the entire memory so, smaller is better)</p>
<p>The more object allocation you do at runtime/per request, the more the GC will need to run, the slower your code will be. So this is not a question of memory space, but more of performance. If your framework/ORM/library/plugin allocates too many objects per request maybe you should start by reporting the problem and if you can, offer some patches.</p>
<p>Here are some hints about memory allocation:</p>
<p>Creating a hash object really allocates more than an object, for instance {&lsquo;joe&rsquo; =&gt; &lsquo;male&rsquo;, &lsquo;jane&rsquo; =&gt; &lsquo;female&rsquo;} doesn&rsquo;t allocate 1 object but 7. (one hash, 4 strings + 2 key strings) If you can use symbol keys as they won&rsquo;t be garbage collected. However because they won&rsquo;t be GC&rsquo;d you want to make sure to not use totally dynamic keys like converting the username to a symbol, otherwise you will &lsquo;leak&rsquo; memory.</p>
<p>Looking at a GC cycle in the Rails3 hello world example shows what objects get deallocated:</p>
<blockquote>
<p>GC run, previous cycle was 6 requests ago.</p>
</blockquote>
<p>GC 203 invokes. (amount of cycles since the program was started)
Index   1</p>
<p>Invoke Time(sec)   25.268</p>
<p>Use Size(byte)   4702440</p>
<p>Total Size(byte)   7307264</p>
<p>Total Object   182414</p>
<p>GC Time(ms) 22.35600000000204090611</p>
<h2 id="56322-freed-objects">56322 freed objects.</h2>
<p><strong>[78%] 44334 freed strings.</strong>
<strong>[7%] 4325 freed arrays.</strong>
[0%] 504 freed bignums.
[1%] 613 freed hashes.
[0%] 289 freed objects.
<strong>[5%] 3030 freed parser nodes (eval usage).</strong></p>
<p>I did not list all the object types but it&rsquo;s pretty obvious that the main issue in the case of Rails is string allocation. To a certain extend the allocated arrays and the runtime use of eval are not helping either. (what is being eval&rsquo;d at runtime anyway?)</p>
<p>If you use the same string in various place of you code, you can &ldquo;cache&rdquo; them using a local var, instance variable, class variable or constant. Sometimes you can just replaced them by a symbol and save a few allocations/deallocations per request. Whatever you do tho, make sure there is a real need for it. My rule of thumb is that if some code gets exercised by 80% of the requests, it should be really optimized and avoid extra allocations so the GC won&rsquo;t slow us down.</p>
<h2 id="what-about-a-better-gc">What about a better GC?</h2>
<p>That&rsquo;s the easy answer. When I mentioned this problem with Rails, a lot of people told me that I should use JRuby or Rubinius because their GC were much better. Unfortunately, that&rsquo;s not that simple and choosing an alternative implementation requires much further research and tests.</p>
<p>But what annoys me with this solution is that using it is not solving the issue, it&rsquo;s just working around it. Yes, Ruby&rsquo;s GC isn&rsquo;t that great but that&rsquo;s the not the key issue, <strong>the key issue is that some libraries/frameworks allocate way too many objects</strong> and that nobody seems to care (or to even know it). I know that the Ruby Core Team is working on some optimizations and I am sure Ruby will eventually get an improved GC. In the meantime, it&rsquo;s easy to blame Matz, Koichi and the rest of the core team but again, it&rsquo;s ignoring that the root cause, totally uncontrolled memory allocation.</p>
<p><strong>Maybe it&rsquo;s time for us, Rubyists, to think a bit more about our memory usage.</strong></p>
]]></content>
		</item>
		
		<item>
			<title>au revoir rails community</title>
			<link>https://matt.aimonetti.net/posts/2010-06-au-revoir-rails-community/</link>
			<pubDate>Fri, 04 Jun 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-06-au-revoir-rails-community/</guid>
			<description>Time really flies!
Back in December 2005, Ruby on Rails 1.0 was released to the masses. I remember that was when I first got interested in Rails. Six months later, I was doing Rails development full time.
Rails pushed me to contribute to the project, to write plugins, to improve my Ruby knowledge, to release gems and to become a better engineer overall. I then joined the Merb project, focusing on problems I was facing in the various client projects I had back then.</description>
			<content type="html"><![CDATA[<p>Time really flies!</p>
<p>Back in December 2005, Ruby on Rails 1.0 was released to the masses. I remember that was when I first got interested in Rails. Six months later, I was doing Rails development full time.</p>
<p>Rails pushed me to contribute to the project, to write plugins, to improve my Ruby knowledge, to release gems and to become a better engineer overall. I then joined the <a href="https://merbivore.com">Merb project</a>, focusing on problems I was facing in the various client projects I had back then.</p>
<p>The competition between Rails and Merb turned into a constant confrontation, splitting the Ruby community into two camps. A resolution was later achieved by merging the two teams and focusing our energy on Rails 3. This is how I became a part of the Activism team with <a href="https://blog.envylabs.com/">Gregg</a> and <a href="https://railscasts.com/">Ryan</a>. In this new role I was given the opportunity to meet lots of different people from various backgrounds and different communities. I really had a lot of fun.</p>
<p>However, things have changed for me. I won&rsquo;t be at Rails Conf 2010 because in a few weeks I will become a father for the first time. And with that, an obvious priority shift. My day job working on <a href="https://community.modnation.com/">Playstation games</a> is also quite time consuming and the little free time I manage to get to work on my own projects is spent on my <a href="https://macruby.labs.oreilly.com/">MacRuby book</a>. The disconnect between the Rails community and myself is probably more evident now than ever. The challenges encountered by most Railists are so different from the ones I face daily that I think others would do a much better job than I at advocating for Rails. So this is why I believe it&rsquo;s time for me to step away from the Rails community, kick back and relax (and get ready to change a lot of diapers).</p>
<p>This is an &ldquo;<a href="https://www.merriam-webster.com/dictionary/au+revoir">au revoir</a>&rdquo;, not an &ldquo;<a href="https://www.merriam-webster.com/dictionary/adieu">Adieu</a>&rdquo;. I will continue to keep an eye on Rails 3 and the fast growing ecosystem.</p>
<p>I will still be writing Ruby for a living and will hopefully keep contributing to the projects I use. And I plan to keep on attending to Ruby conferences around the world just as soon as my kid is old enough to travel with me ;)</p>
<p>Finally, with the imminent release of Rails 3, I hope to see even more people stand up and advocate for Ruby on Rails the way Gregg Pollack, Ryan Bates and many others have done so far.</p>
]]></content>
		</item>
		
		<item>
			<title>writing an open licensed book</title>
			<link>https://matt.aimonetti.net/posts/2010-05-writing-an-open-licensed-book/</link>
			<pubDate>Sun, 09 May 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-05-writing-an-open-licensed-book/</guid>
			<description>To celebrate last week&amp;rsquo;s release of MacRuby 0.6, O&amp;rsquo;Reilly and I started publishing the draft of my MacRuby book online: https://macruby.labs.oreilly.com/
I started thinking about working on &amp;ldquo;MacRuby: The Definitive Guide&amp;rdquo; last year when I realized that the project had a great future but there was a serious lack of documentation. With the support of the MacRuby team, I worked on a table of contents and a pitch. The next step was to decide what we wanted to do with the book.</description>
			<content type="html"><![CDATA[<p>To celebrate last week&rsquo;s release of <a href="https://www.macruby.org/blog/2010/04/30/macruby06.html">MacRuby 0.6</a>, O&rsquo;Reilly and I started publishing the draft of my MacRuby book online: <a href="https://macruby.labs.oreilly.com/">https://macruby.labs.oreilly.com/</a></p>
<p>I started thinking about working on &ldquo;<a href="https://macruby.labs.oreilly.com/">MacRuby: The Definitive Guide</a>&rdquo; last year when I realized that the project had a great future but there was a serious lack of documentation. With the support of the MacRuby team, I worked on a table of contents and a pitch. The next step was to decide what we wanted to do with the book.</p>
<p>I know a lot of technical book authors and most of them will tell you the same thing: if you think that you are going to make money writing a book, you are wrong. Even if your book sells well, because of the time invested in writing the book, you are probably better off doing consulting work and charging by the hour.</p>
<p>So since day one, I knew that this project would not make me rich. The goal was to share knowledge not to reimburse my mortgage or save California from bankruptcy. While publishing a web book is great, distribution is quite limited, especially if you try to reach people outside of your network. That&rsquo;s why I decided to start talking to a few publishers. Most publishers I talked to were interested in working on the book, however they were not really keen on publishing a <a href="https://creativecommons.org/licenses/by-nc-nd/3.0/us/">Creative Commons Attribution-Noncommercial-No Derivative</a> licensed book.</p>
<p>Let me explain why I think releasing technical books under a CC license is important. As you might know (or have figured out by now), I am not a native English speaker. I actually learned my first English words thanks to the computer my dad had at home. The problem when you don&rsquo;t live in an English speaking country and you want to learn about the cutting edge technology is that you have to understand English.  Thanks to the Internet, learning and practicing English is now much easier that it used to be. However, if you want to have access to books, most of the time you have to wait until someone translates the book and publishes it in your country or you have to manage to get an English version delivered to your country. This is often a pain because of national credit card limitations, international delivery restrictions etc&hellip; If you manage to find a way to get a copy, the book ends up costing a lot of money.</p>
<p>What does that mean in practice? Most of the technical books are first available in the English speaking western world, then slowly translated and/or distributed around the world. By the time you get a legal copy in Bolivia, Algeria or Vietnam, a new edition is probably out in the US probably because the technology evolved. Maybe that explains some of the book piracy worldwide?</p>
<p>Think about it for a minute: knowledge is power and time is money. And what do we do? We delay knowledge distribution. This is why I am a big fan of the <a href="https://khanacademy.org/">Khan Academy</a> and its awesome free online courses.</p>
<p>Turns out <a href="https://oreilly.com/">O&rsquo;Reilly</a> shares my vision and has already published a lot of books under various open licenses: <a href="https://oreilly.com/openbook/">https://oreilly.com/openbook/</a> I was also interested in publishing the content of my book ASAP so people could access it right away even though there would be lots of typos and missing content. This is also something O&rsquo;Reilly has already done with the <a href="https://books.couchdb.org/relax/">CouchDB</a> and the <a href="https://labs.oreilly.com/ofps.html">Scala</a> books.</p>
<p>Talking with <a href="https://twitter.com/janl">Jan Lehnardt</a> about his experience working with O&rsquo;Reilly on the <a href="https://books.couchdb.org/relax/">&lsquo;CouchDB: The definitive guide&rsquo;</a> book, I realized that we seem to have some shared interests. I contacted Jan&rsquo;s editor and we decided to start working on the MacRuby book. The book will be available later on in all the usual commercial formats and I hope people will show their support so O&rsquo;Reilly will be encouraged in their choice to continue publishing CC licensed book. At the end of the day, purchasing a CC licensed book helps supporting the authors, the publishers but also all the people who can&rsquo;t have access to the latest technical books.</p>
<p>Finally, working on a book is not an easy thing, especially when you have to write it in a language that&rsquo;s not yours. But I have to say that the community support has been amazing. Even <a href="https://daringfireball.net/linked/2010/05/03/macruby-aimonetti">John Gruber sent a fireball my way</a>. And since the announcement was made, I have received a lot of <a href="https://macruby.labs.oreilly.com/comments/feed?id=book">comments</a>, tweets, emails etc&hellip; It is very encouraging and it gives me the motivation needed to work on the book after a long work day.</p>
]]></content>
		</item>
		
		<item>
			<title>apples ruby macruby</title>
			<link>https://matt.aimonetti.net/posts/2010-04-apples-ruby-macruby/</link>
			<pubDate>Sun, 11 Apr 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-04-apples-ruby-macruby/</guid>
			<description>During ConFoo Canada 2010 in Montreal, Canada Matt Aimonetti gave a talk entitled {{ Apple&amp;rsquo;s Ruby: MacRuby }}.
##Description of the talk:
For many years, Apple has been shipping its OS with Ruby. But starting about two years ago, Apple started developing their own Ruby implementation on top of Objective-C runtime for performance and compatibility reasons. A developer can already write a fully native and compiled Cocoa application only using the Ruby language and the Cocoa API.</description>
			<content type="html"><![CDATA[<p>During <a href="https://confoo.ca/">ConFoo Canada 2010</a> in Montreal, Canada Matt
Aimonetti gave a talk entitled <em>{{ Apple&rsquo;s Ruby:  MacRuby }}</em>.</p>
<p>##Description of the talk:</p>
<p>For many years, Apple has been shipping its OS with Ruby. But starting about two years ago, Apple started developing their own Ruby implementation on top of Objective-C runtime for performance and compatibility reasons. A developer can already write a fully native and compiled Cocoa application only using the Ruby language and the Cocoa API. But MacRuby is more than an Objective-C replacement, it allows developers to push the traditional boundaries of desktop/mobile applications &amp; games by offering easy integration of web services, creation of p2p application, native GUI for backends web application, reuse of code and much more.</p>
<p>During his talk, Matt Aimonetti, MacRuby team member, will explain the state of the project, its goal and potential as well as show concrete examples of how to use this powerful new Ruby implementation.</p>
<p>##Slides</p>
<p>Slides are not currently available.</p>
<p>##Presentation&rsquo;s website</p>
<p><a href="https://confoo.ca/en/2010/session/apple-s-ruby-macruby">Presentation&rsquo;s website</a> contains limited information about the talk.
An interview with other developers was filmed during the conference and
is available <a href="https://www.youtube.com/watch?v=SKB4Re12fII">there</a>. Note
that the interviewed group speaks in French.
The talk itself wasn&rsquo;t recorded.</p>
]]></content>
		</item>
		
		<item>
			<title>confoo dot ca rails for non ruby developers</title>
			<link>https://matt.aimonetti.net/posts/2010-04-confoo-dot-ca-rails-for-non-ruby-developers/</link>
			<pubDate>Sun, 11 Apr 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-04-confoo-dot-ca-rails-for-non-ruby-developers/</guid>
			<description>During ConFoo Canada 2010 in Montreal, Canada Matt Aimonetti gave a talk entitled Rails for the non Ruby developers.
##Description of the talk:
Unless you have been living on a different planet for the last few years, you have more than likely heard of Ruby on Rails. You have probably heard good and bad things about it, and might even have watched some of the famous screencasts. The thing is, you don&amp;rsquo;t really know that much about Ruby and are not sure that it is worth learning yet another programming language and a new framework.</description>
			<content type="html"><![CDATA[<p>During <a href="https://confoo.ca/">ConFoo Canada 2010</a> in Montreal, Canada Matt
Aimonetti gave a talk entitled <em>Rails for the non Ruby developers</em>.</p>
<p>##Description of the talk:</p>
<p>Unless you have been living on a different planet for the last few years, you have more than likely heard of Ruby on Rails.
You have probably heard good and bad things about it, and might even have watched some of the famous screencasts.
The thing is, you don&rsquo;t really know that much about Ruby and are not sure that it is worth learning yet another programming language and a new framework.
With companies like Apple, Microsoft and Sun investing in Ruby, you might be surprised by how easy the transition can be.</p>
<p>Matt will show you the pros and cons of using Rails. He&rsquo;ll go through some of the myths around the framework and explain why it might be a better fit than you would expect.</p>
<p>##Slides</p>
<p>Slides are not currently available.</p>
<p>##Presentation&rsquo;s website</p>
<p><a href="https://confoo.ca/en/2010/session/rails-for-non-ruby-developers">Presentation&rsquo;s website</a> contains limited information about the talk.
An interview with other developers was filmed during the conference and
is available <a href="https://www.youtube.com/watch?v=SKB4Re12fII">there</a>. Note
that the interviewed group speaks in French.
The talk itself wasn&rsquo;t recorded.</p>
]]></content>
		</item>
		
		<item>
			<title>i did it wrong</title>
			<link>https://matt.aimonetti.net/posts/2010-03-i-did-it-wrong/</link>
			<pubDate>Mon, 15 Mar 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-03-i-did-it-wrong/</guid>
			<description>The Ruby community is a well known for at least two things: **being passionate and being **arrogant . Two characteristics that often go together but I am not going to defend or justify anything in this post, instead I will try to reflect on my own experience and will share with you my own view point.

Very much like the Ruby community, I am also quite passionate and can be arrogant at times.</description>
			<content type="html"><![CDATA[<p>The Ruby community is a well known for at least two things: **being <strong><a href="https://pragprog.com/press_releases/the-passionate-programmer">passionate</a></strong> and being **<a href="https://www.bruisin-ales.com/beerblog/wp-content/uploads/2008/09/stoneintro.gif">arrogant</a> .
Two characteristics that often go together but I am not going to defend or justify anything in this post, instead I will try to reflect on my own experience and will share with you my own view point.</p>
<p><a href="https://merbist.com/wp-content/uploads/2010/03/doing_wrong_coaster_2.jpg"><img src="https://merbist.com/wp-content/uploads/2010/03/doing_wrong_coaster_2-225x300.jpg" alt=""></a></p>
<p>Very much like the Ruby community, I am also quite passionate and can be arrogant at times. A few months back I was in Brazil for <a href="https://www.railssummit.com.br/en/pages/home">RailsSummit</a> and I was chatting with <a href="https://twitter.com/dchelimsky">David Chelimsky</a> after a nice evening with the <a href="https://www.railssummit.com.br/en/pages/home">RailsSummit</a> attendees. I was thinking about how cool it was to have people from various non-Ruby communities to come to a Ruby community and share their experience and knowledge while observing the ways we do things with Ruby.</p>
<p>David and I got to talk about technical evangelism, how <a href="https://rspec.info/">RSpec</a> became very popular, the whole <a href="https://en.wikipedia.org/wiki/Merb">Merb</a> vs <a href="https://rubyonrails.org/">Rails</a> situation which turned into Rails3, as well as <a href="https://www.macruby.org/">MacRuby</a> and <a href="https://www.apple.com/">Apple</a>. I was interested by the fact that I couldn&rsquo;t remember David ever saying something bad about test/unit or trying to tell others they were doing it wrong. Instead, he has always tried showing why people might be potentially interested by <a href="https://en.wikipedia.org/wiki/RSpec">RSpec</a>.</p>
<p>As an early RSpec adopter, I often thought that people were wrong not to use the solution that <em><strong>I</strong></em> thought was the best. As part of the Merb &lsquo;propaganda&rsquo;, we spent a lot of time comparing Merb with Rails and showing why Merb might be better for you and why you were doing it wrong if you would fit in Merb&rsquo;s target and still use Rails.</p>
<p>Even before that, I remember thinking that if you were not using Ruby, you were doing it wrong. PHP &amp; Java developers were, for me, just developers who did not know any better (and I thought that Python-ers were just too lazy to learn a &ldquo;better&rdquo; language that takes OOP seriously ;)).</p>
<p><a href="https://merbist.com/wp-content/uploads/2010/03/doing_it_wrong_coaster.jpg"><img src="https://merbist.com/wp-content/uploads/2010/03/doing_it_wrong_coaster-300x218.jpg" alt=""></a></p>
<p>Since then, things have changed. I have gotten involved with other projects, met different people and maybe, just maybe, matured a little bit. Going back to the discussion I had with David, he pointed out to me how often people talk about a piece of technology or an idea to just quickly conclude: <strong>&ldquo;it sucks&rdquo;</strong> and it has got even worse lately with the &lsquo;<a href="https://www.doingitwrong.com/">you&rsquo;re doing it wrong</a> ' meme.</p>
<p>Basically, we judge people&rsquo;s actions without knowing them or even having a clue about the problem they are facing and we just tell them that if they don&rsquo;t do like us, they are wrong. If they are not using this plugin or this gem, they are doing it wrong, and if they are using this other one that sucks, they are also doing it wrong. Also, be careful, something that&rsquo;s hot today will probably turn out to be &lsquo;the suck&rsquo; soon enough, keep up with what the cool kids tweet about ;)</p>
<p>But of course, this is something human and much bigger than the Ruby community. Look at the whole SQL/NoSQL <a href="https://news.ycombinator.com/item?id=1163039">pseudo fight</a> and you will notice the same attitude. Look at the editors war, look at the OS war or even look at the TV with shows like &lsquo;<a href="https://en.wikipedia.org/wiki/The%20Marriage%20Ref">Marriage Ref</a>&rsquo; making money off of people wanting to prove their partner that he/she is doing it wrong. But that&rsquo;s also the root problem of most religion wars and even the motivation for some people to go &lsquo;invade/colonize&rsquo; other countries to eventually force their world vision upon them.</p>
<p>I realize the irony of writing of blog post to tell my readers that telling others that they are doing it wrong is, in itself, fundamental wrong, but maybe next time you think something sucks or is totally wrong, you might want to try to understand the motivation behind why some people decided to go this way. I know I will personally try harder.</p>
]]></content>
		</item>
		
		<item>
			<title>speed up your rails xml responses</title>
			<link>https://matt.aimonetti.net/posts/2010-02-speed-up-your-rails-xml-responses/</link>
			<pubDate>Mon, 22 Feb 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-02-speed-up-your-rails-xml-responses/</guid>
			<description>At work, we have an XML API that gets quite a lot of traffic. Last week I looked into improving its performance since we are expecting more traffic soon and want to make sure our response time is optimized.
My first thought was to make sure we had an optimized ActiveSupport&amp;rsquo;s xmlmini backend. Rails 2.3.5 fixed some issues when using Nokogiri as a xmlmini so I switched to my favorite Ruby XML lib:</description>
			<content type="html"><![CDATA[<p>At <a href="https://www.us.playstation.com/">work</a>, we have an XML API that gets quite a lot of traffic. Last week I looked into improving its performance since we are expecting more traffic soon and want to make sure our response time is optimized.</p>
<p>My first thought was to make sure we had  an optimized <a href="https://api.rubyonrails.org/classes/ActiveSupport/XmlMini.html">ActiveSupport&rsquo;s xmlmini backend</a>. Rails 2.3.5 fixed some issues when using <a href="https://nokogiri.org/">Nokogiri</a> as a xmlmini so I switched to my favorite Ruby XML lib:</p>
<pre><code>ActiveSupport::XmlMini.backend = 'Nokogiri'
</code></pre>
<p>I run some benchmarks using ab, httperf and jmeter but the results were not that great. I was so sure that switching from <a href="https://ruby-doc.org/stdlib/libdoc/rexml/rdoc/index.html">rexml</a> to <a href="https://nokogiri.org/">nokogiri</a> would give me awesome results that I was very disappointed.</p>
<p>I was about to call <a href="https://tenderlovemaking.com/">Aaron Patterson</a> (Nokogiri&rsquo;s author) to insult him, blame him for _why&rsquo;s disappearance and tell him that all his pro bono efforts were useless since my own app was not running much faster when switched to his library. As I was about to dial his number on my iPhone I had a crazy thought&hellip; maybe it was not Aaron&rsquo;s fault, maybe it was mine.</p>
<p>So I took a break went to play some fuzzball and as I was being ridiculed by Italian coworker, Emanuele, I realized that most of our API calls were just simple HTTP requests with no XML payload, just some query params. However, we were generating a lot of XML to send back to the client and AS::XmlMini only takes care of the XML parsing, not the rendering.</p>
<p>The XML rendering is done by <a href="https://onestepback.org/">Jim Weirich</a>&rsquo;s pure Ruby <a href="https://builder.rubyforge.org/">builder library</a> which is vendored in Rails. Builder does a good job, but I thought that maybe a C based library might improve the speed. A coworker of mine (James Bunch) recommended to look into <a href="https://github.com/codahale/faster-builder">faster-builder</a>, a drop-in Builder replacement based on libxml. Unfortunately, the project doesn&rsquo;t seem to be maintained and I decided to look into using <a href="https://nokogiri.org/">Nokogiri</a> XML builder instead. (Also, faster-builder&rsquo;s author doesn&rsquo;t like me very much while Aaron knows he&rsquo;s one of my Ruby heroes so asking for help could be easier)</p>
<p>Some people reported having tried using <a href="https://nokogiri.org/">Nokogiri</a> as a XML builder but didn&rsquo;t see much speed improvement. Because of the amount of magic required to render a rxml template, I was not really surprised but I decided to contact Aaron and ask him if he tried using his lib instead of builder in a Rails app. <a href="https://www.flickr.com/photos/aaronp/57241193/">Aaron</a> told me he gave it a try a while back and he helped me get my Rails app setup to render xml templates using <a href="https://nokogiri.org/">Nokogiri</a>.</p>
<p>The next step was simple, create a <a href="https://github.com/mattetti/noko-vs-builder-benchmark">benchmark app</a> and benchmark Builder vs Nokogiri using various templates. Here are the results I got using Ruby 1.9.1 (the Ruby version we use in production) and two sets of templates:</p>
<p><strong>Builder</strong> small template, <strong>time per request: 15.507 [ms]</strong> (mean)</p>
<pre><code>$ ab -c 1 -n 200 https://127.0.0.1:3000/benchmarks/builder_small
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, https://www.zeustech.net/
Licensed to The Apache Software Foundation, https://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Finished 200 requests

Server Software:        nginx/0.7.65
Server Hostname:        127.0.0.1
Server Port:            3000

Document Path:          /benchmarks/builder_small
Document Length:        216 bytes

Concurrency Level:      1
Time taken for tests:   3.101 seconds
Complete requests:      200
Failed requests:        0
Write errors:           0
Total transferred:      114326 bytes
HTML transferred:       43200 bytes
Requests per second:    64.49 [#/sec] (mean)
Time per request:       15.507 [ms] (mean)
Time per request:       15.507 [ms] (mean, across all concurrent requests)
Transfer rate:          36.00 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    11   15   8.8     12      47
Waiting:        3   15   8.9     12      47
Total:         11   15   8.8     12      47

Percentage of the requests served within a certain time (ms)
  50%     12
  66%     12
  75%     13
  80%     13
  90%     35
  95%     36
  98%     38
  99%     41
 100%     47 (longest request)
</code></pre>
<p><strong>Nokogiri</strong> small template, <strong>time per request: 15.354 [ms] (mean)</strong></p>
<pre><code>$ ab -c 1 -n 200 https://127.0.0.1:3000/benchmarks/noko_small
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, https://www.zeustech.net/
Licensed to The Apache Software Foundation, https://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Finished 200 requests

Server Software:        nginx/0.7.65
Server Hostname:        127.0.0.1
Server Port:            3000

Document Path:          /benchmarks/noko_small
Document Length:        238 bytes

Concurrency Level:      1
Time taken for tests:   3.071 seconds
Complete requests:      200
Failed requests:        0
Write errors:           0
Total transferred:      118717 bytes
HTML transferred:       47600 bytes
Requests per second:    65.13 [#/sec] (mean)
Time per request:       15.354 [ms] (mean)
Time per request:       15.354 [ms] (mean, across all concurrent requests)
Transfer rate:          37.75 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    11   15   8.6     12      39
Waiting:       11   15   8.6     12      39
Total:         11   15   8.6     12      39

Percentage of the requests served within a certain time (ms)
  50%     12
  66%     12
  75%     12
  80%     13
  90%     35
  95%     36
  98%     37
  99%     38
 100%     39 (longest request)
</code></pre>
<p>Running the benchmarks many times showed that Nokogiri and Builder were taking more or less the same amount of time to builder a small template.</p>
<p>I then decided to try a bigger template, closer to what we have in production, here are the results:</p>
<p><strong>Nokogiri</strong> longer template, <strong>time per request: 31.252 [ms] (mean)</strong></p>
<pre><code>$ ab -c 1 -n 200 https://127.0.0.1:3000/benchmarks/noko
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, https://www.zeustech.net/
Licensed to The Apache Software Foundation, https://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Finished 200 requests

Server Software:        nginx/0.7.65
Server Hostname:        127.0.0.1
Server Port:            3000

Document Path:          /benchmarks/noko
Document Length:        54398 bytes

Concurrency Level:      1
Time taken for tests:   6.250 seconds
Complete requests:      200
Failed requests:        0
Write errors:           0
Total transferred:      10951200 bytes
HTML transferred:       10879600 bytes
Requests per second:    32.00 [#/sec] (mean)
Time per request:       31.252 [ms] (mean)
Time per request:       31.252 [ms] (mean, across all concurrent requests)
Transfer rate:          1711.00 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:    24   31  11.3     26      62
Waiting:       23   30  11.3     24      61
Total:         24   31  11.3     26      62

Percentage of the requests served within a certain time (ms)
  50%     26
  66%     27
  75%     27
  80%     29
  90%     54
  95%     55
  98%     58
  99%     59
 100%     62 (longest request)
</code></pre>
<p><strong>Builder</strong>, longer template, <strong>Time per request: 140.725 [ms] (mean)</strong></p>
<pre><code>$ ab -c 1 -n 200 https://127.0.0.1:3000/benchmarks/builder
This is ApacheBench, Version 2.3 &lt;$Revision: 655654 $&gt;
Copyright 1996 Adam Twiss, Zeus Technology Ltd, https://www.zeustech.net/
Licensed to The Apache Software Foundation, https://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 100 requests
Completed 200 requests
Finished 200 requests

Server Software:        nginx/0.7.65
Server Hostname:        127.0.0.1
Server Port:            3000

Document Path:          /benchmarks/builder
Document Length:        54376 bytes

Concurrency Level:      1
Time taken for tests:   28.145 seconds
Complete requests:      200
Failed requests:        0
Write errors:           0
Total transferred:      10947000 bytes
HTML transferred:       10875200 bytes
Requests per second:    7.11 [#/sec] (mean)
Time per request:       140.725 [ms] (mean)
Time per request:       140.725 [ms] (mean, across all concurrent requests)
Transfer rate:          379.83 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:   127  141  24.6    132     331
Waiting:      126  139  23.6    130     328
Total:        127  141  24.6    132     331

Percentage of the requests served within a certain time (ms)
  50%    132
  66%    138
  75%    147
  80%    149
  90%    156
  95%    169
  98%    193
  99%    311
 100%    331 (longest request)
</code></pre>
<p>Wow, <a href="https://twitter.com/tenderlove">@tenderlove</a>&rsquo;s Nokogori just brought us a** 4.5X speed improvement for this specific template**.  100ms per request is probably not a big deal for most people and I have to say that Jim did a great job with Builder. However in my specific case, 100ms on a request being called thousands of times per hour is quite important.</p>
<p>(The <a href="https://github.com/mattetti/noko-vs-builder-benchmark">benchmark app is available on github</a>, feel free to fork it and benchmark your own templates)</p>
<p>Who would have thought that a man like this could save the day?!</p>
<p>[caption id=&ldquo;attachment_1737&rdquo; align=&ldquo;alignleft&rdquo; width=&ldquo;150&rdquo; caption=&ldquo;Aaron &lsquo;Tenderlove&rsquo; Patterson&rdquo;]<a href="https://railsontherun.com/wp-content/uploads/2010/02/aaron.jpg"><img src="https://railsontherun.com/wp-content/uploads/2010/02/aaron-150x150.jpg" alt=""></a>[/caption]</p>
<p><a href="https://www.flickr.com/photos/aaronp/3824959062/"><img src="https://farm3.static.flickr.com/2470/3824959062_fb0755e665_m_d.jpg" alt=""></a></p>
<p><a href="https://www.flickr.com/photos/aaronp/57241193/"><img src="https://farm1.static.flickr.com/29/57241193_8137f2a4af_m_d.jpg" alt=""></a></p>
<p><a href="https://www.flickr.com/photos/aaronp/3132124227/"><img src="https://farm4.static.flickr.com/3289/3132124227_3ace4ec7ae_m_d.jpg" alt=""></a></p>
<p><strong><em>The moral of the story is that adding a bit of tenderlove to your Ruby code can make it perform much much better!</em></strong></p>
<p><strong>Thank you Aaron &lsquo;Tenderlove&rsquo; Patterson!</strong></p>
]]></content>
		</item>
		
		<item>
			<title>googlecharts 1 5 1</title>
			<link>https://matt.aimonetti.net/posts/2010-02-googlecharts-1-5-1/</link>
			<pubDate>Wed, 03 Feb 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-02-googlecharts-1-5-1/</guid>
			<description>To celebrate the relaunch of this site and since we are waiting for Rails 3.0 beta to be released, I figured I should share with you what I worked on the other night.
I merged patches, refactored and released a new version of googlecharts, my Gem to create graphs using Google Chart API.
sudo gem install googlecharts
Here is a quick example of how the API works when dealing with a complex graph:</description>
			<content type="html"><![CDATA[<p>To celebrate the relaunch of this site and since we are waiting for Rails 3.0 beta to be released, I figured I should share with you what I worked on the other night.</p>
<p>I merged patches, refactored and released a new version of googlecharts, my Gem to create graphs using Google Chart API.</p>
<p><code>sudo gem install googlecharts</code></p>
<p>Here is a quick example of how the API works when dealing with a complex graph:</p>
<pre><code>require 'gchart' # or require 'googlecharts' if you prefer to use the Googlecharts constant.
title = &quot;Player Count&quot;
size = &quot;575x300&quot;
data = [85,107,123,131,155,172,173,189,203,222,217,233,250,239,256,267,247,261,275,295,288,305,322,307,325,347,331,346,363,382,343,359,383,352,374,393,358,379,396,416,377,398,419,380,409,426,453,432,452,465,436,460,480,440,457,474,501,457,489,507,347,373,413,402,424,448,475,488,513,475,507,530,440,476,500,518,481,512,531,367,396,423,387,415,446,478,442,469,492,463,489,508,463,491,518,549,503,526,547,493,530,549,493,520,541,564,510,535,564,492,512,537,502,530,548,491,514,538,568,524,548,568,512,533,552,577,520,545,570,516,536,555,514,536,566,521,553,579,604,541,569,595,551,581,602,549,576,606,631,589,615,650,597,624,646,672,605,626,654,584,608,631,574,597,622,559,591,614,644,580,603,629,584,615,631,558,591,618,641,314,356,395,397,429,450,421,454,477,507,458,490,560,593]
Gchart.line(:title =&gt; title, :size =&gt; size, :data =&gt; data, :axis_with_labels =&gt; 'x,y', :line_color =&gt; '1e60cc', :axis_labels =&gt; [(1.upto(24).to_a &lt;&lt; 1)], :max_value =&gt; 700, :custom =&gt; 'chg=10,15,1,0')
</code></pre>
<p>Which provides you with the url or image tag (or downloaded file) that produces the following graph:</p>
<p><img src="https://chart.apis.google.com/chart?chxl=0:%7C1%7C2%7C3%7C4%7C5%7C6%7C7%7C8%7C9%7C10%7C11%7C12%7C13%7C14%7C15%7C16%7C17%7C18%7C19%7C20%7C21%7C22%7C23%7C24%7C1&amp;chxt=x,y&amp;chco=1e60cc&amp;chg=10,15,1,0&amp;chd=s:HJKLNPPQRTTUWVWXVXYaZbcbcedeghefhfhifhjkhjlhklomopmoqmopsorsehkjlnqrtqsumqstqtvgjliknqnprprsprtwsuwruwruvxtvxrtvsuwrtvyuwytvwzuwytvxtvyuwz1vy0wz1wz130250357135z13y03x025z13z23x024bfijlnloqsorx0&amp;chtt=Player+Count&amp;cht=lc&amp;chs=575x300&amp;chxr=1,85,700" alt="Google Chart"></p>
<p>This release works great with Ruby 1.9 and <a href="https://macruby.org">MacRuby</a>, lots of bugs got fixed and some new features were added. Something a lot of people complained was that the gem was called googlecharts but that the main class was called Gchart. The problem was that I wrote my gem and called it Gchart and when I went to register the rubyforge project page, the name was already taken. In this release, I fixed this problem by allowing users to require and use the constant name they want, Gchart or Googlecharts. I also spent quite a lot of time cleaning up the old code which I was a bit ashamed of. Class variables are now removed and overall, the code should be a bit more sane.</p>
<p>The source code can be found in my <a href="https://github.com/mattetti/googlecharts/">GitHub accout</a> and the documentation <a href="https://mattetti.github.com/googlecharts/">there</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>how and why i joined the suit people</title>
			<link>https://matt.aimonetti.net/posts/2010-02-how-and-why-i-joined-the-suit-people/</link>
			<pubDate>Tue, 02 Feb 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-02-how-and-why-i-joined-the-suit-people/</guid>
			<description>It is now official: I have traded my freedom &amp;amp; home office for a job title, an Aeron chair in a cubicle and a 401K.
I received my new employee package and, in less than a week, I will officially become a full-time employee at SCEA (Sony Computer Entertainment America).
I&amp;rsquo;m going to work in the PlayStation department, working on PS3, PS2 and PSP game titles developed by various game studios.</description>
			<content type="html"><![CDATA[<p>It is now official: I have traded my freedom &amp; home office for a job title, an Aeron chair in a cubicle and a 401K.</p>
<p>I received my new employee package and, in less than a week, I will officially become a full-time employee at <a href="https://en.wikipedia.org/wiki/Sony_Computer_Entertainment_of_America"> SCEA</a> (Sony Computer Entertainment America).</p>
<p>I&rsquo;m going to work in the PlayStation department, working on PS3, PS2 and PSP game titles developed by <a href="https://www.naughtydog.com/">various</a> <a href="https://en.wikipedia.org/wiki/SCE_Studio_San_Diego">game</a> <a href="https://en.wikipedia.org/wiki/Sony_Computer_Entertainment_Worldwide_Studios">studios</a>.</p>
<p><a href="https://merbist.com/wp-content/uploads/2010/02/sony_playstation_32.jpg"><img src="https://merbist.com/wp-content/uploads/2010/02/sony_playstation_32-300x206.jpg" alt=""></a></p>
<h3 id="why-o-why">Why &lsquo;o why?</h3>
<p><em>Why leave behind a happy life of indie contracting to join corporate America?</em></p>
<p>For many reasons actually:</p>
<ul>
<li><strong>A Team</strong></li>
</ul>
<p>Being a consultant I have been working with other independent consultants and existing teams. Nonetheless, I really miss being part of a stable team which grows together and learns from each other as we go through new projects and maintain old ones.</p>
<ul>
<li><strong>Long term plan</strong></li>
</ul>
<p>As a consultant, I usually start projects or &ldquo;rescue&rdquo; existing projects. I work on them for a little while and then move on. It&rsquo;s exciting and rewarding but you don&rsquo;t really pay the consequences of your mistakes. You usually don&rsquo;t have to maintain the code you wrote and you rarely deal with the mistakes <em>you</em> made.</p>
<p>It sounds good, nobody likes to maintain the crappy awesome code they wrote 2 years ago and most developers love working on new stuff. But at the same time, to become a better engineer you need to learn from you mistakes and assuming responsibility for your bad decisions is part of the process.</p>
<p>It might sound weird, but I&rsquo;m actually excited to work on long term projects and feel some sort of ownership over the projects. Having to support games for many years means that I&rsquo;d better not mess up the implementation. And if I do, I hope I&rsquo;ll quickly learn from my mistakes.</p>
<ul>
<li><strong>Avoiding burn out</strong></li>
</ul>
<p>There is no secret: when you are passionate about what you do, you have a hard time stopping and taking a break. I&rsquo;m a recovering workaholic and it&rsquo;s really hard for me to say no when I&rsquo;m presented the possibility to work on interesting projects. I love what I do and I keep writing code even after I&rsquo;m done with client work.</p>
<p>The problem is that this can start me on the slippery slope to isolating myself from friends, family and people who don&rsquo;t share the same passion. I&rsquo;m really lucky that my wife is a geek and loves hanging out at conferences, looking at code and playing with my buggy prototypes. But still, I spend too much time &ldquo;playing&rdquo; with my computer and I just can&rsquo;t manage my free time wisely.</p>
<p>Having a full time position will hopefully help me put boundaries and will hopefully teach me to disconnect from work.</p>
<ul>
<li><strong>Exciting projects</strong></li>
</ul>
<p>Hey, let&rsquo;s be honest, how many geeks do you know don&rsquo;t want to work in the video game industry? By the way, if you don&rsquo;t have a PS3, they are now at $299 and on top of getting an awesome console you get a blue ray player! (And no, I do not receive any bonuses or commissions for mentioning the console or promoting it in my blog. I had to pay for my own like everyone else.)</p>
<h3 id="corporate-america-are-you-going-to-write-java-now">Corporate America? Are you going to write Java now?</h3>
<p><img src="https://farm2.static.flickr.com/1412/1264424156_24f4571b10.jpg" alt=""></p>
<p>No, I&rsquo;m mainly going to stick to the language I love: <strong>Ruby</strong>.
From time to time I will probably use other languages here and there, but that usually makes me love Ruby even more. The reality is that Ruby&rsquo;s power and flexibility seem to be appreciated by SCEA, which makes sense when you have tight deadlines and a lot of new technologies to deal with. Ruby is a perfect match!</p>
<p>As you can guess, I can&rsquo;t go into any detail about how and why Sony uses Ruby, but let me just say that while games are still usually written in C++, they are becoming more and more interactive and need to communicate with game servers where some logic operates. Game players also need to interact with other gamers as well as check their gaming progress online, as well as the progress of the players around them etc&hellip; Basically, outside of the game engine and the console SDK, there is a lot of potential for Ruby.</p>
<p>Coming back to Corporate America, I have to say that I&rsquo;ve known my future manager for a few years now. He&rsquo;s always been a fervent Ruby advocate and has introduced lots of teams to the happiness of Ruby &amp; Rails development. He&rsquo;s also a great developer who&rsquo;s contributing patches to major projects and has a bunch of cool stuff on github. To give you an idea, my job description mentions Rails, Merb, Sinatra, CouchdB, MongoDB, Redis, AWS. All these Ruby technologies are actually already used in production or are being seriously evaluated.</p>
<p>I&rsquo;m also really looking forward to join the existing team. I know I&rsquo;m going to love working with a bunch of awesome developers coming from various backgrounds.</p>
<p>Those who know me, know that I&rsquo;m not a morning person. And while your typical office job is categorized as &lsquo;9-5&rsquo;, don&rsquo;t feel too bad for me. I will be joining the video game product department, and morning people are rather rare in these kinds of groups ;)</p>
<h3 id="conclusion">Conclusion</h3>
<p>I&rsquo;m really excited about this opportunity. For me, it is proof again that the Ruby revolution took place and that the Enterprise is evolving. Of course, time will tell if I am right, but I am quite confident.</p>
<p>Also, Sony is always looking for new, talented people who want to push the entertainment world to the next level. Feel free to keep in touch with me if you are interested in joining the fun.</p>
]]></content>
		</item>
		
		<item>
			<title>undoredo in macruby</title>
			<link>https://matt.aimonetti.net/posts/2010-02-undoredo-in-macruby/</link>
			<pubDate>Tue, 02 Feb 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-02-undoredo-in-macruby/</guid>
			<description></description>
			<content type="html"><![CDATA[]]></content>
		</item>
		
		<item>
			<title>macruby 0 5 final is out</title>
			<link>https://matt.aimonetti.net/posts/2010-01-macruby-0-5-final-is-out/</link>
			<pubDate>Sun, 31 Jan 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-01-macruby-0-5-final-is-out/</guid>
			<description>After going through two betas, MacRuby 0.5 final is now released and can be downloaded by clicking on the icon below:
MacRuby 0.5
Don&amp;rsquo;t worry about having MacRuby and Ruby 1.8.x or 1.9 installed, MacRuby is namespaced and won&amp;rsquo;t affect your current Ruby installations, just download and launch the installer. (Note: The build was compiled for SnowLeopard only)
You can read all the details of the release on the MacRuby website.</description>
			<content type="html"><![CDATA[<p>After going through two betas, MacRuby 0.5 final is now released and can be downloaded by clicking on the icon below:</p>
<p><a href="https://macruby.org/downloads.html"><img src="https://macruby.org/images/zip.png" alt="">
MacRuby 0.5</a></p>
<p>Don&rsquo;t worry about having MacRuby and Ruby 1.8.x or 1.9 installed, MacRuby is namespaced and won&rsquo;t affect your current Ruby installations, just download and launch the installer. (Note: The build was compiled for SnowLeopard only)</p>
<p>You can read all the <a href="https://www.macruby.org/blog/2010/01/31/macruby05.html">details of the release on the MacRuby website</a>.</p>
<p>So what changed since 0.4? Too many things for me to list them here but basically 0.5 uses LLVM to compile code and make MacRuby faster and integrate better with the Obj-c runtime. However since the last beta, here is what changed:</p>
<ul>
<li>
<p>HotCocoa is now a separate gem</p>
</li>
<li>
<p>improved AOT compilation</p>
</li>
<li>
<p>Grand Central Dispatch support - use all your cores without the pain of threads. Read <a href="https://www.macruby.org/documentation/gcd.html">this post</a> for more info.</p>
</li>
</ul>
<p>0.5 is a solid release which I consider production ready, I personally wrote a few of small Cocoa apps in MacRuby and everything has been working very well. Of course, I&rsquo;m also excited about the new stuff in 0.6 trunk like the debugger previewed a few weeks ago: <a href="https://merbist.com/2010/01/18/how-to-detect-cylons-with-macruby/">https://merbist.com/2010/01/18/how-to-detect-cylons-with-macruby/</a> but also some drastic changes in the primitive classes that I might cover later on.</p>
<p>Finally, people are asking if the iPad will be able to run apps running in MacRuby. Unfortunately, the current answer is: no. The two issues with the IPhone/iP*d OS are the lack of Garbage Collector and support for BridgeSupport (needed to define CocoaTouch constants available from MacRuby). However, this matter is being discussed on the mailing list and progress is made by contributors (the core team primarily focusing on the desktop).</p>
<p>That is going to be an exciting Ruby week as MacRuby 0.5 is now out and Rails 3 beta/RC0 is expected really soon.</p>
]]></content>
		</item>
		
		<item>
			<title>how to detect cylons with macruby</title>
			<link>https://matt.aimonetti.net/posts/2010-01-how-to-detect-cylons-with-macruby/</link>
			<pubDate>Mon, 18 Jan 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-01-how-to-detect-cylons-with-macruby/</guid>
			<description>Over the weekend, MacRuby&amp;rsquo;s trunk became version 0.6 and the bug fixing is currently done in both the 0.5 branch and trunk. Based on MacRuby&amp;rsquo;s usual release cycle I would expect a 0.5 beta3 or 0.5 final to be released soon so most of the work can be focused on trunk.
I&amp;rsquo;ll let you check on the TODO list to see what was done in 0.5 and what is in the plan for 0.</description>
			<content type="html"><![CDATA[<p>Over the weekend, MacRuby&rsquo;s trunk became version 0.6 and the bug fixing is currently done in both the 0.5 branch and trunk. Based on MacRuby&rsquo;s usual release cycle I would expect a 0.5 beta3 or 0.5 final to be released soon so most of the work can be focused on trunk.</p>
<p>I&rsquo;ll let you check on the <a href="https://svn.macosforge.org/repository/ruby/MacRuby/trunk/TODO">TODO list</a> to see what was done in 0.5 and what is in the plan for 0.6.</p>
<p>However, there is one feature in 0.6 that I know lots of you will just love! The good news is that Laurent already committed a very early version of his work so I figured, I should share the good news with you:</p>
<h3 id="introducing-macrubys-debugger">Introducing MacRuby&rsquo;s debugger!</h3>
<p>If you were expecting to read: &ldquo;a Cylon detector!&rdquo;, keep on reading.</p>
<p>Again, this feature is in really early development since it&rsquo;s scheduled for 0.6 and 0.5 final is not out yet. But if you install MacRuby using the <a href="https://macruby.icoretech.org/">nightly builds</a> or build from trunk, you can already play with the debugger.</p>
<p>Let me give you a really quick tour of the debugger.</p>
<p><img src="https://img.skitch.com/20100118-qn7yuq9h2ce61yxt6kwag9pnbt.jpg" alt="BSG75Logo posted by Matt Aimonetti"></p>
<p>Let&rsquo;s imagine that we were given the task to debug the cylon detector written by Gaius Baltar which looks like that:</p>
<pre><code>characters = %w{Adama Apollo Baltar Roslin StarBuck Six}

def cylon?(character)
  false
end

characters.each do |character|
  if cylon?(character)
    puts &quot;#{character} is a Cylon!&quot;
  else
    puts &quot;#{character} is not a cylon.&quot;
  end
end
</code></pre>
<p>Here is what happens when I execute the script:</p>
<pre><code>$ macruby cylon_detector.rb
Adama is not a cylon.
Apollo is not a cylon.
Baltar is not a cylon.
Roslin is not a cylon.
StarBuck is not a cylon.
Six is not a cylon.
</code></pre>
<p>The only problem is that we all know that Six is a Cylon, the detector isn&rsquo;t working right so let&rsquo;s debug it:</p>
<pre><code>$ macrubyd cylon_detector.rb
Starting program.
cylon_detector.rb:1&gt; b cylon_detector.rb:8 if character == 'Six'
Added breakpoint 1.
cylon_detector.rb:1&gt; c
Adama is not a cylon.
Apollo is not a cylon.
Baltar is not a cylon.
Roslin is not a cylon.
StarBuck is not a cylon.
cylon_detector.rb:8&gt; p cylon?(character)
=&gt; false
cylon_detector.rb:8&gt; p &quot;This detector is broken!&quot;
=&gt; &quot;This detector is broken!&quot;
cylon_detector.rb:8&gt; p def cylon?(character); character == 'Six'; end
=&gt; nil
cylon_detector.rb:8&gt; p cylon?(character)
=&gt; true
cylon_detector.rb:8&gt; p cylon?('Matt')
=&gt; false
cylon_detector.rb:8&gt; c
Six is a Cylon!
Program exited.
</code></pre>
<p>The first thing we do is to add a conditional breakpoint:</p>
<pre><code>b cylon_detector.rb:8 if character == 'Six'
</code></pre>
<p>Basically, the debugger will add a breakpoint at line 8 which will only be active when the value of &lsquo;character&rsquo; is equal to &lsquo;Six&rsquo;.
Now that the breakpoint added, we can continue the program execution and just wait until we reach the defined condition.</p>
<pre><code>cylon_detector.rb:1&gt; c
</code></pre>
<p>Once we reach the breakpoint, we evaluate the result of &ldquo;cylon?(character)&rdquo; by using the p command. We see that the result is &ldquo;false&rdquo; when we know for sure that it should be true since the value of the character variable is &lsquo;Six&rsquo; and she is a cylon. At this point, you might have guessed that somewhat acted as a cylon agent and I pretended to fix the problem by overwriting the &ldquo;cylon?&rdquo; method:</p>
<pre><code>cylon_detector.rb:8&gt; p def cylon?(character); character == 'Six'; end
</code></pre>
<p>Now that the method is overwritten, I can check that Six is recognized as being a cylon:</p>
<pre><code>cylon_detector.rb:8&gt; p cylon?(character)
=&gt; true
</code></pre>
<p>and also check that I am not detected a cylon:</p>
<pre><code>cylon_detector.rb:8&gt; p cylon?('Matt')
=&gt; false
</code></pre>
<p>I can now continue the execution of the program and see that Six is detected as a Cylon!</p>
<p>Of course this is just a very early version of the debugger and we will see lots of improvement in the next few weeks. Who knows someone might even create a GUI for the debugger and/or a Xcode integration.</p>
<p>Anyway, the point being that MacRuby developers should expect a lot of awesome stuff coming up their way soon. (also be careful about the skin jobs around you, cylon detectors can&rsquo;t be trusted!)</p>
]]></content>
		</item>
		
		<item>
			<title>controlling itunes with macruby</title>
			<link>https://matt.aimonetti.net/posts/2010-01-controlling-itunes-with-macruby/</link>
			<pubDate>Sun, 17 Jan 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-01-controlling-itunes-with-macruby/</guid>
			<description>Since Mac OS X v10.5, Apple added a technology called Scripting Bridge which allows to control and communicate with scriptable applications such as Mail, iChat or iTunes.
A few weeks back, I showed how to control iChat with MacRuby. This time I&amp;rsquo;m going to show you how to control iTunes.
Here is a small script that I wrote to wake me up in music every morning.
#!/usr/local/bin/macruby framework &#39;Foundation&#39; framework &#39;ScriptingBridge&#39; itunes = SBApplication.</description>
			<content type="html"><![CDATA[<p>Since Mac OS X v10.5, Apple added a technology called Scripting Bridge which allows to control and communicate with scriptable applications such as Mail, iChat or iTunes.</p>
<p>A few weeks back, <a href="https://merbist.com/2009/12/31/im-new-year-count-down-with-macruby/">I showed how to control iChat</a> with MacRuby. This time I&rsquo;m going to show you how to control iTunes.</p>
<p>Here is a small script that I wrote to wake me up in music every morning.</p>
<pre><code>#!/usr/local/bin/macruby
framework 'Foundation'
framework 'ScriptingBridge'

itunes = SBApplication.applicationWithBundleIdentifier(&quot;com.apple.itunes&quot;)
load_bridge_support_file 'iTunes.bridgesupport'
itunes.run

class SBElementArray
  def [](value)
    self.objectWithName(value)
  end
end

itunes.stop
playlist = itunes.sources[&quot;Library&quot;].userPlaylists[&quot;morning&quot;]
playlist.playOnce(false) if playlist
</code></pre>
<p>The idea is that I have a Mac Mini streaming music through speakers connected to an AirportExpress in my bedroom.</p>
<p>Let&rsquo;s go through the script quickly.</p>
<p>We start by loading two frameworks, Foundation and ScriptingBridge.
Now that we have ScriptingBridge loaded, we can control iTunes. To do that, we use:
SBApplication.applicationWithBundleIdentifier(&ldquo;com.apple.itunes&rdquo;)
We then load a bridgesupport file that contains the enumerated constants from the iTunes scriptable dictionary.</p>
<p>We make sure iTunes is running by calling #run on the application object.</p>
<p>Before using iTune scriptable interface, we are making the API a bit nicer, it&rsquo;s totally unnecessary but it makes our code look better.</p>
<p>itunes.sources returns an instance of <a href="https://developer.apple.com/mac/library/documentation/cocoa/Reference/SBElementArray_Class/SBElementArray/SBElementArray.html">SBElementArray</a> which is not really an array nor a hash.</p>
<p>The rest of the code is pretty simple, we find the library, find the playlist called &lsquo;morning&rsquo; and play it if found.</p>
<p>So you might wonder two things:</p>
<ul>
<li>
<p>What is the iTunes.bridgesupport file?</p>
</li>
<li>
<p>How do you know what methods are available to control iTunes?</p>
</li>
</ul>
<h4 id="bridgesupport-file">bridgesupport file</h4>
<p>The bridgesupport file is important since it defines the required constants.
Apple provides a metadata generator called gen_bridge_metadata which generates a bridgesupport file.</p>
<p>Here is what the documentation says:</p>
<pre><code>$ man gen_bridge_metadata




NAME
gen_bridge_metadata -- Objective-C Bridges Metadata Generator

SYNOPSIS
gen_bridge_metadata [options...] headers...

DESCRIPTION
gen_bridge_metadata is a tool that generates bridging metadata information for a given framework or set of head-
ers. The Objective-C bridges supported in Mac OS X, such as RubyCocoa (Ruby) and PyObjC (Python), read this
information at runtime.

Metadata files describe the parts of an Objective-C framework that the bridges cannot automatically handle. These
are primarily the ANSI C elements of the framework -- functions, constants, enumerations, and so on -- but also
include special cases such as functions or methods that accept pointer-like arguments. These special cases must
be manually specified in separate files called exceptions. The gen_bridge_metadata tool can then read in the
exceptions file when it generates the framework metadata.

The file extension used for metadata files should be .bridgesupport.

Certain elements, such as inline functions, cannot be described in the metadata files. It is therefore required
to generate a dynamic library in order to make the bridges use them. The gen_bridge_metadata tool can take care
of that for you.

The file extension for the dynamic libraries should be .dylib.

You should install metadata files in one of three filesystem locations. For example, for a framework named
MyFramework that is installed as /Library/Frameworks/MyFramework.framework, you can install the
MyFramework.bridgesupport and MyFramework.dylib files in one of the following possible locations, in order of
priority:

o   /Library/Frameworks/MyFramework/Resources/BridgeSupport

o   /Library/BridgeSupport

o   ~/Library/BridgeSupport
</code></pre>
<p>The problem is that we don&rsquo;t have a framework or header file to generate a bridgesupport file for.
So, what we need a header file for iTunes, turns out we have a tool to do that:</p>
<pre><code>$ sdef /Applications/iTunes.app | sdp -fh --basename iTunes
</code></pre>
<p>I won&rsquo;t go in the details of what sdef and sdp do, just check their manual page.
Running the command above will create a iTunes.h which we can use to create a bridgesupport file.
Here is the generated header file: <a href="https://gist.github.com/279657">https://gist.github.com/279657</a></p>
<p>Now, let&rsquo;s create a bidgesupport file:</p>
<pre><code>$ gen_bridge_metadata -c '-I.' iTunes.h &gt; iTunes.bridgesupport
</code></pre>
<p>An that&rsquo;s how we get the bridgesupport file. (see file: <a href="https://gist.github.com/279698">https://gist.github.com/279698</a>)</p>
<h4 id="itunes-documentation">iTunes Documentation</h4>
<p>The easiest way to understand what&rsquo;s available to you is to open iTunes' dictionary in the AppleScript Editor.</p>
<p><img src="https://img.skitch.com/20100118-fe5c3224jd8xfhciwqxpy4hptc.jpg" alt="iTunes API by Matt Aimonetti"></p>
<p>Otherwise you can study the iTunes.h file.</p>
<p>I wrote a very dumb parser to give you an idea of the methods and properties available when controlling iTunes via ScriptingBridge, here is the  output:</p>
<pre><code>Class: iTunesPrintSettings
Properties:
copies (the number of copies of a document to be printed)
collating (Should printed copies be collated?)
startingPage (the first page of the document to be printed)
endingPage (the last page of the document to be printed)
pagesAcross (number of logical pages laid across a physical page)
pagesDown (number of logical pages laid out down a physical page)
errorHandling (how errors are handled)
requestedPrintTime (the time at which the desktop printer should print the document)
printerFeatures (printer specific options)
faxNumber (for fax number)
targetPrinter (for target printer)

Method: printPrintDialog:(BOOL)printDialog withProperties:(iTunesPrintSettings *)withProperties kind:(iTunesEKnd)kind theme:(NSString *)theme
Returned: void
Print the specified object(s)
----
Method: close
Returned: void
Close an object
----
Method: delete
Returned: void
Delete an element from an object
----
Method: duplicateTo:(SBObject *)to
Returned: SBObject
Duplicate one or more object(s)
----
Method: exists
Returned: BOOL
Verify if an object exists
----
Method: open
Returned: void
open the specified object(s)
----
Method: playOnce:(BOOL)once
Returned: void
play the current track or the specified track or file.
----

Class: iTunesApplication
Properties:
currentEncoder (the currently selected encoder (MP3, AIFF, WAV, etc.))
currentEQPreset (the currently selected equalizer preset)
currentPlaylist (the playlist containing the currently targeted track)
currentStreamTitle (the name of the current song in the playing stream (provided by streaming server))
currentStreamURL (the URL of the playing stream or streaming web site (provided by streaming server))
currentTrack (the current targeted track)
currentVisual (the currently selected visual plug-in)
EQEnabled (is the equalizer enabled?)
fixedIndexing (true if all AppleScript track indices should be independent of the play order of the owning playlist.)
frontmost (is iTunes the frontmost application?)
fullScreen (are visuals displayed using the entire screen?)
name (the name of the application)
mute (has the sound output been muted?)
playerPosition (the player’s position within the currently playing track in seconds.)
playerState (is iTunes stopped, paused, or playing?)
selection (the selection visible to the user)
soundVolume (the sound output volume (0 = minimum, 100 = maximum))
version (the version of iTunes)
visualsEnabled (are visuals currently being displayed?)
visualSize (the size of the displayed visual)

Method: browserWindows
Returned: SBElementArray
----
Method: encoders
Returned: SBElementArray
----
Method: EQPresets
Returned: SBElementArray
----
Method: EQWindows
Returned: SBElementArray
----
Method: playlistWindows
Returned: SBElementArray
----
Method: sources
Returned: SBElementArray
----
Method: visuals
Returned: SBElementArray
----
Method: windows
Returned: SBElementArray
----
Method: printPrintDialog:(BOOL)printDialog withProperties:(iTunesPrintSettings *)withProperties kind:(iTunesEKnd)kind theme:(NSString *)theme
Returned: void
Print the specified object(s)
----
Method: run
Returned: void
run iTunes
----
Method: quit
Returned: void
quit iTunes
----
Method: add:(NSArray *)x to:(SBObject *)to
Returned: iTunesTrack
add one or more files to a playlist
----
Method: backTrack
Returned: void
reposition to beginning of current track or go to previous track if already at start of current track
----
Method: convert:(NSArray *)x
Returned: iTunesTrack
convert one or more files or tracks
----
Method: fastForward
Returned: void
skip forward in a playing track
----
Method: nextTrack
Returned: void
advance to the next track in the current playlist
----
Method: pause
Returned: void
pause playback
----
Method: playOnce:(BOOL)once
Returned: void
play the current track or the specified track or file.
----
Method: playpause
Returned: void
toggle the playing/paused state of the current track
----
Method: previousTrack
Returned: void
return to the previous track in the current playlist
----
Method: resume
Returned: void
disable fast forward/rewind and resume playback, if playing.
----
Method: rewind
Returned: void
skip backwards in a playing track
----
Method: stop
Returned: void
stop playback
----
Method: update
Returned: void
update the specified iPod
----
Method: eject
Returned: void
eject the specified iPod
----
Method: subscribe:(NSString *)x
Returned: void
subscribe to a podcast feed
----
Method: updateAllPodcasts
Returned: void
update all subscribed podcast feeds
----
Method: updatePodcast
Returned: void
update podcast feed
----
Method: openLocation:(NSString *)x
Returned: void
Opens a Music Store or audio stream URL
----

Class: iTunesItem
Properties:
container (the container of the item)
index (The index of the item in internal application order.)
name (the name of the item)
persistentID (the id of the item as a hexidecimal string. This id does not change over time.)

Method: id
Returned: NSInteger
the id of the item
----
Method: printPrintDialog:(BOOL)printDialog withProperties:(iTunesPrintSettings *)withProperties kind:(iTunesEKnd)kind theme:(NSString *)theme
Returned: void
Print the specified object(s)
----
Method: close
Returned: void
Close an object
----
Method: delete
Returned: void
Delete an element from an object
----
Method: duplicateTo:(SBObject *)to
Returned: SBObject
Duplicate one or more object(s)
----
Method: exists
Returned: BOOL
Verify if an object exists
----
Method: open
Returned: void
open the specified object(s)
----
Method: playOnce:(BOOL)once
Returned: void
play the current track or the specified track or file.
----
Method: reveal
Returned: void
reveal and select a track or playlist
----

Class: iTunesPlaylist
Properties:
duration (the total length of all songs (in seconds))
name (the name of the playlist)
parent (folder which contains this playlist (if any))
shuffle (play the songs in this playlist in random order?)
size (the total size of all songs (in bytes))
songRepeat (playback repeat mode)
specialKind (special playlist kind)
time (the length of all songs in MM:SS format)
visible (is this playlist visible in the Source list?)

Method: tracks
Returned: SBElementArray
----
Method: moveTo:(SBObject *)to
Returned: void
Move playlist(s) to a new location
----
Method: searchFor:(NSString *)for_ only:(iTunesESrA)only
Returned: iTunesTrack
search a playlist for tracks matching the search string. Identical to entering search text in the Search field in iTunes.
----

Class: iTunesAudioCDPlaylist
Properties:
artist (the artist of the CD)
compilation (is this CD a compilation album?)
composer (the composer of the CD)
discCount (the total number of discs in this CD’s album)
discNumber (the index of this CD disc in the source album)
genre (the genre of the CD)
year (the year the album was recorded/released)

Method: audioCDTracks
Returned: SBElementArray
----

Class: iTunesDevicePlaylist
Method: deviceTracks
Returned: SBElementArray
----

Class: iTunesLibraryPlaylist
Method: fileTracks
Returned: SBElementArray
----
Method: URLTracks
Returned: SBElementArray
----
Method: sharedTracks
Returned: SBElementArray
----

Class: iTunesRadioTunerPlaylist
Method: URLTracks
Returned: SBElementArray
----

Class: iTunesSource
Properties:
capacity (the total size of the source if it has a fixed size)
freeSpace (the free space on the source if it has a fixed size)
kind ()

Method: audioCDPlaylists
Returned: SBElementArray
----
Method: devicePlaylists
Returned: SBElementArray
----
Method: libraryPlaylists
Returned: SBElementArray
----
Method: playlists
Returned: SBElementArray
----
Method: radioTunerPlaylists
Returned: SBElementArray
----
Method: userPlaylists
Returned: SBElementArray
----
Method: update
Returned: void
update the specified iPod
----
Method: eject
Returned: void
eject the specified iPod
----

Class: iTunesTrack
Properties:
album (the album name of the track)
albumArtist (the album artist of the track)
albumRating (the rating of the album for this track (0 to 100))
albumRatingKind (the rating kind of the album rating for this track)
artist (the artist/source of the track)
bitRate (the bit rate of the track (in kbps))
bookmark (the bookmark time of the track in seconds)
bookmarkable (is the playback position for this track remembered?)
bpm (the tempo of this track in beats per minute)
category (the category of the track)
comment (freeform notes about the track)
compilation (is this track from a compilation album?)
composer (the composer of the track)
databaseID (the common, unique ID for this track. If two tracks in different playlists have the same database ID, they are sharing the same data.)
dateAdded (the date the track was added to the playlist)
objectDescription (the description of the track)
discCount (the total number of discs in the source album)
discNumber (the index of the disc containing this track on the source album)
duration (the length of the track in seconds)
enabled (is this track checked for playback?)
episodeID (the episode ID of the track)
episodeNumber (the episode number of the track)
EQ (the name of the EQ preset of the track)
finish (the stop time of the track in seconds)
gapless (is this track from a gapless album?)
genre (the music/audio genre (category) of the track)
grouping (the grouping (piece) of the track. Generally used to denote movements within a classical work.)
kind (a text description of the track)
longDescription ()
lyrics (the lyrics of the track)
modificationDate (the modification date of the content of this track)
playedCount (number of times this track has been played)
playedDate (the date and time this track was last played)
podcast (is this track a podcast episode?)
rating (the rating of this track (0 to 100))
ratingKind (the rating kind of this track)
releaseDate (the release date of this track)
sampleRate (the sample rate of the track (in Hz))
seasonNumber (the season number of the track)
shufflable (is this track included when shuffling?)
skippedCount (number of times this track has been skipped)
skippedDate (the date and time this track was last skipped)
show (the show name of the track)
sortAlbum (override string to use for the track when sorting by album)
sortArtist (override string to use for the track when sorting by artist)
sortAlbumArtist (override string to use for the track when sorting by album artist)
sortName (override string to use for the track when sorting by name)
sortComposer (override string to use for the track when sorting by composer)
sortShow (override string to use for the track when sorting by show name)
size (the size of the track (in bytes))
start (the start time of the track in seconds)
time (the length of the track in MM:SS format)
trackCount (the total number of tracks on the source album)
trackNumber (the index of the track on the source album)
unplayed (is this track unplayed?)
videoKind (kind of video track)
volumeAdjustment (relative volume adjustment of the track (-100% to 100%))
year (the year the track was recorded/released)

Method: artworks
Returned: SBElementArray
----

Class: iTunesFileTrack
Properties:
location (the location of the file represented by this track)

Method: refresh
Returned: void
update file track information from the current information in the track’s file
----

Class: iTunesURLTrack
Properties:
address (the URL for this track)

Method: download
Returned: void
download podcast episode
----

Class: iTunesUserPlaylist
Properties:
shared (is this playlist shared?)
smart (is this a Smart Playlist?)

Method: fileTracks
Returned: SBElementArray
----
Method: URLTracks
Returned: SBElementArray
----
Method: sharedTracks
Returned: SBElementArray
----
</code></pre>
]]></content>
		</item>
		
		<item>
			<title>amazon kindle 2</title>
			<link>https://matt.aimonetti.net/posts/2010-01-amazon-kindle-2/</link>
			<pubDate>Tue, 05 Jan 2010 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2010-01-amazon-kindle-2/</guid>
			<description>For Noël, my wife got me a new toy: the Amazon Kindle 2.

Kindle vs Nook Before my wife bought what became my new favorite gadget, we checked on the Barnes &amp;amp; Noble Nook.
The primary problem with the Nook was that it was out of stock. That pushed me to dig deeper and really compare both devices.
The Nook had some interesting features like wifi, small color screen and the book lending feature.</description>
			<content type="html"><![CDATA[<p>For Noël, my wife got me a new toy: <a href="https://www.amazon.com/gp/product/B0015T963C?ie=UTF8&amp;tag=merbist-20&amp;linkCode=as2&amp;camp=1789&amp;creative=390957&amp;creativeASIN=B0015T963C">the Amazon Kindle 2</a>.</p>
<p><a href="https://www.amazon.com/gp/product/B0015T963C?tag=merbist-20"><img src="https://placeholder.apture.com/ph/360x280_AmazonProduct/" alt=""></a></p>
<h2 id="kindle-vs-nook">Kindle vs Nook</h2>
<p>Before my wife bought what became my new favorite gadget, we checked on the Barnes &amp; Noble Nook.</p>
<p><img src="https://farm5.static.flickr.com/4012/4176062087_704a33b9fd_m.jpg" alt=""></p>
<p>The primary problem with the Nook was that it was out of stock. That pushed me to dig deeper and really compare both devices.</p>
<p>The Nook had some interesting features like wifi, small color screen and the book lending feature.</p>
<p>However, I don&rsquo;t really care about a small, clunky extra color screen since I just want to read books. The wifi is nice&hellip; but what am I going to do with it? Lending books is a cool feature, but this feature isn&rsquo;t available for all books and is apparently seriously limited.</p>
<p>So I decided to focus on what I really needed instead of what I could use.</p>
<ul>
<li>
<p>The main purpose of an e-book is reading, page loading should be fast and the user experience should be at least as good as when reading a &lsquo;real&rsquo; book.</p>
</li>
<li>
<p>I need to be able to have a great choice of books and if possible in multiple languages.</p>
</li>
<li>
<p>I would like to be able to read the <a href="https://www.safaribooksonline.com/">safarionline</a> books that I can access online.</p>
</li>
</ul>
<p>From what I read almost everywhere, the nook is slow and a bit buggy (it&rsquo;s a first generation after all) and doesn&rsquo;t come with a web browser. I also checked on the ebooks available on Amazon and Barnes &amp; Noble. Amazon has way more ebooks and that&rsquo;s really what motivated my decision. The other thing is that Amazon is present world wide and I expect them to start selling more ebooks in French and Spanish.</p>
<p>The other thing that pushed me to buy a Kindle was the fact that I know so many people having one and being so pleased. During a recent trip to San Diego, <a href="https://www.linkedin.com/in/yehudakatz">Yehuda Katz</a> told me about how much he loves his Kindle and he recommended a book to read. I started reading the book on my iPhone (using kindle for iPhone) and was really wanted a bigger screen.</p>
<h2 id="kindle-vs-itablet">Kindle vs iTablet</h2>
<p>A lot of people asked me why I didn&rsquo;t wait for the big announcement of the iTablet because it might be a Kindle killer.</p>
<p>First, the iTablet is currently just a rumor and if we would believe the rumor, the iTablet will sell around $1,000 vs $250 for a kindle. The tablet will probably do a lot of cool stuff my e-reader can&rsquo;t do&hellip; but I don&rsquo;t care I chose the kindle because I wanted a simple device to read book and only do that. Actually, the  kindle + iphone combo works great for me. I used to read a lot but because I have been moving so many times I started reading less because I always get rid of my books. Also, when traveling a lot, carrying your books with you is a pain. (especially now that most airlines charge you per bag)</p>
<h2 id="kindle-and-tech-booksdocumentation">Kindle and tech books/documentation.</h2>
<p>If you want a kindle to read tech books, don&rsquo;t get a 6&quot;, get the kindle DX instead. Even though the 6&quot; natively supports PDF files, the text is usually too small and the Kindle doesn&rsquo;t support zooming (yet).</p>
<p><a href="https://www.amazon.com/gp/product/B0015TCML0?tag=merbist-20"><img src="https://placeholder.apture.com/ph/360x280_AmazonProduct/" alt=""></a></p>
<p>The DX is perfect to read PDFs because the ratio matches the print expectations. I was thinking about converting all the Cocoa docs to a kindle friendly format since the kindle supports search etc.. But the truth is that it&rsquo;s not worth it. The display on a 6&quot; screen is clunky, it just doesn&rsquo;t feel right. I didn&rsquo;t try any of the pragprog ebooks but something tells me they will just look better on the DX.</p>
<p>Since I wanted a kindle to read books and not browse tech documentation, I&rsquo;m still really happy with 6&quot;.</p>
<p>If you also have kindle or are planning on buying one soon, here are two books I&rsquo;ve been enjoying reading:</p>
<p>[caption id=&quot;&quot; align=&ldquo;alignleft&rdquo; width=&ldquo;280&rdquo; caption=&ldquo;Flashforward by Robert J. Sawyer&rdquo;]<a href="https://www.amazon.com/Flashforward-ebook/dp/B002NANLCE/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1262741423&amp;sr=8-1-catcorr"><img src="https://ecx.images-amazon.com/images/I/51qntNYMMEL._SL500_AA246_PIkin2,BottomRight,-12,34_AA280_SH20_OU01_.jpg" alt=""></a>[/caption]</p>
<p>[caption id=&quot;&quot; align=&ldquo;alignright&rdquo; width=&ldquo;280&rdquo; caption=&ldquo;The Talent Code by Daniel Coyle&rdquo;]<a href="https://www.amazon.com/Talent-Code-Greatness-Grown-ebook/dp/B0026OR1UK/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1262741566&amp;sr=1-1"><img src="https://ecx.images-amazon.com/images/I/41CluL6Fo9L._SL500_AA246_PIkin2,BottomRight,-13,34_AA280_SH20_OU01_.jpg" alt=""></a>[/caption]</p>
]]></content>
		</item>
		
		<item>
			<title>im new year count down with macruby</title>
			<link>https://matt.aimonetti.net/posts/2009-12-im-new-year-count-down-with-macruby/</link>
			<pubDate>Thu, 31 Dec 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-12-im-new-year-count-down-with-macruby/</guid>
			<description>Here is the geekiest way I found to wish Happy New Year to my IM contacts:
framework &#39;ScriptingBridge&#39; app = SBApplication.applicationWithBundleIdentifier(&amp;quot;com.apple.iChat&amp;quot;) original_status = app.statusMessage new_year = Time.mktime(2010, 1, 1, 0, 0) loop do now = Time.now time_left = (new_year - now).ceil if time_left &amp;gt; 0 app.statusMessage = &amp;quot;#{time_left} seconds left until 2010 (EST)&amp;quot; else app.statusMessage = &amp;quot;Happy New Year 2010!&amp;quot; exit end sleep(1) end  If you are alone at home playing WOW, you can also trigger iTunes to play a mp3 file with crowd noise and people shouting &amp;lsquo;Happy New Year 2010&amp;rsquo;!</description>
			<content type="html"><![CDATA[<p>Here is the geekiest way I found to wish Happy New Year to my IM contacts:</p>
<p><img src="https://img.skitch.com/20091231-c9t2n9889rxiinux6qsfhqtxfq.jpg" alt=""></p>
<pre><code>framework 'ScriptingBridge'
app = SBApplication.applicationWithBundleIdentifier(&quot;com.apple.iChat&quot;)
original_status = app.statusMessage
new_year = Time.mktime(2010, 1, 1, 0, 0)

loop do
  now = Time.now
  time_left = (new_year - now).ceil
  if time_left &gt; 0
    app.statusMessage = &quot;#{time_left} seconds left until 2010 (EST)&quot;
  else
    app.statusMessage = &quot;Happy New Year 2010!&quot;
    exit
  end
  sleep(1)
end
</code></pre>
<p>If you are alone at home playing WOW,  you can also trigger iTunes to play a mp3 file with crowd noise and people shouting &lsquo;<strong>Happy New Year 2010</strong>&rsquo;!</p>
<p><img src="https://img.skitch.com/20091231-c5j9dhhy46t76gh26fu6a26h7c.jpg" alt=""></p>
]]></content>
		</item>
		
		<item>
			<title>fun with macruby</title>
			<link>https://matt.aimonetti.net/posts/2009-12-fun-with-macruby/</link>
			<pubDate>Tue, 29 Dec 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-12-fun-with-macruby/</guid>
			<description>To be ready for 2010, I&amp;rsquo;m taking some time off relaxing and spending time with my family in Florida.
During my free time, I&amp;rsquo;ve been reading, catching up on movies and TV shows and worked on the MacRuby book that I am writing for O&amp;rsquo;Reilly.
I wrote a bunch of small apps, played with various APIs and every single time I was amazed by all the goodies Apple makes available to developers.</description>
			<content type="html"><![CDATA[<p>To be ready for 2010, I&rsquo;m taking some time off relaxing and spending time with my family in Florida.</p>
<p>During my free time, I&rsquo;ve been reading, catching up on movies and TV shows and worked on the MacRuby book that I am writing for O&rsquo;Reilly.</p>
<p>I wrote a bunch of small apps, played with various APIs and every single time I was amazed by all the goodies Apple makes available to developers. My most recent discovery is very simple but I wanted to share it with you.</p>
<p>I often type text in English, French and Spanish and I even mix the languages from time to time. SnowLeopard comes with a great spellchecker that auto detects the language I&rsquo;m typing in and is most of the time correct. It&rsquo;s a very impressive feature and I was wondering if, as a MacRuby developer, I could use one of Apple&rsquo;s lib to detect what language is being used.  I dug through the documentation but didn&rsquo;t find anything. I started looking at some header files and found the API to use :)</p>
<pre><code>framework 'Foundation'
class String
  def language
    CFStringTokenizerCopyBestStringLanguage(self, CFRangeMake(0, self.size))
  end
end

puts &quot;Bonne année!&quot;.language
# =&gt; &quot;fr&quot;
puts &quot;Happy new year!&quot;.language
# =&gt; &quot;en&quot;
puts &quot;¡Feliz año nuevo!&quot;.language
# =&gt; &quot;es&quot;
puts &quot;Felice anno nuovo!&quot;.language
# =&gt; &quot;it&quot;
puts &quot;أعياد سعيدة&quot;.language
# =&gt; &quot;ar&quot;
puts &quot;明けましておめでとうございます。&quot;.language
# =&gt; &quot;ja&quot;
</code></pre>
<p>The documentation says that the result is not guaranteed to be accurate and that typically 200-400 characters are required to reliably guess the language of a string. (<a href="https://developer.apple.com/mac/library/documentation/CoreFoundation/Reference/CFStringTokenizerRef/Reference/reference.html#//apple_ref/c/func/CFStringTokenizerCopyBestStringLanguage">CFStringTokenizer Doc</a>)</p>
<p>Probably not the most useful piece of code, but really cool none the less :)</p>
<p>Happy new year!</p>
]]></content>
		</item>
		
		<item>
			<title>lots of rubies now what</title>
			<link>https://matt.aimonetti.net/posts/2009-11-lots-of-rubies-now-what/</link>
			<pubDate>Mon, 30 Nov 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-11-lots-of-rubies-now-what/</guid>
			<description>If you were at RubyConf 2009 or looked at the schedule, you saw that the big thing happening in the Ruby scene is the maturation of a many of the Ruby implementations: BlueRuby, HotRuby, IronRuby, JRuby, MacRuby, Maglev, MRI, REE, Rubinius, SmallRuby&amp;hellip; Ruby developers really have plenty of choice when it comes to choosing an alternative Ruby implementation.
Is that a bad thing?
Turns out, Matz , Ruby author mentioned one ore time during RubyConf that it was actually a good thing for the Ruby ecosystem.</description>
			<content type="html"><![CDATA[<p>If you were at RubyConf 2009 or looked at the schedule, you saw that the big thing happening in the Ruby scene is the maturation of a many of the Ruby implementations:
BlueRuby, HotRuby, IronRuby, JRuby, MacRuby, Maglev, MRI, REE, Rubinius, SmallRuby&hellip;
Ruby developers really have plenty of choice when it comes to choosing an alternative Ruby implementation.</p>
<p>Is that a bad thing?</p>
<p>Turns out, Matz , Ruby author mentioned one ore time during RubyConf that it was actually a good thing for the Ruby ecosystem.</p>
<p>But maybe we should take a step back and look at the big picture. So here are some of my thoughts on the topic. <em>(disclaimer: being part of the MacRuby team, I&rsquo;m certainly biased)</em></p>
<p><strong>Stop comparing alternative Ruby implementations against Ruby 1.8.x.</strong></p>
<p>Even though a lot of people are still using Ruby 1.8.x, it&rsquo;s totally unfair to compare against such an old version of Matz&rsquo;s Ruby.
Ruby 1.9 is what people should compare against and believe me, Ruby 1.9.2 is going to change the game (much faster, cleaned up version).
Hopefully, all the Ruby alternative implementations will quickly become 1.9 compatible.</p>
<p>(On a site note, <a href="https://weblog.rubyonrails.org/2009/11/30/ruby-on-rails-2-3-5-released">Rails 2.3.5 was released</a> a few days ago which fixes some of the last few remaining Ruby 1.9 bugs)</p>
<p><strong>Don&rsquo;t trust the benchmarks</strong></p>
<p>As we all know, <a href="https://en.wikipedia.org/wiki/Lies,_damned_lies,_and_statistics">there are lies, damn lies and statistics</a>. Evan Phoenix explained that very clearly with lots of examples during his <a href="https://rubyconf2009.confreaks.com/">RubyConf talk</a> and I totally agree with him.
Micro benchmarks only help implementers know where they are standing and find performance issue.
Let&rsquo;s take a very simple example: <a href="https://jruby.org/">JRuby</a>.
What you might not know is that most JRuby benchmarks are usually &lsquo;warmed up&rsquo;.  Basically, to get the results you see in most reported benchmarks, you need to run the benchmark in a loop X amount of times and then run the benchmark. The reason for that is that JRuby uses HotSpot which needs to process the code to optimize the JITting and finally get your code to run faster.
The problem is that it is not a fair comparison. I was benchmarking Rails3 for instance and JRuby starts way slower than Ruby 1.8.6 and takes a little while to get as fast/faster than 1.9.1.
This is something you need to take in consideration since each deployment will slow down your app and you probably shouldn&rsquo;t use JRuby if you are not using long running processes.
Another example would be MacRuby, even though the MacRuby project never released any benchmarks, it&rsquo;s known to be a <em>fast</em> implementation.
Currently, the allocation of objects in MacRuby is actually still a bit costly and if you benchmark that, you can <em>show</em> that MacRuby is slow. Other operations are super optimized and both Rubinius and MacRuby will be way faster than anyone else. (check Phoenix&rsquo;s talk at Ruby conf for more examples)
So, before choosing an implementation for performance reasons, benchmark against the code you are going to use.</p>
<p><strong>There is only one real original Ruby</strong></p>
<p>I think nobody will disagree with the fact that there is only one Ruby reference and that&rsquo;s Matz.
Therefore is only one &ldquo;real&rdquo; Ruby and that is Matz&rsquo;s. (Matz actually disagreed with me when I said that, since all the other implementations are also &ldquo;real&rdquo; but you get the point)
There is nothing wrong with Ruby&rsquo;s alternatives but they stay alternatives to the original
MRI might not be the best option for every single case out there but it is and will stay the reference.</p>
<p>During RubyConf, I was joking with Matz and Koichi that maybe they should claim a Ruby tax to the Ruby implementations.
The reality is that Ruby is maintained by 5 to 10 contributors, most of them doing that on the side of their full time job.
Most of the other implementations have full time staff working hard on their implementations. That&rsquo;s exciting but sad at the same time.</p>
<p>During the different talks given by the Ruby core team, it was clear that they really want to bridge the West/East gap and asked for help. It&rsquo;s very honorable on their part and I hope we will see more contributions coming from outside Japan.</p>
<p>Finally, I think that even if people work hard to write the best Ruby implementation ever, let&rsquo;s not forget to respect Matz&rsquo;s project, team and achievements. People spent hours/weeks/months creating the Ruby language we love and even though there are some aspects that could be and are being improved, let&rsquo;s not forget that when criticizing/comparing their work.</p>
<p><strong>There is not only one way to do things</strong></p>
<p>I don&rsquo;t know where that&rsquo;s coming from, but some people in our community seem to believe that there is only one way to do things and if you don&rsquo;t do it their way, you do it wrong.
I personally have a hard time believing that and I even think it goes against what Ruby was designed for. (However, I must admit that sometimes I did/do think that some approaches were totally wrong :p)
It reminds me of people trying to convince you that God exists, other people trying to convince you that their religion is the only true one, or finally the other people trying to convince believers that they are wrong.
Maybe it is just that as humans we have a hard time dealing with people coming to a different conclusion than us and therefore we have to convince them that we are right and they are wrong.</p>
<p>The way I see it, for any new Ruby project, you should start be using with Ruby1.9. If it doesn&rsquo;t fit your needs, then, consider an alternative. Here is how I look at the other alternatives (feel free to disagree):</p>
<ul>
<li>
<p><a href="https://wiki.sdn.sap.com/wiki/display/Research/BlueRuby">BlueRuby</a> - use if you are writing a SAP app</p>
</li>
<li>
<p><a href="https://hotruby.yukoba.jp/">HotRuby</a> - use if you want to use Ruby to write a Flash app</p>
</li>
<li>
<p><a href="https://ironruby.net/">IronRuby</a> - use it if you want to integrate with .NET and/or write a silverlight app</p>
</li>
<li>
<p><a href="https://jruby.org/">JRuby</a> - use if you want to integrate with the Java world</p>
</li>
<li>
<p><a href="https://macruby.org">MacRuby</a> - use it if you want to integrate with Cocoa/want a native OSX application</p>
</li>
<li>
<p><a href="https://maglev.gemstone.com/">Maglev</a> - use if you want to use an object persistence layer and a distributed shared cache</p>
</li>
<li>
<p><a href="https://www.rubyenterpriseedition.com/">REE</a> - use if you have a ruby 1.8 web app that uses too much memory</p>
</li>
<li>
<p><a href="https://rubini.us">Rubinius</a> - use if you want to know what&rsquo;s going on in your code</p>
</li>
<li>
<p><a href="https://smalltalk.felk.cvut.cz/projects/smallruby">SmallRuby</a> - don&rsquo;t use it yet, but keep an eye on it</p>
</li>
</ul>
<p>This is the way I see the various existing implementations and I think this is where they shine and why they were created in the first place. They are all complimentary and help bring the Ruby language further. The goal is always the same.</p>
<p><strong>The future is exciting</strong></p>
<p>Ruby is getting everywhere or almost. Matz&rsquo;s Ruby is going to get multiVM support, various other improvements and get even faster and faster.
Alternative implementations are getting more and more mature and they grow the community by bringing people from different communities (.NET, java, obj-c/cocoa)</p>
<p>At the end of the day, we are all beneficiaries of the work done by all the implementers, thank you guys and keep up the good work!</p>
]]></content>
		</item>
		
		<item>
			<title>rubyconf 2009 2d games for os x</title>
			<link>https://matt.aimonetti.net/posts/2009-11-rubyconf-2009-2d-games-for-os-x/</link>
			<pubDate>Sat, 21 Nov 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-11-rubyconf-2009-2d-games-for-os-x/</guid>
			<description>During RubyConf 2009 in San Francisco, CA Matt Aimonetti gave a talk entitled Writing 2D games for the OSX platform in Ruby.
##Description of the talk:
Are you a developer who would love to get into video games but get scared when he hears &amp;ldquo;OpenGL&amp;rdquo; or &amp;ldquo;rendering engines&amp;rdquo;? Or Maybe, you never considered writing a video game because you have heard Ruby was slow and you are not ready to give up on your favorite programming language.</description>
			<content type="html"><![CDATA[<p>During <a href="https://rubyconf.org/">RubyConf 2009</a> in San Francisco, CA Matt
Aimonetti gave a talk entitled <em>Writing 2D games for the OSX platform in Ruby</em>.</p>
<p>##Description of the talk:</p>
<p>Are you a developer who would love to get into video games but get scared when he hears &ldquo;OpenGL&rdquo; or &ldquo;rendering engines&rdquo;? Or Maybe, you never considered writing a video game because you have heard Ruby was slow and you are not ready to give up on your favorite programming language. This talk is for you then. Together, we will build a very simple game using Ruby and the development tools offered by Apple. At the end of the presentation you will be ready to get started on your own project.</p>
<p><a href="https://speakerdeck.com/u/matt_aimonetti/p/rubyconf-2009-writing-2d-games-for-the-osx-platform-in-ruby"><img src="/images/matt_aimonetti_2d_video_games.jpg" alt="Matt Aimonetti demonstrating a simple game workflow"></a></p>
<p>##Slides</p>
<script async class="speakerdeck-embed" data-id="4f911cf25edf72002200cf4e" data-ratio="1.299492385786802" src="https://speakerdeck.com/assets/embed.js"></script>
<p>The slides are available on <a href="https://speakerdeck.com/u/matt_aimonetti/p/rubyconf-2009-writing-2d-games-for-the-osx-platform-in-ruby">Matt&rsquo;s SpeakerDeck</a> and can be [downloaded here]({{ page.slides }}).</p>
<p>##Video</p>
<p>{% video <a href="https://cdn.confreaks.com/system/assets/datas/420/original/21-nov-2009-10-25-writing-d-games-for-the-osx-platform-in-ruby-matt-aimonetti-small.mp4">https://cdn.confreaks.com/system/assets/datas/420/original/21-nov-2009-10-25-writing-d-games-for-the-osx-platform-in-ruby-matt-aimonetti-small.mp4</a> 640 360 <a href="https://www.confreaks.com/system/videos/images/192/preview/21-nov-2009-10-25-writing-d-games-for-the-osx-platform-in-ruby-matt-aimonetti-preview.png">https://www.confreaks.com/system/videos/images/192/preview/21-nov-2009-10-25-writing-d-games-for-the-osx-platform-in-ruby-matt-aimonetti-preview.png</a> %}</p>
<p>##Presentation website</p>
<p>Matt&rsquo;s presentation was filmed by <a href="https://confreaks.com/">confreaks</a> and the dedicated page for the talk is available <a href="https://www.confreaks.com/videos/192-rubyconf2009-writing-2d-games-for-the-osx-platform-in-ruby">here</a></p>
<h2 id="source-code">Source Code</h2>
<p>The code and game demonstrated in this talk is available on Matt
<a href="https://github.com/mattetti/phileas_frog">Aimonetti&rsquo;s GitHub repository</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>the ruby revolution take ii</title>
			<link>https://matt.aimonetti.net/posts/2009-11-the-ruby-revolution-take-ii/</link>
			<pubDate>Mon, 16 Nov 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-11-the-ruby-revolution-take-ii/</guid>
			<description>[caption id=&amp;ldquo;attachment_638&amp;rdquo; align=&amp;ldquo;alignright&amp;rdquo; width=&amp;ldquo;300&amp;rdquo; caption=&amp;ldquo;Mohandas Karamchand Gandhi&amp;rdquo;][/caption]
My recent &amp;lsquo;Ruby revolution being over&amp;rsquo; blog post generated quite a lot of comments. Let&amp;rsquo;s be honest, I did not expect less from the readers.
However, I noticed three types of reactions I would like to address:
  It was not a Ruby revolution, it was a Rails revolution
  The revolution has stalled due to no major enterprise backing
  The revolution will only be over when we will reach a greater adoption</description>
			<content type="html"><![CDATA[<p>[caption id=&ldquo;attachment_638&rdquo; align=&ldquo;alignright&rdquo; width=&ldquo;300&rdquo; caption=&ldquo;Mohandas Karamchand Gandhi&rdquo;]<img src="https://merbist.com/wp-content/uploads/2009/11/GANDHI.jpg" alt="Mohandas Karamchand Gandhi">[/caption]</p>
<p>My recent &lsquo;<a href="https://merbist.com/2009/11/09/the-ruby-revolution-is-over">Ruby revolution being over</a>&rsquo; blog post generated quite a <a href="https://merbist.com/2009/11/09/the-ruby-revolution-is-over/#comments">lot of comments</a>.
Let&rsquo;s be honest, I did not expect less from the readers.</p>
<p>However, I noticed three types of reactions I would like to address:</p>
<ul>
<li>
<p>It was not a Ruby revolution, it was a Rails revolution</p>
</li>
<li>
<p>The revolution has stalled due to no major enterprise backing</p>
</li>
<li>
<p>The revolution will only be over when we will reach a greater adoption</p>
</li>
</ul>
<p>First of all, as <a href="https://merbist.com/2009/11/09/the-ruby-revolution-is-over/#comment-817">Joe correctly mentioned</a>, for me, the revolution is not about specifics or individuals. It&rsquo;s really about the big picture.</p>
<p>The influence Ruby had and still has on the IT world seems to be undermined by some.
Ruby is a dynamic, truly Object Oriented programming scripting language <strong>designed for humans first</strong>.
The real paradigm shift is in the fact that Ruby was designed to make programming fast, enjoyable and easy instead of being optimized for the machines running it.
This is for me the essence of the revolution and it is meant to transcend the scope of the Ruby language.</p>
<p>The way I see it, Yukihiro Matsumoto (Matz) is more of an artist than a technician. He had a vision for software development. <strong>Programming languages cannot be optimized/designed for both machines and humans, the language designer has to choose which one he wants to privilege.</strong></p>
<p>Most programming languages believe that it&rsquo;s up to the programmer to make an extra effort since he is smarter and easier to optimize than a machine. Matz questioned this approached and decided to turn things around. The result is one of the reasons why developers seem to just fall in love with Ruby.</p>
<h3 id="it-was-not-a-ruby-revolution-it-was-a-rails-revolution">It was not a Ruby revolution, it was a Rails revolution.</h3>
<p>I am not denying that there <em><strong>also</strong></em> was a Rails revolution.
But if you look at it, Rails and its revolution are a direct effect from Ruby&rsquo;s revolution.
One might argue that it is actually an extension of Ruby&rsquo;s philosophy. But what is Rails if not a web framework designed to make web development fast, easy and enjoyable?
Without Ruby there would not have been Rails and that was my point, the underlying revolution comes from the language itself.</p>
<h3 id="the-revolution-has-stalled-due-to-no-major-enterprise-backing">The revolution has stalled due to no major enterprise backing.</h3>
<p>That&rsquo;s an interesting comment. It is true that .NET and Java are still dominating the enterprise world. But let&rsquo;s be clear, Ruby was not designed to please &ldquo;suit people&rdquo;.
And to this day, there is still a strong feeling, from some individuals against the enterprise.
In the past, DHH openly said that he did not care nor wanted to hear about the enterprise, more recently, Obie Fernandez, during one of his talks said: <a href="https://blip.tv/file/2733212">&ldquo;Fuck the enterprise&rdquo;</a> (49:39).
<strong>But the truth is that Ruby and the so called enterprise, both, are changing.</strong>
The smart people in the enterprise world saw potential in Ruby and decided to give it a chance. An easy way to include Ruby&rsquo;s philosophy without breaking the fragile enterprise equilibrium was to inject Ruby in the midst of well known and respected technologies such as Java and .NET. The enterprise can now use &ldquo;re-branded Ruby versions&rdquo; with &ldquo;new taste or &lsquo;improved&rsquo; flavor&rdquo; like JRuby, Scala, groovy, IronRuby.
I work for some enterprise clients and I can tell you that they &lsquo;also&rsquo; use Ruby. Mainly because developers love the language.
Microsoft, Apple and SAP investing in their own implementation of the language is yet another example that the enterprise recognizes the value of Matz&rsquo;s work.
Nobody can blame them to try to make Ruby fit more their requirements.
So, at the end of the day, Ruby is not the #1 enterprise language and Rails isn&rsquo;t used by the large majority of enterprise web apps, but that is NOT the point. Ruby has influenced the enterprise and we will see its effects for many years.</p>
<h3 id="the-revolution-will-only-be-over-when-we-will-reach-a-greater-adoption">The revolution will only be over when we will reach a greater adoption</h3>
<p>Saying that is missing the point entirely. A revolution is a step towards a situation change. Things don&rsquo;t change right away after a revolution. It takes a long time for mentalities to evolve and for people to change their habits.
The consequences of a revolution are to be studied over the decades following the event. Take smalltalk for instance. Smalltalk adoption was not that great, however it brought a paradigm shift that directly influenced languages such as Ruby, Python and Objective-C.
So, again, do not focus on the adoption but instead look at the influence of the Ruby revolution and the ripple effect around it.</p>
]]></content>
		</item>
		
		<item>
			<title>the ruby revolution is over</title>
			<link>https://matt.aimonetti.net/posts/2009-11-the-ruby-revolution-is-over/</link>
			<pubDate>Mon, 09 Nov 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-11-the-ruby-revolution-is-over/</guid>
			<description>According to wikipedia, a revolution (from the latin revolutio, &amp;ldquo;a turn around&amp;rdquo;) is a fundamental change in power or organizational structures that takes place in a relatively short period of time.
Somehow, I believe this is exactly what Ruby has done in the programming world, especially with the help of Rails. Over the last few years, Ruby lead a mini revolution in the midst of software development. Thanks to Ruby, developers now look at software development differently.</description>
			<content type="html"><![CDATA[<p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/Eug%C3%A8ne_Delacroix_-_La_libert%C3%A9_guidant_le_peuple.jpg/300px-Eug%C3%A8ne_Delacroix_-_La_libert%C3%A9_guidant_le_peuple.jpg" alt="Liberté guidant le peuple - Eugene Delacroix posted by Matt Aimonetti"></p>
<p>According to wikipedia, a <strong>revolution</strong> (from the latin <em>revolutio</em>, &ldquo;a turn around&rdquo;) is a fundamental change in power or organizational structures that takes place in a relatively short period of time.</p>
<p>Somehow, I believe this is exactly what Ruby has done in the programming world, especially with the help of Rails. Over the last few years, Ruby lead a mini revolution in the midst of software development. Thanks to Ruby, developers now look at software development differently. One thing for sure, it pushed DHH to write Rails and then convinced thousands of people to develop Ruby based applications on a daily basis.</p>
<h3 id="how-did-it-happen">How did it happen?</h3>
<p>Let&rsquo;s take a look at history of revolutions. Some people get frustrated their situation, they try to find workarounds until it&rsquo;s just too much and the revolution kicks in.</p>
<p>Ruby came up with a new holistic perspective on things. Unlike most other programming languages, one of the main key value of Ruby is that writing code should feel right for the developer. You feel good about it because the language was written for humans and not machines. Basically, the language was designed to make you productive because it&rsquo;s designed to please you.</p>
<p>As people were discovering web 2.0, Ruby also came with an opinionated framework, pushing for productivity, testing, simplicity and elegance. People started to see a new way of doing things and it quickly became the new, cool technology. Rails became a buzz word, developers were hired to work on cool projects, and books were selling by the thousands.</p>
<h3 id="what-did-it-change">What did it change?</h3>
<p>If you ask my mom, she would probably say: nothing, except that now my son works from his home office and he seems to really enjoy what he does for living.</p>
<p>Relatively speaking, Ruby did not change the way we work or live. However, I believe that it has influenced many software developers around the globe. Why else do you think that companies like Microsoft, Apple or SAP are working on their own implementation of the Ruby language?</p>
<p>When I first discovered Ruby, I was amazed at how &ldquo;right&rdquo; it felt, at how much fun it was to write code using its syntax and idioms. Now, if I don&rsquo;t get that feeling when testing a programming language, I think there is something wrong.</p>
<p>The Ruby community also revived the Agile/XP world. Testing being a strong value of the community, we spent a lot of time discussing TDD, BDD, integration test as well as other practices such as pair programming, code review, sprints etc..</p>
<p>A few years ago, when people were asking me what programming language I would write their app in, I would reply Ruby and had to explain what it was, why it is great and would have to answer a lot of questions from potential clients. Nowadays, people don&rsquo;t even argue, sites like hulu.com, twitter.com, yellowpages.com and many others are written in Ruby and it&rsquo;s just part of the tools known to work very well.</p>
<h3 id="the-revolution-is-over">The revolution is over!</h3>
<p>Yes, Ruby made it&rsquo;s revolution and the world &ldquo;has changed&rdquo;. But a real movement doesn&rsquo;t die after its revolution, that&rsquo;s actually when it has to be strong and defend its values.</p>
<p>This doesn&rsquo;t mean that Ruby is dead or that Rails is &ldquo;passé&rdquo;. To the contrary, Ruby imposed itself as a new valued and respected player, a new standard if you will.</p>
<p>Ruby is certainly not the &ldquo;new kid in the block&quot;anymore nor the &ldquo;popular kid&rdquo;, however lots of older kids seem to want to have her on their team. (.NET, Java, Objective-C can all use Ruby)</p>
<p>The TDD + Ruby combo doesn&rsquo;t surprise anyone anymore and the Enterprise is slowly but surely adopting Ruby. Ruby is now just getting better, tools and libraries are improving and the amount of users is growing.</p>
<p>Certainly the Ruby community is still small compared to other software developer communities, but the fundamental change was done and we are now working on improvement and keeping things running smoothly, growing and getting new ideas inspired by our experience and other communities.</p>
<p>Long live Ruby!</p>
<p><a href="https://merbist.com/2009/11/16/the-ruby-revolution-take-ii/">See my follow up.</a></p>
]]></content>
		</item>
		
		<item>
			<title>macruby browse for folder or file dialog</title>
			<link>https://matt.aimonetti.net/posts/2009-10-macruby-browse-for-folder-or-file-dialog/</link>
			<pubDate>Sun, 25 Oct 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-10-macruby-browse-for-folder-or-file-dialog/</guid>
			<description>This is yet another pretty simple tip. Use case: let say you want your applications users to choose one or multiple files or folder on their file system. A good example would be that you want the user to choose a file to process or a folder where to save some data.
In the example above, I added a browse button and a text field.
I would like my users to click on the browse button, locate a folder and display it in the text field.</description>
			<content type="html"><![CDATA[<p>This is yet another pretty simple tip.
Use case: let say you want your applications users to choose one or multiple files or folder on their file system. A good example would be that you want the user to choose a file to process or a folder where to save some data.</p>
<p><img src="https://img.skitch.com/20091025-nc89xd2ywqutqqddnwm2met3x4.jpg" alt=""></p>
<p>In the example above, I added a browse button and a text field.</p>
<p>I would like my users to click on the browse button, locate a folder and display it in the text field.</p>
<p>In your MacRuby controller, use a simple action method as well as an accessor to the text field:</p>
<pre><code>attr_accessor :destination_path

def browse(sender)
end
</code></pre>
<p>Now, in Interface builder bind the destination_path outlet to the text field you want to use to display the path and bind the button to the browse action.</p>
<p>Let&rsquo;s go back to our action method and let&rsquo;s create a dialog panel, set some options and handle the user selection:</p>
<pre><code>def browse(sender)
  # Create the File Open Dialog class.
  dialog = NSOpenPanel.openPanel
  # Disable the selection of files in the dialog.
  dialog.canChooseFiles = false
  # Enable the selection of directories in the dialog.
  dialog.canChooseDirectories = true
  # Disable the selection of multiple items in the dialog.
  dialog.allowsMultipleSelection = false

  # Display the dialog and process the selected folder
  if dialog.runModalForDirectory(nil, file:nil) == NSOKButton
  # if we had a allowed for the selection of multiple items
  # we would have want to loop through the selection
    destination_path.stringValue = dialog.filenames.first
  end
end
</code></pre>
<p>That&rsquo;s it, your user can now browse for a folder and the selection will be displayed in the text field. Look at the <a href="https://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSOpenPanel_Class/Reference/Reference.html">NSOpenPanel documentation</a> for more details on the Cocoa API.</p>
]]></content>
		</item>
		
		<item>
			<title>railssummit 2009</title>
			<link>https://matt.aimonetti.net/posts/2009-10-railssummit-2009/</link>
			<pubDate>Fri, 23 Oct 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-10-railssummit-2009/</guid>
			<description>During Rails Summit2009 in São Paulo, Brazil Matt Aimonetti gave a talk entitled The future of Ruby and Rails.
##Description of the talk:
Plans for Rails 3 and tour of the various Ruby implementations.
##Slides
 ##Video
The video of this talk is available here.
##Blog post
I have had the opportunity to go to and speak at many conferences but this year was the first time I had the chance to go to RailsSummit in São Paulo, Brazil.</description>
			<content type="html"><![CDATA[<p>During <a href="https://www.flickr.com/photos/danicuki/sets/72157622452350763/">Rails Summit2009</a> in São Paulo, Brazil Matt
Aimonetti gave a talk entitled <em>The future of Ruby and Rails</em>.</p>
<p>##Description of the talk:</p>
<p>Plans for Rails 3 and tour of the various Ruby implementations.</p>
<p>##Slides</p>
<script async class="speakerdeck-embed" data-id="4f90acc391b203001f002180" data-ratio="1.3333333333333333" src="//speakerdeck.com/assets/embed.js"></script>
<p>##Video</p>
<p>The video of this talk is available <a href="https://blip.tv/agaelebe/ruby-rails-future-matt-aimonetti-rails-summit-2009-2748035">here</a>.</p>
<p>##Blog post</p>
<p>I have had the opportunity to go to and speak at many conferences but this year was the first time I had the chance to go to <a href="https://railssummit.com.br">RailsSummit</a> in São Paulo, Brazil.</p>
<p>I was really looking forward to this trip and I have to say it went beyond my expectations. I had heard really good things from people such as the <a href="https://www.phusion.nl/">Phusion guys</a> (Ninh &amp; Hongli), Gregg Pollack and others.</p>
<p>For those who don&rsquo;t know, RailsSummit is one of the biggest, if not the biggest, Ruby event in Latin America. It&rsquo;s organized yearly by <a href="https://www.locaweb.com.br/">Locaweb</a>, the #1 hosting company in Brazil (props to Akita &amp; Cristiane for their work).</p>
<p><img src="https://farm3.static.flickr.com/2761/4027342992_789777fd03_m_d.jpg" alt=""></p>
<p>As part of my involvement in the Ruby community I have met a lot of Brazilians always willing to help and especially giving time to translate content. (A good example would be the <a href="https://wiki.rubyonrails.org/pt/start">Portuguese version of the Rails wiki</a> or <a href="https://blog.plataformatec.com.br/">José Valim</a> GSOC contribution) However, I did not realize how fast Rails was growing over here.</p>
<p>To come back to the conference, I have to say it was one of the best conference I have gone to. Chad Fowler, who gave the opening keynote, later told me that it reminded him of the first Ruby conferences in the US . For me, what made a huge difference was the fact that it was a very positive conference. People were happy to be here, eager to share and you could feel the passion. Unfortunately, I missed the first few Ruby conferences, but I can totally imagine how must have been. Passionate people, not trying to push their products but instead, share the cool stuff they&rsquo;ve been working on. This is exactly the feeling I had during this conference.</p>
<p>Maybe it&rsquo;s because I don&rsquo;t understand Portuguese well enough or maybe it&rsquo;s just a cultural thing, but the people at the conference were just super friendly and always willing to help. I was really glad to meet those who have been using some of my work, some new people to Ruby and people who don&rsquo;t do Ruby but were just interested in knowing what was going on in the Ruby world.</p>
<p><img src="https://farm3.static.flickr.com/2719/4027357802_1082f38090.jpg" alt=""></p>
<p>The schedule was pretty packed and the discussions very interesting, you could certainly feel the excitement in the air. Ruby seems to catching up quickly over there. Brazilian Rubyists seem to be very pragmatic and a good illustration of that was certainly made by <a href="https://improveit.com.br/en">Vinicus Teles</a>, Brazil Agile XPert, who shared tips on how to release a successful product.</p>
<p>I stayed a few days after the conference and went to visit the Rubyists in Rio. Rio is a great city. It has some of the best soccer players in the world and some seriously talented software developers. Ruby &amp; Rails are not just the new trendy startup secret to success, companies like globo.com, currently the largest TV network in <a href="https://en.wikipedia.org/wiki/Latin_America">Latin America</a> and the fourth largest in the world, also started using Ruby and Rails. I had the opportunity to visit their office and meet their teams. It&rsquo;s very exciting to see how they use Agile/XP and Ruby and how they seem to be so successful. But I will keep that for another post.</p>
<p>Overall, even though the actual traveling to/from Brazil was a bit long, RailsSummit was a blast. I really hope to be able to come back next year, and by then, hopefully my Portuguese will have improved.</p>
]]></content>
		</item>
		
		<item>
			<title>macruby tips capturing keyboard events</title>
			<link>https://matt.aimonetti.net/posts/2009-10-macruby-tips-capturing-keyboard-events/</link>
			<pubDate>Fri, 09 Oct 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-10-macruby-tips-capturing-keyboard-events/</guid>
			<description>If you are writing any type of games you might want your users to interact with your application using their keyboards.
This is actually not that hard. The approach is simple and fast forward if you are used to Cocoa.
Everything starts in Interface Builder, add a custom view instance to your window.
Now switch to your project and a new file with a class called KeyboardControlView and make in inherit from NSView.</description>
			<content type="html"><![CDATA[<p>If you are writing any type of games you might want your users to interact with your application using their keyboards.</p>
<p>This is actually not that hard. The approach is simple and fast forward if you are used to Cocoa.</p>
<p>Everything starts in Interface Builder, add a custom view instance to your window.</p>
<p><img src="https://img.skitch.com/20091010-8tf834wf9se6y81h2jf7a7e5he.jpg" alt=""></p>
<p>Now switch to your project and a new file with a class called KeyboardControlView and make in inherit from NSView. We are creating a subview of NSView so we will be able to make our top view &ldquo;layer&rdquo; use this subclass.</p>
<pre><code>class KeyboardControlView &lt; NSView
  attr_accessor :game_controller

  def acceptsFirstResponder
    true
  end

end
</code></pre>
<p>As you can see in the example above, I added an attribute accessor. attr_accessor class method creates getters and setters. It&rsquo;s basically the same as writing:</p>
<pre><code> def game_controller=(value)
  @game_controller = value
end

def game_controller
  @game_controller
end
</code></pre>
<p>MacRuby is keeping an eye on these accessors and let bind outlets to them.
But let&rsquo;s not get ahead of ourselves, we&rsquo;ll keep that for another time.</p>
<p>Let&rsquo;s go back to our newly created class. Notice, we also added a method called <code>[acceptsFirstResponder](https://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSResponder_Class/Reference/Reference.html#//apple_ref/occ/instm/NSResponder/acceptsFirstResponder)</code> and returns true. <a href="https://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSResponder_Class/Reference/Reference.html#//apple_ref/occ/instm/NSResponder/acceptsFirstResponder">acceptsFirstResponder</a> returns false by default.
But in this case we want it to return true so our new class instance can be first in the responder chain.</p>
<p>Now that our class is ready, let&rsquo;s go back to Interface Builder, select our new custom view and click on the inspector button.</p>
<p><img src="https://img.skitch.com/20091010-1trkxhw2r2paaik3ipa4gtytgg.jpg" alt="">
Click on the (i) icon and in the Class field choose our new KeyboardControlView.
Yep, our new class just shows up by magic, it&rsquo;s also called the lrz effect, just don&rsquo;t ask ;)
So now when our application starts, a new instance of our NSView class is created and Cocoa will call different methods based on events triggered.</p>
<p>The two methods we are interested in reimplementing are keyDown and keyUp. They get called when a key gets pressed or released.</p>
<pre><code>def keyDown(event)
  characters = event.characters
  if characters.length == 1 &amp;&amp; !event.isARepeat
    character = characters.characterAtIndex(0)
    if character == NSLeftArrowFunctionKey
      puts &quot;LEFT pressed&quot;
    elsif character == NSRightArrowFunctionKey
      puts &quot;RIGHT pressed&quot;
    elsif character == NSUpArrowFunctionKey
      puts &quot;UP pressed&quot;
    elsif character == NSDownArrowFunctionKey
      puts &quot;DOWN pressed&quot;
    end
  end
 super
end
</code></pre>
<p>I don&rsquo;t think the code above needs much explanation. The only things that you might not understand are &lsquo;event.isARepeat&rsquo;. This method returns true if the user left his/her finger on the key. The other thing is the use of the &lsquo;super&rsquo; call at the end of the method. Basically, we reopened a method that was already defined and we don&rsquo;t want to just overwrite it, we just want to inject out code within the existing method, so once we are done handling the event, we just pass it back to original method.</p>
<p>Final result:</p>
<pre><code>class KeyboardControlView &lt; NSView
  attr_accessor :game_controller

  def acceptsFirstResponder
    true
  end

  def keyDown(event)
    characters = event.characters
    if characters.length == 1 &amp;&amp; !event.isARepeat
      character = characters.characterAtIndex(0)
      if character == NSLeftArrowFunctionKey
        puts &quot;LEFT pressed&quot;
      elsif character == NSRightArrowFunctionKey
        puts &quot;RIGHT pressed&quot;
      elsif character == NSUpArrowFunctionKey
        puts &quot;UP pressed&quot;
      elsif character == NSDownArrowFunctionKey
    puts &quot;DOWN pressed&quot;
      end
    end
    super
  end

  # Deals with keyboard keys being released
  def keyUp(event)
    characters = event.characters
    if characters.length == 1
      character = characters.characterAtIndex(0)
      if character == NSLeftArrowFunctionKey
       puts &quot;LEFT released&quot;
      elsif character == NSRightArrowFunctionKey
        puts &quot;RIGHT released&quot;
      elsif character == NSUpArrowFunctionKey
       puts &quot;UP released&quot;
      elsif character == NSDownArrowFunctionKey
        puts &quot;DOWN released&quot;
      end
    end
    super
  end

end
</code></pre>
<p>Now it&rsquo;s up to you to handle the other keystrokes and do whatever you want. That&rsquo;s it for this tip, I hope it helps.</p>
]]></content>
		</item>
		
		<item>
			<title>macruby 0 5 beta 1 and textorize</title>
			<link>https://matt.aimonetti.net/posts/2009-10-macruby-0-5-beta-1-and-textorize/</link>
			<pubDate>Wed, 07 Oct 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-10-macruby-0-5-beta-1-and-textorize/</guid>
			<description>Good news everyone!
MacRuby beta 1 has been released! Official announcement here.
[caption id=&amp;quot;&amp;quot; align=&amp;ldquo;aligncenter&amp;rdquo; width=&amp;ldquo;144&amp;rdquo; caption=&amp;ldquo;Download MacRuby 0.5 beta1&amp;rdquo;][/caption]
Note that the download is only for SnowLeopard, intel machines.
Lots of great stuff in this new release, the first one based on LLVM. Check the Laurent&amp;rsquo;s post to learn more about the work done on compilation, optimization, concurrency, compatibility and Cocoa interaction. And a big thank you to Laurent Sansonetti who is putting so much effort in this project!</description>
			<content type="html"><![CDATA[<p>Good news everyone!</p>
<p>MacRuby beta 1 has been released! <a href="https://www.macruby.org/blog/2009/10/07/macruby05b1.html">Official announcement here</a>.</p>
<p>[caption id=&quot;&quot; align=&ldquo;aligncenter&rdquo; width=&ldquo;144&rdquo; caption=&ldquo;Download MacRuby 0.5 beta1&rdquo;]<a href="https://www.macruby.org/files/MacRuby%200.5%20beta%201.zip"><img src="https://www.macruby.org/images/zip.png" alt="Download MacRuby 0.5 beta1"></a>[/caption]</p>
<p>Note that the download is only for SnowLeopard, intel machines.</p>
<p>Lots of great stuff in this new release, the first one based on LLVM. Check the <a href="https://www.macruby.org/blog/2009/10/07/macruby05b1.html">Laurent&rsquo;s post</a> to learn more about the work done on compilation, optimization, concurrency, compatibility and Cocoa interaction. And a big thank you to <a href="https://www.youtube.com/watch?v=BVgM7qeAlko">Laurent Sansonetti</a> who is putting so much effort in this project!</p>
<p>However, don&rsquo;t forget it&rsquo;s still a beta release and you might encounter bugs. Feel free to report them in the bug tracker or ask on the mailing list.</p>
<p>On a different topic, the other day, John Gruber from <a href="https://daringfireball.net/">Daring Fireball</a> <a href="https://daringfireball.net/linked/2009/09/30/textorize">wrote a quick note</a> about <a href="https://mir.aculo.us/2009/09/29/textorize-pristine-font-rendering-for-the-web/">Thomas Fuchs' textorize script</a> which since got its own place on the internet <a href="https://textorize.org/">https://textorize.org/</a>.</p>
<p>Textorize is a Ruby-based font rasterizer command line utility for Mac OS X. It generates PNG files from an input string and options, using Mac OS X&rsquo;s pristine typography facilities. As John said, it&rsquo;s a case where a few lines of Ruby code beat Photoshop.</p>
<p>Thomas version is based on RubyCocoa which is great&hellip; but not MacRuby.</p>
<p>To celebrate<a href="https://www.macruby.org/blog/2009/10/07/macruby05b1.html"> MacRuby 0.5 beta1</a>, I ported the gem over and pushed it to the excellent <a href="https://gemcutter.org/">gemcutter.org facility</a>.</p>
<p>After installing MacRuby beta, follow these directives:</p>
<pre><code>$ macgem sources -a https://gemcutter.org
$ sudo macgem install textorize-mr
$ textorize -f&quot;Didot&quot; -s200 &quot;MacRuby 0.5b1&quot;
$ open output.png
</code></pre>
<p>And you will get a <a href="https://en.wikipedia.org/wiki/Subpixel_antialiasing">subpixel antialiased</a> fancy bitmap like that:</p>
<p><img src="https://merbist.com/wp-content/uploads/2009/10/macruby05b1.png" alt="macruby05b1"></p>
<p>Check <a href="https://textorize.org/">https://textorize.org/</a> for more examples and <a href="https://github.com/mattetti/textorize">https://github.com/mattetti/textorize</a> for the source code.</p>
]]></content>
		</item>
		
		<item>
			<title>macruby tips embed a custom font</title>
			<link>https://matt.aimonetti.net/posts/2009-10-macruby-tips-embed-a-custom-font/</link>
			<pubDate>Tue, 06 Oct 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-10-macruby-tips-embed-a-custom-font/</guid>
			<description>Let say you want to release your MacRuby app and use a custom embedded font? You probably don&amp;rsquo;t want to force your users to install the font. Well, don&amp;rsquo;t worry, just put the font file in your resources folder and use the following code:
font_location = NSBundle.mainBundle.pathForResource(&#39;MyCustomFont&#39;, ofType: &#39;ttf&#39;) font_url = NSURL.fileURLWithPath(font_location) # in MacRuby, always make sure that cocoa constants start by an uppercase CTFontManagerRegisterFontsForURL(font_url, KCTFontManagerScopeProcess, nil)  That&amp;rsquo;s it, now your custom font is available and you can change your textfield instance&amp;rsquo;s font like that:</description>
			<content type="html"><![CDATA[<p>Let say you want to release your MacRuby app and use a custom embedded font?
You probably don&rsquo;t want to force your users to install the font.
Well, don&rsquo;t worry, just put the font file in your resources folder and use the following code:</p>
<pre><code>font_location = NSBundle.mainBundle.pathForResource('MyCustomFont', ofType: 'ttf')
font_url = NSURL.fileURLWithPath(font_location)
# in MacRuby, always make sure that cocoa constants start by an uppercase
CTFontManagerRegisterFontsForURL(font_url, KCTFontManagerScopeProcess, nil)
</code></pre>
<p>That&rsquo;s it, now your custom font is available and you can change your textfield instance&rsquo;s font like that:</p>
<pre><code>text_field.font = NSFont.fontWithName('MyCustomFont', size:24)
</code></pre>
<p>The only tricky things here were to know the Cocoa API call and to know that even if the Cocoa API references the constant to use as kCTFontManagerScopeProcess, because in Ruby, constants start by an uppercase, you need to convert it to: KCTFontManagerScopeProcess.</p>
]]></content>
		</item>
		
		<item>
			<title>macruby tips how to play an audio file</title>
			<link>https://matt.aimonetti.net/posts/2009-10-macruby-tips-how-to-play-an-audio-file/</link>
			<pubDate>Tue, 06 Oct 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-10-macruby-tips-how-to-play-an-audio-file/</guid>
			<description>Let&amp;rsquo;s say you would like to play an audio file in your MacRuby app/script, how would you do? It&amp;rsquo;s actually pretty simple, you just need to use NSSound. If we wanted to use a system sound we could do:
NSSound.soundNamed(&#39;Basso&#39;).play  But let&amp;rsquo;s look at a more advanced example with some Cocoa patterns. We will loop through all the audio files in a folder and we will play them one after the other.</description>
			<content type="html"><![CDATA[<p>Let&rsquo;s say you would like to play an audio file in your MacRuby app/script, how would you do?
It&rsquo;s actually pretty simple, you just need to use NSSound. If we wanted to use a system sound we could do:</p>
<pre><code>NSSound.soundNamed('Basso').play
</code></pre>
<p>But let&rsquo;s look at a more advanced example with some Cocoa patterns. We will loop through all the audio files in a folder and we will play them one after the other.</p>
<pre><code>#!/usr/bin/env macruby
framework 'Cocoa'
# Cocoa documentation reference:
# https://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSSound_Class/Reference/Reference.html

def play_sound
  if @sounds.empty?
    NSApplication.sharedApplication.terminate(nil)
  else
    sound_file = @sounds.shift
    s = NSSound.alloc.initWithContentsOfFile(sound_file, byReference: false)
    puts &quot;previewing #{sound_file}&quot;
    s.delegate = self
    s.play
  end
end

# This is a delegate method called by the sound object
def sound(sound, didFinishPlaying: state)
  play_sound if state
end

# Delegate method called when the app finished loading
def applicationDidFinishLaunching(notification)
  @sounds = Dir.glob(&quot;/System/Library/Sounds/*.aiff&quot;)
  play_sound
end

# We are delegating the application to self so the script will know when
# it finished loading
NSApplication.sharedApplication.delegate = self
NSApplication.sharedApplication.run
</code></pre>
<p>On my machine, I get the following output:</p>
<pre><code>$ macruby macrubysound.rb
previewing /System/Library/Sounds/Basso.aiff
previewing /System/Library/Sounds/Blow.aiff
previewing /System/Library/Sounds/Bottle.aiff
previewing /System/Library/Sounds/Frog.aiff
previewing /System/Library/Sounds/Funk.aiff
previewing /System/Library/Sounds/Glass.aiff
previewing /System/Library/Sounds/Hero.aiff
previewing /System/Library/Sounds/Morse.aiff
previewing /System/Library/Sounds/Ping.aiff
previewing /System/Library/Sounds/Pop.aiff
previewing /System/Library/Sounds/Purr.aiff
previewing /System/Library/Sounds/Sosumi.aiff
previewing /System/Library/Sounds/Submarine.aiff
previewing /System/Library/Sounds/Tink.aiff
</code></pre>
<p>Cocoa delegation might seem a bit strange at first when you come from Ruby. In Ruby we rarely do any type of async delegation so let&rsquo;s quickly look at what&rsquo;s going on in this script.</p>
<p>The first thing we do is loading the cocoa framework which makes total sense, then we define a bunch of methods and finally we get to:</p>
<pre><code>NSApplication.sharedApplication.delegate = self
NSApplication.sharedApplication.run
</code></pre>
<p>We are setting the run loop to delegate to set, which means that when an event is triggered, the delegation method will be called on self (our script).
Once that done, we are starting out run loop.</p>
<p>Once the application is loaded the applicationDidFinishLaunching delegate is being triggered (line 24). At this point, we are looking for all the sound files in the sound system folder and storing them in an instance variable (line 25). Finally, we are calling the play_sound method (line 26).</p>
<p>The play_sound method checks that we have some audio files left to play (line 7), otherwise it quits the app. (line 8 ) If we still have some files in the queue, we get the first one (line 10) and use it to create an instance of NSSound (line 11).</p>
<p>Before playing the NSSound instance, we are setting its delegate to our script (self) (line 13). If you read <a href="https://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSSound_Class/Reference/Reference.html">NSSound Cocoa documentation</a> for #play, you will notice that #play &ldquo;initiates playback asynchronously and returns control to your application. Therefore, your application can continue doing work while the audio is playing.&rdquo; In our case, we don&rsquo;t want to do that, otherwise all the sounds will play at the same time.</p>
<p>The documentation also mentions a delegation you can use to avoid that. This is exactly what we did when we implemented:  def sound(sound, didFinishPlaying: state) (line 19)</p>
<p>Rubyists might be surprised by the method signature. MacRuby extended Ruby to support Objective-C selectors.</p>
<p>When the sound is playing, this delegate gets called, we check on the state of the sound, if it finished playing then we call play_sound again.</p>
<p>That&rsquo;s it!  It&rsquo;s a very elegant implementation giving us the benefits of both Ruby and Cocoa.</p>
]]></content>
		</item>
		
		<item>
			<title>macruby soon to reach a new milestone</title>
			<link>https://matt.aimonetti.net/posts/2009-10-macruby-soon-to-reach-a-new-milestone/</link>
			<pubDate>Mon, 05 Oct 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-10-macruby-soon-to-reach-a-new-milestone/</guid>
			<description>Laurent just posted a MacRuby status update on the mailing list and the first official beta of MacRuby 0.5 should be released pretty soon.
Let&amp;rsquo;s quickly look at Laurent&amp;rsquo;s report:
  Early backtracing support.
  Much better AOT compilation. Parts of the standard library are now pre-compiled for testing.
  Migrated to LLVM top of tree.
  Dispatcher performance is now back to normal (we lost about 30% due to gcc not inlining code).</description>
			<content type="html"><![CDATA[<p>Laurent just posted a <a href="https://bit.ly/2YPwRT">MacRuby status update</a> on the mailing list and the first official beta of MacRuby 0.5 should be released pretty soon.</p>
<p>Let&rsquo;s quickly look at Laurent&rsquo;s report:</p>
<ul>
<li>
<p>Early backtracing support.</p>
</li>
<li>
<p>Much better AOT compilation. Parts of the standard library are now pre-compiled for testing.</p>
</li>
<li>
<p>Migrated to LLVM top of tree.</p>
</li>
<li>
<p>Dispatcher performance is now back to normal (we lost about 30% due to gcc not inlining code).</p>
</li>
<li>
<p>Many bug fixes.</p>
</li>
</ul>
<p>In lay terms, backtracing is what you see when your app crashes or has a problem, it&rsquo;s the list of methods called before the exception was raised and the line where the error happened. Currently the backtrace is similar to what you would have with Ruby 1.9, however objective-c exceptions are not supported and there is still some work to do.</p>
<p>AOT compilation or Ahead Of Time compilation is the process of compiling a script into machine code. I already covered that <a href="https://merbist.com/2009/07/12/compiled-hello-world-with-macruby/">feature earlier</a>. Progress has been made and now some Ruby standard libraries are now pre-compiled in MacRuby. The two main advantages of doing AOT compilation are startup speed and obfuscation. Two important features for desktop applications or for when you want to license your server app.</p>
<p>Updating LLVM doesn&rsquo;t mean much for end users. With the support of the MacRuby team, <a href="https://www.icoretech.org/">Claudio</a> setup a nightly build bot <a href="https://macruby.icoretech.org/">https://macruby.icoretech.org/</a> allowing you to download nightly builds for SnowLeopard. The app is a <a href="https://sinatrarb.com">Sinatra app</a> that could can checkout on github:  <a href="https://github.com/masterkain/macruby-nightlies-web">https://github.com/masterkain/macruby-nightlies-web</a> What&rsquo;s interesting is that Apple is sponsoring both LLVM and MacRuby which will hopefully bring some synergy and help both projects.</p>
<p>Fixed dispatcher, this is a just a perf bug fix only affecting people on trunk.</p>
<p>I personally used MacRuby quite a lot recently. I have been writing a 2D video game for my <a href="https://rubyconf.org/talks/153-writing-2-d-games-for-the-osx-platform-in-ruby">RubyConf talk</a>.</p>
<p><img src="https://img.skitch.com/20091006-kj64ix4up5q8dh4yin38hjrjcp.jpg" alt="">It&rsquo;s a simple game only using Ruby and Cocoa. It&rsquo;s not a fancy game and, no, it doesn&rsquo;t run on the iPhone yet ;)</p>
<p>I never wrote a game in Cocoa and I decided not to use an existing framework like Gosu or cocos2d, instead I decided to write everything from scratch. Using CoreAnimation instead of OpenGL, the task wasn&rsquo;t that hard at all. in less than 1,000 LOC (before refactoring), I have a fully working game.</p>
<p>I will be previewing the game at <a href="https://www.railssummit.com.br/">RailsSummit</a> and will show the code and explain how to get there at <a href="https://rubyconf.org/talks/153-writing-2-d-games-for-the-osx-platform-in-ruby">RubyConf</a>.</p>
<p>When I started getting involved with MacRuby, I really did not think I would write a video game in Ruby and actually enjoy it. At the end of the day, I will more than likely use MacRuby for desktop/mobile/server apps more than games, but it&rsquo;s awesome to be able to use your favorite language to do other things than what you are usually paid to do.</p>
<p>MacRuby is coming along very nicely, and I&rsquo;m really excited about the multitude of new options offered to Ruby developers on OSX and can&rsquo;t wait for 0.5 final and see what people will do with it.</p>
]]></content>
		</item>
		
		<item>
			<title>blog status</title>
			<link>https://matt.aimonetti.net/posts/2009-08-blog-status/</link>
			<pubDate>Sun, 30 Aug 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-08-blog-status/</guid>
			<description>I had people asking me how come I was not blogging as much lately. Well, on top of being really busy, I have been blogging on other blogs such as the official Rails blog.
There aren&amp;rsquo;t a lot of Merb news, we are waiting for Carl and Yehuda to sign out on the 1.1 release and will hopefully soon start the migration work to Rails3. If you want more news about Rails3, check Yehuda&amp;rsquo;s blog and the official Rails blog.</description>
			<content type="html"><![CDATA[<p>I had people asking me how come I was not blogging as much lately. Well, on top of being really busy, I have been blogging on other blogs such as the <a href="https://weblog.rubyonrails.org/">official Rails blog</a>.</p>
<p>There aren&rsquo;t a lot of Merb news, we are waiting for Carl and Yehuda to sign out on the 1.1 release and will hopefully soon start the migration work to Rails3. If you want more news about Rails3, check <a href="https://yehudakatz.com/">Yehuda&rsquo;s blog</a> and the <a href="https://weblog.rubyonrails.com/">official Rails blog</a>. Lots of exciting things are coming up.</p>
<p>Finally, if you are planning on upgrading your Mac to Snow Leopard, <a href="https://weblog.rubyonrails.org/2009/8/30/upgrading-to-snow-leopard">these instructions</a> are also valid for all Ruby developers on an Intel mac.</p>
]]></content>
		</item>
		
		<item>
			<title>ruby rack and couchdb lots of awesomeness</title>
			<link>https://matt.aimonetti.net/posts/2009-07-ruby-rack-and-couchdb-lots-of-awesomeness/</link>
			<pubDate>Mon, 27 Jul 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-07-ruby-rack-and-couchdb-lots-of-awesomeness/</guid>
			<description>Over the weekend, I spent some time working on a Ruby + Rack +CouchDB project. Three technologies that I know quite well but that I never put to work together at the same time, at least not directly. Let&amp;rsquo;s call this Part I.
Before we get started, let me introduce each component:
  Ruby : if you are reading this blog, you more than likely know at least a little bit about, what I consider, one of the most enjoyable programming language out there.</description>
			<content type="html"><![CDATA[<p>Over the weekend, I spent some time working on a Ruby + Rack +CouchDB project. Three technologies that I know quite well but that I never put to work together at the same time, at least not directly.  Let&rsquo;s call this Part I.</p>
<p>Before we get started, let me introduce each component:</p>
<ul>
<li>
<p><a href="https://en.wikipedia.org/wiki/Ruby%20%28programming%20language%29">Ruby</a> : if you are reading this blog, you more than likely know at least a little bit about, what I consider, one of the most enjoyable programming language out there. It&rsquo;s also a very flexible language that lets us do some interesting things. I could have chosen Python to do the same project but that&rsquo;s a whole different topic. For this project we will do something Ruby excels at: reopening existing classes and injecting more code.</p>
</li>
<li>
<p><a href="https://rack.rubyforge.org/">Rack</a>: a webserver interface written in Ruby and inspired by <a href="https://www.wsgi.org/wsgi/">Python&rsquo;s WSGI</a>. Basically, it&rsquo;s a defined API to interact between webservers and web frameworks. It&rsquo;s used by most common Ruby web frameworks, from Sinatra to Rails (btw, Rails3 is going to be even more Rack-focused than it already is). So, very simply put, the webserver receives a request, passes it to Rack, that converts it, passes it to your web framework and the web framework sends a response in the expected format (more on Rack later).</p>
</li>
<li>
<p><a href="https://couchdb.apache.org/">CouchDB</a>: Apache&rsquo;s document-oriented database. RESTful API, schema-less, written in Erlang with built-in support for map/reduce. For this project, I&rsquo;m using <a href="https://github.com/mattetti/couchrest">CouchRest</a>, a Ruby wrapper for Couch.</p>
</li>
</ul>
<h2 id="goal-log-couch-requests-and-analyze-data">Goal: Log Couch requests and analyze data</h2>
<p>Let&rsquo;s say we have a Rails, Sinatra or Merb application and we are using CouchRest (maybe we are using CouchRest and ActiveRecord, but let&rsquo;s ignore that for now).</p>
<p>Everything works fine but we would like to profile our app a little and maybe optimize the DB usage. The default framework loggers don&rsquo;t support Couch. The easy way would be to tail the Couch logs or look at the logs in <a href="https://janl.github.com/couchdbx/">CouchDBX</a>. Now, while that works, we can&rsquo;t really see what DB calls are made per action, so it makes any optimization work a bit tedious. (Note that Rails3 will have some better conventions for logging, making things even easier)</p>
<p>So, let&rsquo;s see how to fix that. Let&rsquo;s start by looking at Rack.</p>
<h2 id="rack-middleware">Rack Middleware</h2>
<p>Instead of hacking a web framework specific solution, let&rsquo;s use Rack. Rack is dead simple, you just need to write a class that has a <em>call</em> method.
In our case, we don&rsquo;t care about modifying the response, we just want to instrument our app. We just want our middleware to be transparent and let our webserver deal with it normally.</p>
<p>Here we go &hellip; that wasn&rsquo;t hard, was it? We keep the application reference in the @app variable when a new instance of the middleware is created. Then when the middleware is called, we just call the rest of the chain and pretend nothing happened.</p>
<p>As you can see, we just added some logging info around the request. Let&rsquo;s do one better and save the logs in CouchDB:</p>
<p>Again, nothing complicated. In our rackup file we defined which Couch database to use and we passed it to our middleware (we change our initialize method signature to take the DB).
Finally, instead of printing out the logs, we are saving them to the database.</p>
<p>W00t! At this point all our requests have been saved in the DB with all the data there, ready to be manipulated by some map/reduce views we will write. For the record, you might want to use the bulk_save approach in CouchDB which will wait for X amount of records to save them in the DB all at once. Couch also let&rsquo;s you send new documents, but only save it to the DB every X documents or X seconds.</p>
<p><img src="https://img.skitch.com/20090726-ebmpgjtrc6x8239ia69kmri1rt.jpg" alt=""></p>
<p>As you can see, our document contains the timestamps and the full environment as a hash.</p>
<p>All of that is nice, but even though we get a lot of information, we could not actually see any of the DB calls made in each request. Let&rsquo;s fix that and inject our logger in CouchRest (you could apply the same approach to any adapter).</p>
<p>Let&rsquo;s reopen the HTTP Abstraction layer class used by CouchRest and inject some instrumentation:</p>
<p>Again, nothing fancy, we are just opening the module, reopening the methods and wrapping our code around the <em>super</em> call (for those who don&rsquo;t know, <em>super</em> calls the original method).</p>
<p>This is all for Part I. In Part II, we&rsquo;ll see how to process the logs and make all that data useful.</p>
<p>By the way, if you make it to <a href="https://www.railssummit.com.br/">RailsSummit</a>, I will be giving a talk on Rails3 and the new exciting stuff you will be able to do including Rack based stuff, CouchDB, MongoDB, new DataMapper etc..</p>
<p><a href="https://railssummit.com.br/"><img src="https://railssummit.com.br/images/banners/en_souPalestrante_210x60.jpg" alt=""></a></p>
]]></content>
		</item>
		
		<item>
			<title>ruby authentication of couchdb requests</title>
			<link>https://matt.aimonetti.net/posts/2009-07-ruby-authentication-of-couchdb-requests/</link>
			<pubDate>Mon, 13 Jul 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-07-ruby-authentication-of-couchdb-requests/</guid>
			<description>CouchDB is an awesome technology. I&amp;rsquo;m lucky enough to work on quite a big project where we decided to switch from MySQL to Couch for various reasons.
One of the many things I like with Couch is that it handles attachments and can replicate them as well as serve them for you using the Erlang based builtin webserver. (you can load balance your dbs and do some other really cool stuff)</description>
			<content type="html"><![CDATA[<p><a href="https://couchdb.apache.org/">CouchDB</a> is an awesome technology. I&rsquo;m lucky enough to work on quite a big project where we decided to switch from MySQL to Couch for various reasons.</p>
<p>One of the many things I like with Couch is that it handles attachments and can replicate them as well as serve them for you using the <a href="https://en.wikipedia.org/wiki/Erlang%20%28programming%20language%29">Erlang</a> based builtin webserver. (you can load balance your dbs and do some other really cool stuff)</p>
<p>Let&rsquo;s take a use case. Let&rsquo;s imagine that you have a web app with logged in users. Every user can have their own avatar.</p>
<p>No big deal, you get the user to upload his/her avatar to your app and add it to the user document in the database. To serve it from the database, you just need to create a proxy in nginx/apache and redirect the virtual avatar url to the protected DB making sure the request is a GET request.</p>
<p>Add to that a caching solution like <a href="https://varnish.projects.linpro.no/">varnish</a> or <a href="https://www.igvita.com/2008/02/11/nginx-and-memcached-a-400-boost/">memcached module for nginx</a> and all your db goodies get cached and served by the cache (server/client) until they get modified.</p>
<p>Now, the problem is when you want to serve authorized attachments. Let&rsquo;s imagine that we want to let our users upload private files, files that should be accessible only by the owner or users designated by the owner.</p>
<p>In this case, a simple <a href="https://en.wikipedia.org/wiki/Nginx">nginx</a> rewrite wouldn&rsquo;t work. We need to authorize attachment requests. Here is a cool way of doing that using nginx and merb&rsquo;s router. (Expect Rails3 router to do the same).</p>
<p>Let&rsquo;s start by setting up nginx and create a proxy for couchdb:</p>
<p>Now that this is done, we are going to use Merb&rsquo;s awesome router to handle the incoming requests. The cool part of this is that we won&rsquo;t be dispatching requests so, going through the router is almost free. (check on the Merb router benchmarks for more info).  Let&rsquo;s edit our router and set a special route for our assets.</p>
<p>We are using a deferred route which gets executed instead of dispatching the request.</p>
<p>If the attachment route is being matched then we are checking what environment we are currently running in. If we are in production or staging environment then we are sending back a rack response to the webserver. The response is just a forward to the proper couchdb document behind the proxy. Of course, before allowing that to happen, we could authenticate the logged in user, log the request and do a couple of other things. You have full access to your models from the router, so authenticating a session isn&rsquo;t a big deal. You could even create temporarily urls like AWS s3 does.</p>
<p>If we are not in production or staging mode, then just redirect the request to couch since we assume you have access to the local db. This way, your asset urls will be working in production and dev. In real life, you&rsquo;ll want to apply the authorization before choosing how to deliver the document/attachment tho as you want it work the same way in development and production.</p>
]]></content>
		</item>
		
		<item>
			<title>compiled hello world with macruby</title>
			<link>https://matt.aimonetti.net/posts/2009-07-compiled-hello-world-with-macruby/</link>
			<pubDate>Sun, 12 Jul 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-07-compiled-hello-world-with-macruby/</guid>
			<description>To celebrate the amazing work being done by Laurent Sansonetti on MacRuby here is a hello world using the new LLVM based compiler. $ echo &amp;quot;p ARGV.join(&#39; &#39;).upcase&amp;quot; &amp;gt; hello_world.rb $ macrubyc hello_world.rb -o macruby_says $ ./macruby_says hello world &amp;quot;HELLO WORLD&amp;quot;
Note that to achieve this result, you need to be using the experimental branch of MacRuby and have LLVM installed. (check the readme available in MacRuby&amp;rsquo;s repo).
Let&amp;rsquo;s quickly look at what we just did.</description>
			<content type="html"><![CDATA[<p>To celebrate the amazing <a href="https://lists.macosforge.org/pipermail/macruby-devel/2009-July/002062.html">work being done by Laurent Sansonetti on MacRuby</a> here is a hello world using the new <a href="https://en.wikipedia.org/wiki/LLVM">LLVM</a> based compiler.
<code>$ echo &quot;p ARGV.join(' ').upcase&quot; &gt; hello_world.rb $ macrubyc hello_world.rb -o macruby_says $ ./macruby_says hello world &quot;HELLO WORLD&quot;</code></p>
<p>Note that to achieve this result, you need to be using the experimental branch of MacRuby and have LLVM installed. (check the <a href="https://svn.macosforge.org/repository/ruby/MacRuby/branches/experimental/README.rdoc">readme</a> available in MacRuby&rsquo;s repo).</p>
<p>Let&rsquo;s quickly look at what we just did.
We created a single line ruby script that takes the passed arguments, joins them and print them uppercase.
Then, we compiled our script into a <a href="https://en.wikipedia.org/wiki/Mach-O">Mach-O</a> object file and produce an executable.</p>
<p>Here is an extract from Laurent&rsquo;s latest status report:</p>
<blockquote>
<p>Produced executables embed all the compiled Ruby code as well as MacRuby, statically.
It can be distributed as is and does not depend on anything MacRuby or LLVM at runtime.
The Ruby source code is compiled into native machine code (same process as we do at runtime with the JIT compiler), so it&rsquo;s also a good way to obfuscate the source code.
The final binary looks like an Objective-C binary (except that it&rsquo;s larger)</p>
</blockquote>
<p>Don&rsquo;t expect to compile Rails just yet, it&rsquo;s still in a preliminary stage.</p>
<p>The final release you should let you pick one of the 2 compilation modes:</p>
<ul>
<li><strong>normal mode</strong>: full ruby specs, compile down to machine code and use LLVM at runtime. (recommended for desktop/server apps)</li>
<li><strong>full mode</strong>: no full ruby spec support, no runtime code generation, no LLVM. (&ldquo;very light application and/or if the environment does not support runtime code generation&rdquo; (<em>hint-hint)</em>)</li>
</ul>
<p>As you can see, <a href="https://macruby.org">MacRuby</a> is moving forward and the experimental branch should soon move to trunk.</p>
]]></content>
		</item>
		
		<item>
			<title>macruby changing the ruby ecosystem</title>
			<link>https://matt.aimonetti.net/posts/2009-05-macruby-changing-the-ruby-ecosystem/</link>
			<pubDate>Wed, 27 May 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-05-macruby-changing-the-ruby-ecosystem/</guid>
			<description>What&amp;rsquo;s MacRuby? MacRuby is an Apple-sponsored, open source, full Ruby implementation on top of Objective-C runtime. In other words, whatever code runs on Ruby 1.9, should/will run on MacRuby. Yes, you read correctly, MacRuby can/will be able to run all your Ruby code. That means that eventually you will even be able to run your Rails/Sinatra/new-sexy-ruby-framework app on MacRuby.
Unlike RubyCocoa, MacRuby is not a bridge, it is a full implementation of the Ruby language on top of Apple&amp;rsquo;s Objective-C runtime.</description>
			<content type="html"><![CDATA[<h3 id="whats-macruby">What&rsquo;s MacRuby?</h3>
<p><a href="https://www.macruby.org/">MacRuby</a> is an Apple-sponsored, open source, full Ruby implementation on top of <a href="https://en.wikipedia.org/wiki/Objective-C">Objective-C</a> runtime. In other words, whatever code runs on Ruby 1.9, should/will run on MacRuby. Yes, you read correctly, MacRuby can/will be able to run all your Ruby code. That means that eventually you will even be able to run your <a href="https://en.wikipedia.org/wiki/Ruby%20on%20Rails">Rails</a>/<a href="https://en.wikipedia.org/wiki/Sinatra%20%28software%29">Sinatra</a>/new-sexy-ruby-framework app on MacRuby.</p>
<p>Unlike <a href="https://en.wikipedia.org/wiki/RubyCocoa">RubyCocoa</a>, MacRuby is not a bridge, it is a full implementation of the Ruby language on top of Apple&rsquo;s Objective-C runtime. Taking a huge shortcut, MacRuby implements the Ruby syntax by aliasing it to the Obj-C language counterpart. A Ruby string instance is really in fact, an instance of <a href="https://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSMutableString_Class/Reference/Reference.html">NSMutableString</a>. This is obviously transparent for you as a developer since you have the same Ruby API, but it also means that MacRuby can make use of the various Objective-C&rsquo;s goodies such as native threads, <a href="https://en.wikipedia.org/wiki/Objective-c#Garbage_collection"> garbage collector</a> in the background as well as the runtime performance.</p>
<p>On top of that, you have full access to the Obj-C API from your Ruby code. (tip: in macirb, try &ldquo;my string&rdquo;.methods(true, true).sort to see the available Ruby + Objective-C methods on your String instance)  The reason why having access to Objective-C is important is because it gives you the possibility to write native <a href="https://en.wikipedia.org/wiki/Cocoa%20%28API%29">Cocoa</a>apps using Ruby. For those who don&rsquo;t know Cocoa, is a set of APIs for MacOSX development.</p>
<p>However, note that even though, the Cocoa support is almost complete and stable, MacRuby is still in development, especially on the Ruby side of things.</p>
<h3 id="what-is-it-not">What is it not?</h3>
<ul>
<li>
<p><a href="https://www.macruby.org/">MacRuby</a> is not a fork of Ruby. Full <a href="https://rubyspec.org/">rubyspec</a> compliance is expected! It&rsquo;s true that MacRuby supports smalltalk/Obj-C method selectors so it might be considered a language superset.</p>
</li>
<li>
<p>MacRuby is not limited to the OSX platform. All its dependencies are open source and could possibly be compiled for other POSIX-based systems such as Linux.. (not done yet)</p>
</li>
<li>
<p>Even if MacRuby&rsquo;s primary goal is to allow you to write efficient Cocoa apps, it does not mean that MacRuby is limited to that.</p>
</li>
<li>
<p>MacRuby doesn&rsquo;t require you to learn Objective-C in order to develop Cocoa apps. (you just need to understand Obj-C selectors)</p>
</li>
</ul>
<h3 id="whats-coming-up">What&rsquo;s coming up?</h3>
<p>The current version of MacRuby (today being the 27th of May 2009) is version 0.4. You might have heard of things about MacRuby crazy performance, <a href="https://en.wikipedia.org/wiki/Low%20Level%20Virtual%20Machine">LLVM</a>, <a href="https://en.wikipedia.org/wiki/AOT%20compiler">AOT compilation</a><a href="https://en.wikipedia.org/wiki/AOT%20compiler">AOT compilation</a> etc&hellip; This is all happening in the &lsquo;experimental&rsquo; branch.</p>
<p>What&rsquo;s going on is that up to MacRuby 0.5, MR was  using YARV (Ruby 1.9 interpreter) on top of Obj-C and which obviously limited MacRuby&rsquo;s  to YARV&rsquo;s performance. After RubyConf 2008, Laurent Sansonetti, MacRuby&rsquo;s lead developer, decided to try removing YARV to only keep its <a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree">AST</a> and experiment with using <a href="https://en.wikipedia.org/wiki/Llvm">LLVM</a> instead of the 1.9 interpreter.</p>
<p>This switch turned out to be very promising and was noticed right away by influential people such as <a href="https://antoniocangiano.com/2009/03/29/why-macruby-matters/">IBM&rsquo;s Antonio Cangiano</a>. Since then, performance and compatibility have increased. Laurent even started working on an Ahead Of Time (AOT) compiler: <a href="https://pastie.org/485095">https://pastie.org/485095</a> What&rsquo;s really impressive is that in this specific example (Fibonacci sequence), <strong>MacRuby&rsquo;s compiled code is faster than Objective-C!</strong> But let&rsquo;s not jump the gun. First this is a very very early prototype and most of your apps won&rsquo;t be using Fib. sequences ;) In this case, MacRuby&rsquo;s recursive method dispatch is faster but again, this is just a proof of concept and even though MacRuby is getting close to Obj-C speed, it&rsquo;s still far from matching Obj-C&rsquo;s impressive performance.</p>
<p>What this basically means is that you will be able to compile your Ruby code down to binary code. Imagine, taking your Rails app and compiling it down to a binary file that you can just push to your server :) But really, what&rsquo;s almost more important is that Ruby will get closer to Objective-C&rsquo;s speed.</p>
<h3 id="why-will-macruby-change-the-ruby-ecosystem">Why will MacRuby change the Ruby ecosystem?</h3>
<p>As a web developer, getting better performance is great. But Ruby is already fast enough. Rails is faster than any PHP framework out there and when doing Merb&rsquo;s benchmarks we proved that Ruby for the web can definitely be fast.</p>
<p>Now if MacRuby ends up running 3-7X faster than Ruby 1.9 (no one can tell for sure), existing Ruby developers will certainly be really pleased but it will probably affect more people outside of our community than within. Let&rsquo;s face it, our community isn&rsquo;t that big but it&rsquo;s growing fast and people are mainly coming to Ruby for its web frameworks. But Ruby has much more than that to offer. Desktop applications, <a href="https://www.railsenvy.com/2009/5/11/rubystein-ruby-meets-wolfenstein">video games</a>, scientific computation and even embedded apps. Apple is betting on Ruby probably because of the fact that they see the potential in the language itself.</p>
<p>Would people still use Java if Ruby is as fast/faster than Java? Probably! Would they think about using Ruby for their next project? I would certainly hope so!</p>
<p>Ruby is viral, it&rsquo;s such a great language, people who have started using it are having a hard time going back to what they used before. But to spread the &lsquo;love&rsquo;, we need to give people the opportunity to discover why Ruby is so great and to do that, we need to make sure Ruby is relevant to them. By making Ruby a realistic option to write desktop/mobile applications, we are targeting a new audience. An experienced audience which will be able to bring a new perspective to our ecosystem and help it grow.</p>
<p>Of course, MacRuby isn&rsquo;t the only implementation out there trying to do that. JRuby and IronRuby are also very interesting projects. My take on it, is that MacRuby will be able to change things because of its new approach and potential community. It will more than likely be the first Ruby implementation compiling down to binary code, it will more than likely be the fastest implementation and it will more than likely draw a different type of developer.</p>
<p>Does it mean that <a href="https://jruby.codehaus.org/">JRuby</a>, <a href="https://www.ironruby.net/">IronRuby</a>, <a href="https://www.infoq.com/news/2009/04/ruby-on-sap">BlueRuby</a> will be useless? Absolutely not! Matz is the first one to encourage diversity and I agree that this is a great way to move forward. These projects solve different problems and all have pros and cons, but they also all share a similar goal: making Ruby a better and more popular language outside of its original community. JRuby, IronRuby and MacRuby bring Ruby to the respective Java, .net and Cocoa communities, and indirectly bring fresh developers to Ruby. These implementations are critical in the way they actually bridge existing communities and in the end, all Rubyists will benefit from it. Also, even though MacRuby and IronRuby are in active development, JRuby is the only mature alternative to MRI/YARV at this point and it proved that Ruby can coexist in a different community as well as contribute a lot of interesting things back to the Ruby community.</p>
<p>To summarize, I see tremendous potential in MacRuby. There is the obvious technical aspect of the implementation, but also the indirect affect MacRuby could have on our community. I believe that MacRuby is an agent of change and will help bringing more diversity to our community. It will change mentalities and push Ruby to places where it&rsquo;s being struggling to make a mark. I can see the so-called &ldquo;Enterprise&rdquo; people looking at Ruby differently. I also think that MacRuby has the potential to be at the origin of a new type of hybrid application, mixing desktop/mobile/distributed applications with centralized web applications. Why not dream of p2p applications/games using a subset of Rails to communicate between each other and with a central server?</p>
<p><a href="https://macruby.org"><img src="https://merbist.com/wp-content/uploads/2009/05/macruby-site.jpg" alt="macruby-site"></a></p>
<p>If you are interested in learning more about MacRuby, check the list of <a href="https://www.macruby.org/documentation.html">resources available on the MacRuby site</a>.</p>
<p>Rich Kilmer and I are also working on a documentation application for Cocoa and <a href="https://www.macruby.org/hotcocoa.html">HotCocoa</a> as well as a MVC framework for writing Cocoa apps using HotCocoa (HotCocoa is a thin, idiomatic Ruby layer that sits above Cocoa and other frameworks).</p>
<p>Make sure to keep an eye on <a href="https://twitter.com/macruby">@macruby</a> and the <a href="https://macruby.org">MacRuby website</a> if you want to keep track of the latest news.</p>
]]></content>
		</item>
		
		<item>
			<title>couchdb with couchrest in 5 minutes</title>
			<link>https://matt.aimonetti.net/posts/2009-05-couchdb-with-couchrest-in-5-minutes/</link>
			<pubDate>Sun, 17 May 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-05-couchdb-with-couchrest-in-5-minutes/</guid>
			<description>The other night, during our monthly SDRuby meetup, lots of people were very interested in learning more about CouchDB and Ruby. I tried to show what Couch was all about but I didn&amp;rsquo;t have time to show how to use CouchDB with Ruby. Here is me trying to do that in 10 minutes or less. I&amp;rsquo;ll assume you don&amp;rsquo;t have CouchDB installed.
Install CouchDB, if you are on MacOSX, you are in luck, download and unzip the standalone package called CouchDBX.</description>
			<content type="html"><![CDATA[<p>The other night, during our monthly <a href="https://sdruby.com">SDRuby meetup</a>, lots of people were very interested in learning more about CouchDB and Ruby. I tried to show what Couch was all about but I didn&rsquo;t have time to show how to use CouchDB with Ruby.
Here is me trying to do that in 10 minutes or less. I&rsquo;ll assume you don&rsquo;t have CouchDB installed.</p>
<p>Install CouchDB, if you are on MacOSX, you are in luck, download and unzip the standalone package called <a href="https://janl.github.com/couchdbx/">CouchDBX</a>.
That&rsquo;s it you have couch ready to go, press play and play with the web interface.</p>
<p>Next, let&rsquo;s write a quick script. Let&rsquo;s say we want to write a script that manages your contacts.</p>
<p>First, let&rsquo;s install CouchRest:</p>
<p><code>$ sudo gem install couchrest</code></p>
<p>Now, let&rsquo;s open a new file and write our script.</p>
<p>In line 4 and 5 we are just setting up the server(by default, localhost is being used). If the database doesn&rsquo;t exist, it will get created.</p>
<p><code>SERVER    = CouchRest.new</code></p>
<p><code>DB           = SERVER.database!('contact-manager') </code></p>
<p>Then, we define your &lsquo;model&rsquo;, we set the default database to use and define a list of properties. Properties are not required, but they generate getters and setters for you. They are also used to set default values and validate your model.  Line 11 shows how to use an alias that will provider a getter and a setter for the property name and the alias name:</p>
<p><code>property :last_name, :alias =&gt; :family_name</code></p>
<p>Line 14 does something that might seem strange at first. We are casting the address property as an instance of the Address class.  Here is what the implementation of the Address class could look like:</p>
<p>Address is just an instance of Hash with some extra methods provided by the CouchRest::CastedModel module. (If you wonder why it&rsquo;s called CastedModel instead of the more grammatically correct CastModel, the answer is simple: I suck at English grammar :p )</p>
<p>So here is a quick example of how to use a &lsquo;CastedModel&rsquo;:</p>
<p>That&rsquo;s part of what&rsquo;s great with CouchDB, you don&rsquo;t need to worry too much about storage. Just define your properties, cast to models if needed and save everything as a document.</p>
<p>For more examples checkout the <a href="https://github.com/mattetti/couchrest/tree/a4e6713aeb04721604553bb03475b11912a6e1ff/spec/fixtures/more">CouchRest spec fixtures</a> and the <a href="https://github.com/mattetti/couchrest/tree/85079a54d98ea90ecbab31cba319f0971904e9a6/examples">examples</a>.</p>
<p>To learn more about couchdb, read the (free) online draft of the <a href="https://books.couchdb.org/relax/">CouchDB book</a> and of course you probably should read the <a href="https://github.com/mattetti/couchrest">CouchRest source on GitHub</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>railsconf 2009</title>
			<link>https://matt.aimonetti.net/posts/2009-05-railsconf-2009/</link>
			<pubDate>Fri, 08 May 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-05-railsconf-2009/</guid>
			<description>During RailsConf 2009 in Las Vegas, Nevada Matt Aimonetti gave a talk entitled Rails 3: Stepping off of the golden path.
##Description of the talk:
Back in December 2008, the Rails and Merb core teams surprised everybody by deciding to merge their teams and focus their energy on a common release: Rails 3.0. On one hand, Rails is famous for being an opinionated Rapid Application Development framework following the well known “convention over configuration” design paradigm.</description>
			<content type="html"><![CDATA[<p>During <a href="https://en.oreilly.com/rails2009/">RailsConf 2009</a> in Las Vegas, Nevada Matt
Aimonetti gave a talk entitled <em>Rails 3: Stepping off of the golden path</em>.</p>
<p>##Description of the talk:</p>
<p>Back in December 2008, the Rails and Merb core teams surprised everybody by deciding to merge their teams and focus their energy on a common release: Rails 3.0. On one hand, Rails is famous for being an opinionated Rapid Application Development framework following the well known “convention over configuration” design paradigm. On the other hand, Merb is known for its performance, extreme modularity and greenfield experimentations. The new unified team is working on having the best of both worlds, but the real questions are:</p>
<p>How does that affect me as a Ruby/Rails/Merb developer? When should I step off of the golden path and why?</p>
<p>Matt Aimonetti, Merb core and Rails team member will take you through the new world of possibilities now available to Rails 3.0 developers. You will see the pros and cons of different options for people desiring to step off the “golden path”. Matt will show concrete examples of application/cases where alternative solutions could be more appropriate and others where you are better off staying on the golden path</p>
<p>##Slides</p>
<script async class="speakerdeck-embed" data-id="4f91748891b203001f01a62c" data-ratio="1.299492385786802" src="//speakerdeck.com/assets/embed.js"></script>
<p>A PDF version can also be downloaded [here]({{ page.slides }}).</p>
<p>##Video</p>
<p>The presentation wasn&rsquo;t recorded.</p>
<p>##Blog post</p>
<p>RailsConf 2009 has now finished.  This time last year, no one would have ever guessed that the Merb and Rails teams would join forces and focus on what will hopefully be known as one of the best Web Frameworks.</p>
<p>It was encouraging to see so many people excited about what&rsquo;s being ported over from Merb and the new options available to people who are currently limited by the existing stack. For those interested in pushing Rails further and doing stuff out of the norm, here are my slides. <a href="https://www.workingwithrails.com/person/5919-arthur-zapparoli">Arthur Zapparoli</a> from <a href="https://www.rubyonrails.pro.br/">Brazilian Rails squad</a> recorded most of the talk and told me he will upload the video ASAP. You can also read <a href="https://yehudakatz.com/2009/05/08/railsconf-wrapup/">Yehuda Katz' blog</a> which covers what he talked about.</p>
<p>It was really great to meet a lot of new people as well as people I only knew via IRC/IM/twitter.</p>
<p>It was a great honor to finally meet <a href="https://twitter.com/dkubb">Dan Kubb</a> (DataMapper), <a href="https://twitter.com/ninh">Ninh Hernandez-Búi</a> &amp; <a href="https://twitter.com/phusion_nl">Hongli McLovin Lai (Phusion)</a>, <a href="https://twitter.com/peterc">Peter Cooper</a> (<a href="https://www.rubyinside.com/">RubyInside</a>), <a href="https://twitter.com/rsim">Raimonds Simanovskis</a> (Oracle adapter for AR), <a href="https://weblogs.java.net/blog/arungupta/">Arun Gupta</a> (Sun/Glassfish),  <a href="https://twitter.com/copiousfreetime">Jeremy Hinegardner</a> (crate), <a href="https://maximilien.org">Michael Maxilien</a> (IBM), Dana Jones (<a href="https://railsbridge.org/">railsbridge</a>), Zach Zolton &amp; Geoff Buesing (CouchRest) and of course the Brazilian crew (lots of awesome .br guys came this year, I&rsquo;m looking forward to RailsSummit) and last but not least, the French speaking crew (I&rsquo;m glad to see Ruby is picking up back home). (I know I&rsquo;m forgetting people&hellip; sorry about that)</p>
<p>It was also really nice to chat with some domain experts like Dave Astels, Aslak Hellesøy, Rich Kilmer, David Chelimsky, Ryan Brown, Derek Neighbors etc.. to get their feedback on various projects I&rsquo;m working on.</p>
<p>Leaving Vegas, I feel like the Rails community is expanding quickly (it was the first RailsConf for 1/4 to 1/5 of the attendees) and that the community is organizing itself to welcome a new audience (better documentation, great initiatives like <a href="https://railsbridge.org/">railsbridge.org</a>, willingness to help), as well as trying to be more available to the &lsquo;Enterprise&rsquo; world.</p>
<p>These feelings were enforced during our Rails Activism BOF and after talking with 3rd party developers and sponsors really trying to solve problems that newcomers to Rails are now facing. This is an exciting time.</p>
<p>##Presentation website</p>
<p>O&rsquo;Reilly wrote <a href="https://en.oreilly.com/rails2009/public/schedule/detail/7539">a page</a> covering this presentation.</p>
]]></content>
		</item>
		
		<item>
			<title>merb 11 delayed</title>
			<link>https://matt.aimonetti.net/posts/2009-04-merb-11-delayed/</link>
			<pubDate>Tue, 14 Apr 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-04-merb-11-delayed/</guid>
			<description>We made the decision to slightly delay the release of Merb 1.1 as we ended up changing the scope of what we wanted to make available in the 1.1 release. If you have been following our releases, you know that this is not something we usually do, but we strongly believe that this is actually something that will save us time for the next release.
The big themes for 1.1 are full Ruby 1.</description>
			<content type="html"><![CDATA[<p>We made the decision to slightly delay the release of Merb 1.1 as we ended up changing the scope of what we wanted to make available in the 1.1 release. If you have been following our releases, you know that this is not something we usually do, but we strongly believe that this is actually something that will save us time for the next release.</p>
<p>The big themes for 1.1 are full Ruby 1.9 support and Rails3 compatibilty: action-orm(previously called active-orm) and the new router.</p>
<p>While on one hand, Ruby 1.9 work is 99% done (we still have a couple of failing specs with action-args) and action-orm just needs to be merged in, on the other hand, the new router currently does more than what we initially planned for. It actually covers stuff we scheduled for 1.2.</p>
<p>Here is a quick preview of what Carl has been working on:</p>
<p>Merb&rsquo;s router is now extracted into a rack middleware library and a bunch of features to try to get &ldquo;mountable apps&rdquo; working in Merb 1.1 have been added.</p>
<p>The proof of concept has been submitted to the Rack development mailing list and the draft is available at:
<a href="https://github.com/carllerche/rack-router/tree/master">https://github.com/carllerche/rack-router</a></p>
<p>Merb, CloudKit, Sinatra and more than likely Rails3 should be using this new rack based router. This is a huge step for the Ruby community!</p>
<p>Here is the abstract explained by carl:</p>
<blockquote>
<p>Conceptually, rack-router allows you to create a two way map between HTTP requests and Rack applications. It is built as a piece of middleware that takes in a set of routes.
When a request comes in, the router will compare that request against the set of routes until it finds one that matches. It then calls the associated rack app.
It can also generate URL&rsquo;s that you can use to link to other mountable apps.
It also goes quite a bit further and attempts to make reusing rack applications completely painless (what we are tentatively calling &ldquo;mountable apps&rdquo;).</p>
</blockquote>
<p>For more information, check the <a href="https://groups.google.com/group/rack-devel/browse_thread/thread/41334bce83cb173f">mailing list thread</a>.</p>
<p>Now that the proof of concept has been accepted, the new implementation needs to be optimized to match the speed of the previous router. Currently the new router is pretty slow compared to 1.x router.</p>
]]></content>
		</item>
		
		<item>
			<title>merb 1011 minor release</title>
			<link>https://matt.aimonetti.net/posts/2009-03-merb-1011-minor-release/</link>
			<pubDate>Tue, 31 Mar 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-03-merb-1011-minor-release/</guid>
			<description>Following the DataMapper 0.9.11 release, we just pushed a new minor Merb release.
This release is mainly targeting new developers and Windows users wanting to install the full Merb stack. Others can simply update their dependencies if they use the dependencies.rb file or install the new gems if nothing is bundled and no hard dependencies are set.
Merb is a metagem which installs a bunch of other gems (merb-core, DataMapper and a lot of small gems).</description>
			<content type="html"><![CDATA[<p>Following the DataMapper 0.9.11 release, we just pushed a new minor Merb release.</p>
<p>This release is mainly targeting new developers and Windows users wanting to install the full Merb stack. Others can simply update their dependencies if they use the dependencies.rb file or install the new gems if nothing is bundled and no hard dependencies are set.</p>
<p>Merb is a metagem which installs a bunch of other gems (merb-core, DataMapper and a lot of small gems). The problem was that Merb was trying to install DM and dm-types, unfortunately, dm-types had a dependency on a gem which couldn&rsquo;t be installed on Windows. All of that is now fixed and Windows users can install Merb 1.0.11 without having to manually pick the gems they need.</p>
<p>This release also includes a fix for people using CouchRest, a CouchDB Document Mapping DSL.</p>
<p>Merb 1.1 is still planned to be released in April. A majority of the work has been done, but since Yehuda and myself are going to be traveling, the release will be slightly delayed.</p>
<p>The great news regarding Merb 1.1 is that, on top of being fully Ruby 1.9 compatible, and using action-orm, and being closer to Rack, Yehuda and Carl have been working on the router to make it awesomer and ready for mountable apps :)</p>
<p>Stay tuned for more news.</p>
<p>date = &ldquo;People&rdquo;
slug = &ldquo;People/merb-1011-minor-release&rdquo;</p>
<p>resources :articles,        :identify =&gt; :id</p>
<p>Otherwise, resource(@article) won&rsquo;t work. (This is usually done by the merb orm plugin and I might add it to CouchRest in the future)</p>
]]></content>
		</item>
		
		<item>
			<title>merb 1010 minor release</title>
			<link>https://matt.aimonetti.net/posts/2009-03-merb-1010-minor-release/</link>
			<pubDate>Wed, 18 Mar 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-03-merb-1010-minor-release/</guid>
			<description>We just pushed a really tiny update because of a bug in 1.0.9 affecting people using: Merb::Config[:max_memory]
Merb::Config[:max_memory] has been fixed and now polls for memory usage every 30s instead of 0.25s. (memory is set in KB)
This new version also uses DataMapper.repository instead of Kernel#repository (DM and Vlad related bug fix)
We are still on schedule for Merb 1.1 which is planned for early April. (If you install Merb from our edge server, the latest version should already be Ruby 1.</description>
			<content type="html"><![CDATA[<p>We just pushed a really tiny update because of a bug in 1.0.9 affecting people using: Merb::Config[:max_memory]</p>
<p>Merb::Config[:max_memory] has been fixed and now polls for memory usage every 30s instead of 0.25s. (memory is set in KB)</p>
<p>This new version also uses DataMapper.repository instead of Kernel#repository (DM and Vlad related bug fix)</p>
<p>We are still on schedule for Merb 1.1 which is planned for early April. (If you install Merb from our edge server, the latest version should already be Ruby 1.9 compatible)</p>
]]></content>
		</item>
		
		<item>
			<title>merb 11 roadmap</title>
			<link>https://matt.aimonetti.net/posts/2009-03-merb-11-roadmap/</link>
			<pubDate>Mon, 02 Mar 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-03-merb-11-roadmap/</guid>
			<description>Yesterday, Carl Lerche, Yehuda Katz and myself had a meeting to discuss Merb 1.1&amp;rsquo;s roadmap.
Key items on the agenda were:
  Ruby 1.9
  Mountable apps
  migration path to Rails3
  After spending some time arguing back and forth, we decided that few things had to happen before we could migrate the current slices to pure mountable apps. Freezing the releases while waiting to get that done doesn&amp;rsquo;t seem like a good idea.</description>
			<content type="html"><![CDATA[<p>Yesterday, Carl Lerche, Yehuda Katz and myself had a meeting to discuss Merb 1.1&rsquo;s roadmap.</p>
<p>Key items on the agenda were:</p>
<ul>
<li>
<p><strong>Ruby 1.9</strong></p>
</li>
<li>
<p><strong>Mountable apps</strong></p>
</li>
<li>
<p><strong>migration path to Rails3</strong></p>
</li>
</ul>
<p>After spending some time arguing back and forth, we decided that few things had to happen before we could migrate the current slices to pure mountable apps. Freezing the releases while waiting to get that done doesn&rsquo;t seem like a good idea.</p>
<h3 id="therefore-here-is-the-plan-for-merb-11">Therefore, here is the plan for Merb 1.1:</h3>
<ul>
<li>
<p><strong>Ruby 1.9 full compatibility</strong> (with the very appreciated help from <a href="https://twitter.com/maiha">Maiha</a> and <a href="https://blog.s21g.com/takiuchi">Genki</a> (preview of their work <a href="https://merbi.st">there</a>)). Because Merb depends on different gems, we also need to work with 3rd party developers to make sure Merb&rsquo;s dependencies are Ruby 1.9 compatible</p>
</li>
<li>
<p><strong>Merb helpers</strong> (fixes, enhancement and missing helpers)</p>
</li>
<li>
<p><strong>Make Merb controllers, rack endpoints</strong>. This is a fully transparent change for the framework users. By making this switch, we offer more flexibility to the router (you can mount a sinatra app for instance) and we adopt the same approach as Rails 2.3 making the transition to 3 much easier and facilitating the implementation of mountable apps. Again, this is an internal change and you won&rsquo;t have to change anything in your application.</p>
</li>
<li>
<p><strong>Router optimization</strong>, Carl has been working on few tricks/optimizations for the router that will be available in 1.1</p>
</li>
<li>
<p><strong>Namespacing</strong>. If we want to make every single application, a potential mountable app, we need to namespace our applications. This is something we already do with slices, but currently generated applications are not namespaced. We are planning on doing that for 1.1 (backward compatible) to make mountable apps easier.</p>
</li>
<li>
<p><strong>ActiveORM</strong>. ActiveORM is an ORM abstraction layer developed by Lori Holden (AT&amp;T interactive) which helps with helpers and other parts of your code accessing your ORM directly. For instance, the errors_for method need to be implemented differently depending on the underlying ORM. ActiveORM offers mapping for the 3 major Ruby ORMs: ActiveRecord, DataMapper and Sequel but let you hook to it if you want to extend ActiveORM to support your own ORM.</p>
</li>
</ul>
<p>date = &ldquo;is&rdquo;
slug = &ldquo;is/merb-11-roadmap&rdquo;</p>
<h3 id="what-about-merb-12">What about Merb 1.2?</h3>
<p>1.2 will focus on mountable apps and we hope to get started on a separate branch before we release 1.1. However, mountable apps are hard to spec and we need a better feedback from the community. Tell us what you like with slices and what you don&rsquo;t like. Let us know how you would like the new mountable apps to work. Be as precise as possible. (you can leave a comment here or on the mailing list)</p>
]]></content>
		</item>
		
		<item>
			<title>merb progress</title>
			<link>https://matt.aimonetti.net/posts/2009-02-merb-progress/</link>
			<pubDate>Fri, 06 Feb 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-02-merb-progress/</guid>
			<description>As they say: fail early, fail often. Well, I&amp;rsquo;ve been failing to blog recently, but as always I have some good excuses ;)
  Yehuda has been blogging a lot about the work done on the merge.
  I have been busy working on probably the awesomest CouchDB Ruby DSL/ORM.
  I have been working with the Rails Activists on the new wiki and many other projects.</description>
			<content type="html"><![CDATA[<p>As they say: fail early, fail often. Well, I&rsquo;ve been failing to blog recently, but as always I have some good excuses ;)</p>
<ul>
<li>
<p><a href="https://yehudakatz.com/">Yehuda</a> has been blogging a lot about the work done on the merge.</p>
</li>
<li>
<p>I have been busy working on probably the <a href="https://github.com/mattetti/couchrest">awesomest CouchDB Ruby DSL/ORM</a>.</p>
</li>
<li>
<p>I have been working with the <a href="https://weblog.rubyonrails.com/activism">Rails Activists</a> on the <a href="https://newwiki.rubyonrails.org">new wiki</a> and many other projects.</p>
</li>
<li>
<p>My sister is visiting from France :)  (most of my free time is not spent in front of a computer anymore :p)</p>
</li>
<li>
<p>I&rsquo;ve been playing with MacRuby (see the end of the post)</p>
</li>
<li>
<p>Ohh and spent some time maintaining Merb and preparing 1.0.9</p>
</li>
</ul>
<h2 id="merb-109">Merb 1.0.9</h2>
<p>Merb 1.0.8.1 has some issues with the merb-cache settings set in init.rb being called twice when you use some Rake tasks. (rake db:automigrate for instance).The problem is due to the fact that the rake tasks load the dependencies twice:</p>
<ul>
<li>
<p>Merb rake file loads all of your app dependencies and their rake tasks. (for instance rake db:automigrate is a rake task coming from merb_datamapper)</p>
</li>
<li>
<p>The task you are invoking might start merb itself to load the models etc.. and starting Merb reloads the dependencies.</p>
</li>
</ul>
<p>Dependencies have the option to have a require block. A require block is a Proc that gets called when the dependency is being required. In the case of 1.8.1, we added a default block to set merb-cache. The problem was that the block was being set and called twice and merb-cache was complaining that the default cache was already setup.</p>
<p>To fix this issue we worked on a band-aid type solution (read: kinda evil but ok). Even if you start Merb multiple times, the init.rb file will no only load once and the dependency require blocks will only be called once. However, in the case of merb-cache, the setup block is being called everytime you go through the bootloader. That&rsquo;s why we added a verification on the block itself. In the long term, we are going to fix things nicely and optimize the way merb-cache loads.</p>
<p>We also addressed some other issues. Some people have been pointed out issues with some merb-helpers and patches were provided by the community (thanks a lot).</p>
<p>Talking about patches, we also accepted a patch fixing a small problem with merb-auth and some open-id servers.</p>
<p>Ruby 1.9.1: We started going through all the different places were things are not compatible yet, most of the work that needs to be done right away is focused on the router. Carl has been working on that and you can check his branch to see how we are doing. During the next week we will try to get things ironed out, we still don&rsquo;t know how we are going to deal with the fact that action-args uses parsetree which is not 1.9.1 compatible.</p>
<p>The upcoming version also gets a brand new feature: memory monitoring by the merb master process. The master process checks that the workers don&rsquo;t use too much memory ( you can set what you consider beign too much memory using Merb::Config[:max_memory]) and if one of the workers reaches the limit, it does a kill -1. It then waits a configured amount of seconds (defaults to 5) then kill using -9.</p>
<p>Finally, we also fixed a bunch of tiny issues.</p>
<p>1.0.9 should be released in the next few days.</p>
<hr>
<h2 id="macruby">MacRuby</h2>
<p>Finally, because for those interested in MacRuby here are my slides from last night&rsquo;s SDRuby meetup:</p>
<p><a href="https://www.slideshare.net/mattetti/macruby-when-objectivec-and-ruby-meet?type=presentation">MacRuby - When objective-c and Ruby meet</a></p>
<p>View more <a href="https://www.slideshare.net/">presentations</a> from <a href="https://www.slideshare.net/mattetti">Matt Aimonetti</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>recent news jan 13 2009</title>
			<link>https://matt.aimonetti.net/posts/2009-01-recent-news-jan-13-2009/</link>
			<pubDate>Tue, 13 Jan 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-01-recent-news-jan-13-2009/</guid>
			<description>Lately, I have been really busy with my business, an upcoming training and some non rails-merb related experimentations. (I&amp;rsquo;m learning objective-c and playing with macruby)
However, here are some of the latest news:
  Merb 1.0.8 should be released soon with some bug fixes and some improvements
  The Merb book got 2 new sections, Sequel and Active Record. I&amp;rsquo;ll be spending quite a lot of time on the book in the next weeks.</description>
			<content type="html"><![CDATA[<p>Lately, I have been really busy with my <a href="https://ma-agile.com">business</a>, an <a href="https://merbclass.com">upcoming training</a> and some non rails-merb related experimentations. (I&rsquo;m learning objective-c and playing with <a href="https://www.macruby.org/trac/wiki/MacRuby">macruby</a>)</p>
<p>However, here are some of the latest news:</p>
<ul>
<li>
<p>Merb 1.0.8 should be released soon with some bug fixes and some improvements</p>
</li>
<li>
<p>The Merb book got 2 new sections, Sequel and Active Record. I&rsquo;ll be spending quite a lot of time on the book in the next weeks.</p>
</li>
<li>
<p>Ted Han is working on reorganizing the <a href="https://wiki.merbivore.com">Merb wiki</a></p>
</li>
<li>
<p>We started a new mailing list for people wanting to help with the <a href="https://groups.google.com/group/rubyonrails-wiki">Rails wiki</a></p>
</li>
<li>
<p>We also started a mailing list for people wanting to help with the <a href="https://groups.google.com/group/rails-activism">activism effort</a></p>
</li>
</ul>
<p>For those in the Phoenix area, next week, <a href="https://yehuda">Yehuda</a> and I will be at <a href="https://integrumtech.com/">integrum</a>/<a href="https://gangplankhq.com/">gangplank</a>&rsquo;s for the <a href="https://phxrails.com/">Phoenix Rails User Group</a>.</p>
<p>We are looking to meeting you all.</p>
]]></content>
		</item>
		
		<item>
			<title>meet the merbists hampton catlin</title>
			<link>https://matt.aimonetti.net/posts/2009-01-meet-the-merbists-hampton-catlin/</link>
			<pubDate>Tue, 06 Jan 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-01-meet-the-merbists-hampton-catlin/</guid>
			<description>Meet today&amp;rsquo;s merbist: Hampton Catlin
I&amp;rsquo;m personally looking forward to seeing Hampton&amp;rsquo;s work migrated to Rails 3 in a few months.
 Matt Aimonetti: Hi Hampton, could you please introduce yourself and tell us what you do for a living.
**Hampton Catlin: **I&amp;rsquo;m Hampton Catlin. I&amp;rsquo;m &amp;ldquo;The Haml Guy&amp;rdquo; as I&amp;rsquo;m apparently termed all the time when introduced. I&amp;rsquo;m an early Rails hacker who has done a lot more than Haml, but whatever.</description>
			<content type="html"><![CDATA[<p><img src="https://farm1.static.flickr.com/156/379744976_8f241811fe_m.jpg" alt="Matt Aimonetti interviewing Hampton Catlin"></p>
<p>Meet today&rsquo;s merbist: <a href="https://hamptoncatlin.com/">Hampton Catlin</a></p>
<p>I&rsquo;m personally looking forward to seeing Hampton&rsquo;s work migrated to Rails 3 in a few months.</p>
<p> </p>
<p><strong>Matt Aimonetti</strong>: Hi Hampton, could you please introduce yourself and tell us what you do for a living.</p>
<p>**Hampton Catlin: **I&rsquo;m Hampton Catlin. I&rsquo;m &ldquo;The Haml Guy&rdquo; as I&rsquo;m apparently termed all the time when introduced. I&rsquo;m an early Rails hacker who has done a lot more than Haml, but whatever. These days, I&rsquo;m doing a ton of iPhone development and am currently heading Wikimedia&rsquo;s efforts for a new mobile platform&hellip; based on Merb!</p>
<p> </p>
<p><strong>Matt Aimonetti</strong>: How did you get started with Ruby, what&rsquo;s your background?</p>
<p><strong>Hampton Catlin</strong>: Well, everyone is welcome to laugh. But Slashdot introduced me to Ruby. I got into it about two months before Rails because the hotness (it was an obscure project at the time) and I grabbed a copy of the Pickaxe and never looked back. Prior to that I was working a crappy job getting people coffee at a bank. And then prior to that I was doing research for Nasa at my university with Java beuwolf clusters. It sounds fancier than it was.</p>
<p> </p>
<p><strong>Matt Aimonetti:</strong> You chose to learn and use Merb, could you please let us know why and how that happened?</p>
<p>**Hampton Catlin: **I had known of Ezra for a while and Yehuda. And so when I heard about the project, I was very interested. At the time I was looking forward to using a &ldquo;Rails Light&rdquo;. Of course, we know Merb is much more than that, but that was the original attraction.</p>
<p>Also, at some point I got really upset by the use of global variables in both of the frameworks, so I did some major patching to Merb to change over to module based constants. Aka, Merb.root instead of MERB_ROOT. I was ranting about it enough that I decided to do something about it. Also, I did some patches that messed up Merb with some weird documentation stuff. Sorry, Ezra.</p>
<p> </p>
<p><strong>Matt Aimonetti</strong>: Do you have some Merb projects available online we can look at? what was your experience so far?</p>
<p><strong>Hampton Catlin</strong>: My most successful iPhone app (which was recently purchased by Wikimedia) was an app to browse Wikipedia. I chose Merb because I knew that I wanted something a little more bare bones than Rails, and it turned out to be a really good choice. And now, I&rsquo;m getting a chance to extend that work into an entire platform for Wikimedia mobile. I am still looking for help with it&hellip;.<a href="https://github.com/hcatlin/wikimedia-mobile/tree/master">https://github.com/hcatlin/wikimedia-mobile/tree/master</a>
Its not live yet with wikipedia, but that&rsquo;s the code that you can help with! :)</p>
<p> </p>
<p><strong>Matt Aimonetti</strong> What is your favorite aspect of the Merb framework?</p>
<p>**Hampton Catlin: **Its modular design. Its as complex or as simple as you would like it to be. Also, its easy to run Haml, and the more people that use Haml, the harder my nipples get.</p>
<p> </p>
<p><strong>Matt Aimonetti</strong> Could you please mention an aspect of Merb you hope to see being improved in the near future?</p>
<p><strong>Hampton Catlin</strong>: Honestly, everyone is wild about gems, but I&rsquo;m not particularly. I find gem management a bit cumbersome. I&rsquo;m most likely doing something wrong or not doing it the right way. But yeah, I still find it cumbersome. I&rsquo;d like to pair the excellent Gem support with better library creation support. I think both are needed. I don&rsquo;t want to throw stuff in my /lib folder or randomly in my project. I want some structure and some simplicity. Somewhere between plugins and base libraries. I think this is where Merb <em>could</em> shine.</p>
<p>Also, resource handling. I wrote make_resourceful for Rails and I keep needing to do something similar for Merb. m_r is not very popular because I haven&rsquo;t really put much time into spreading the word. Mostly, I just use it. However, there are about 60 other Rails developers in the world that use it extensively. So, its a small, close-knit group of developers using the tool. And, I think something like it could be much more elegantly mixed into Merb. Obviously its a plug-in, but I think its a low hanging fruit. &ldquo;current_object&rdquo; as a method should ALWAYS be around when its logical.</p>
<p> </p>
<p><strong>Matt Aimonetti</strong> Thank you for your time. Anything else you would like to add?</p>
<p><strong>Hampton Catlin</strong>: Buy my book. Buy my book. Buy my book. Buy my book. Buy my book. Buy my book. Buy my book. Buy my book. Buy my book. Buy my book. Ok, not really. My book isn&rsquo;t very good. But, I just wanted to make a &ldquo;The Critic&rdquo; reference.</p>
<p> </p>
]]></content>
		</item>
		
		<item>
			<title>presenting the rails activists</title>
			<link>https://matt.aimonetti.net/posts/2009-01-presenting-the-rails-activists/</link>
			<pubDate>Mon, 05 Jan 2009 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2009-01-presenting-the-rails-activists/</guid>
			<description>Today is Monday. I usually don&amp;rsquo;t like Mondays. Being Monday goes with waking up early, going back to work, and lots of deadlines.
However, today is a special Monday. It&amp;rsquo;s the first Monday of the year and I have a special announcement!
During the Rails/Merb merge announcement, it was mentioned that I will be joining the soon to be created &amp;ldquo;Evangelism team&amp;rdquo;.
A few people asked me what being a &amp;ldquo;Rails Evangelist&amp;rdquo; means.</description>
			<content type="html"><![CDATA[<p>Today is Monday. I usually don&rsquo;t like Mondays.
Being Monday goes with waking up early, going back to work, and lots of deadlines.</p>
<p>However, today is a special Monday. It&rsquo;s the first Monday of the year and I have a <strong>special announcement</strong>!</p>
<p>During the Rails/Merb merge announcement, it was mentioned that I will be joining the soon to be created <strong>&ldquo;Evangelism team&rdquo;</strong>.</p>
<p>A few people asked me what being a <strong>&ldquo;Rails Evangelist&rdquo;</strong> means. To reassure my parents and close friends, no, <em>I didn&rsquo;t join a new cult worshiping locomotives</em>. However, I still think that public transportation should be improved, especially in this time of crisis (but that&rsquo;s a different topic).</p>
<p>A technical evangelist, is usually someone who knows and uses a specific technology and thinks others should look into it. This is something I&rsquo;ve been doing for Merb while being part of the core team. I initiated and helped organizing MerbCamp, re-did the wiki, started working on the merb-book, spent time looking for and listening to users, spent time with third party developers and people pushing Merb to a new level (YellowPages, Wikimedia and many others).</p>
<p>This interaction with the end users and the third party developers is something the entire Merb team valued a great deal and I always felt it was something the community really appreciated.</p>
<p>As part of the merge, it was agreed that we would push things further and have a team within the Rails team to take care of &ldquo;communication&rdquo;. Rails is a bigger project than Merb and communication between the dev team and the users isn&rsquo;t always something easy to do.</p>
<p>That&rsquo;s why we have formed a separate team that will help communicate and support the community better. We now even have <a href="https://rubyonrails.org/activists">an official page on the Rails website</a> itself :)</p>
<h2 id="the-rails-activists">The Rails Activists</h2>
<p><a href="https://merbist.com/wp-content/uploads/2009/01/ateam.jpg"><img src="https://merbist.com/wp-content/uploads/2009/01/ateam-300x225.jpg" alt=""></a>The A-Team <a href="https://weblog.rubyonrails.org/2009/1/5/announcing-the-rails-activists">just got announced on the Rails blog</a>.</p>
<p>Instead of being called &ldquo;evangelists&rdquo;, we are going to be called &ldquo;activists&rdquo;. I think part of the argument was that the E-Team doesn&rsquo;t sound as good as the A-Team.</p>
<p>We started with team of 4. You might not know them yet but they all are brilliant people and I&rsquo;m really glad to be working with them.</p>
<p><img src="https://weblog.rubyonrails.com/assets/2009/1/4/gregg_pollack.png" alt=""><strong>Gregg Pollack</strong>, from Rails Envy. You might remember Gregg from the Rails vs * commercials or from the Rails Envy podcasts. I&rsquo;ve known Gregg for a little while and he&rsquo;s someone you can rely on and always full of energy/new ideas.</p>
<p><img src="https://weblog.rubyonrails.com/assets/2009/1/4/ryan_bates.png" alt="">**
Ryan Bates**, mainly known for his Railscasts. I only met Ryan once in person, but I&rsquo;ve always been impressed by his work (don&rsquo;t tell anyone, but I secretly dreamt of having something like Railscasts but for Merb :) )</p>
<p><img src="https://weblog.rubyonrails.com/assets/2009/1/4/mike_gunderloy.png" alt=""><strong>Mike Gunderloy</strong>. I actually did not know Mike but I have read and enjoyed his <a href="https://afreshcup.com/">blog</a> and have seen his work on the Rails guides. Mike is an experienced writer and developer. He joked the other day saying that he started programming before any member of the Rails team was even born. Mike is a great addition to the team and I&rsquo;m looking forward to learning from his experience.</p>
<p>Gregg and Ryan also covered the event, you might want to check their blog posts (<a href="https://www.railsenvy.com/2009/1/5/the-rails-activist-team">Gregg&rsquo;s</a> and <a href="https://afreshcup.com/2009/01/05/announcing-the-rails-activists/">Mike&rsquo;s</a>)</p>
<h2 id="so-what-are-we-going-to-do">So what are we going to do?</h2>
<p>Pretty simple. We&rsquo;ve boiled it down to 2 sentences:</p>
<blockquote>
<p>The mission of the Rails Activists is to empower and support the worldwide network of Ruby on Rails users. We do this by publicizing Rails, making adoption easier, and enhancing developer support.</p>
</blockquote>
<p>if you prefer a few more details, here are some of the tasks we are going to work on:</p>
<ul>
<li>
<p>Public Relations with media of all sizes</p>
</li>
<li>
<p>Ombudsman work to ensure good user-to-user support</p>
</li>
<li>
<p>Community Leadership at events and conferences</p>
</li>
<li>
<p>Media Organization to help create good promotional opportunities</p>
</li>
<li>
<p>Website maintenance</p>
</li>
<li>
<p>Documentation efforts</p>
</li>
<li>
<p>Developer support</p>
</li>
</ul>
<h2 id="do-we-need-help">Do we need help?</h2>
<p><strong>Absolutely!</strong> The idea is not that we are going to do all the work. The concept of this new team is to help organize the community. We are going to build a Rails Network, a network of people involved in local Rails &ldquo;evangelism&rdquo;/activism, people contributing and/or translating documentation, third part developers etc&hellip;</p>
<p>First thing would be to <a href="https://groups.google.com/group/rails-activism">join the mailing list</a> and share your suggestions, comments, concerns, etc., with us.</p>
<p>Secondly, we have already set up some forums to hear your feedback.</p>
<p>To start off, we are asking people to let us know what they <a href="https://rails.uservoice.com/">would like to see happening in the Rails3 timeframe</a>.
We have other forums for more <a href="https://rails.uservoice.com/pages/general_feedback">general feedback</a>, but we need to work with deadlines so we can prioritize accordingly. Using the Rails3 milestone should help us focus on a short/medium term deadline. <a href="https://rails.uservoice.com/pages/rails_future">Long term and not specific suggestions</a> are welcome in the other forums.</p>
<p>Finally, contact us. You can find multiple ways to do so on the <a href="https://rubyonrails.org/activists">activism team web page</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>latest merb and rails 30 news</title>
			<link>https://matt.aimonetti.net/posts/2008-12-latest-merb-and-rails-30-news/</link>
			<pubDate>Mon, 29 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-latest-merb-and-rails-30-news/</guid>
			<description>Foy Savas, author or the &amp;ldquo;merb way&amp;rdquo; wrote a very well written post on &amp;ldquo;Rails monoculture&amp;rdquo;
  Pat Eyler, wrote an article asking if Rails and Merb would be better together.
  Ben Aldred, tell people to stop worrying and start loving Rails 3.
  fotonauts.com a Rails and Merb Photo website developed by an ex-apple team, was featured in TechCrunch. Fotonauts is the perfect example of an app that will bain a lot from the merge.</description>
			<content type="html"><![CDATA[<p><a href="https://foysavas.com"><img src="https://merbist.com/wp-content/uploads/2008/12/foy-savas-1.png" alt=""></a></p>
<ul>
<li>
<p><a href="https://foysavas.com">Foy Savas</a>, author or the &ldquo;<a href="https://my.safaribooksonline.com/9780321601636">merb way</a>&rdquo; wrote a very well written <a href="https://www.foysavas.com/blog/2008/12/25/lets-be-clear-the-rails-monoculture-is-over.html">post on &ldquo;Rails monoculture&rdquo;</a></p>
</li>
<li>
<p><a href="https://on-ruby.blogspot.com/">Pat Eyler</a>, wrote an article asking if <a href="https://on-ruby.blogspot.com/2008/12/rails-and-merb-better-together.html">Rails and Merb would be better together</a>.</p>
</li>
<li>
<p><a href="https://www.geekmade.co.uk/">Ben Aldred</a>, tell people to <a href="https://www.geekmade.co.uk/2008/12/stop-worrying-and-start-loving-rails-3/">stop worrying and start loving Rails 3</a>.</p>
</li>
<li>
<p><a href="https://www.fotonauts.com/">fotonauts.com</a> a Rails and Merb Photo website developed by an ex-apple team, was <a href="https://www.techcrunch.com/2008/12/24/fotonauts-opens-up-a-little-more-skip-the-5000-long-waitlist/">featured in TechCrunch</a>. Fotonauts is the perfect example of an app that will bain a lot from the merge.</p>
</li>
<li>
<p><a href="https://yehudakatz.com">Yehuda</a> has been blogging a lot about every single step and even though most people are enjoying a well deserved break, you can read the <a href="https://yehudakatz.com/2008/12/26/dispatch-from-the-front-lines/">details</a> <a href="https://yehudakatz.com/2008/12/27/status-memorandum/">of</a> the <a href="https://yehudakatz.com/2008/12/29/another-rails-2x3-update/">work</a> started on the merge.</p>
</li>
</ul>
<p>Basically, the work started, we are getting familiar with the rails code base and are optimizing things slowly but surely with a focus on testing JRuby. The Merb router is being optimized and ported over to Rails 3.0. Rails and Merb developers will be able to stick to their DSL (so we stay backward compatible). Merb bootloader is also being ported over without breaking the backward compatibility. Finally, ActiveSupport is being broken down in more manageable/independant chunks so people will be able to pick only what they want to use. A &ldquo;mini&rdquo; version is also on the work.</p>
<ul>
<li>
<p><a href="https://yehudakatz.com/2008/12/28/merb-107-release-notes/">Merb 1.0.7 got released</a> yesterday with a bunch of bug fixes.</p>
</li>
<li>
<p>merb_sequel 1.0 should be released sometime this week and i&rsquo;m planning on adding rails i18n syntax support to merb_babel.</p>
</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>merb rails merge or why should merbists be happy</title>
			<link>https://matt.aimonetti.net/posts/2008-12-merb-rails-merge-or-why-should-merbists-be-happy/</link>
			<pubDate>Thu, 25 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-merb-rails-merge-or-why-should-merbists-be-happy/</guid>
			<description>December 23, 2008, was an important day for the Ruby community. People who used to argue and not get along, have decided to sit down, talk and evaluate their differences. The end result is a strong collaboration of two teams who share the exact same goal.
Overall, the news was very well received, just look at the tweets out there and the comments on Yehuda&amp;rsquo;s and Rails&#39; blogs.
Interestingly enough, the Rails community really embraced this decision and just got totally excited about the perspective of merging merb&amp;rsquo;s philosophy and expertise into Rails.</description>
			<content type="html"><![CDATA[<p><a href="https://flickr.com/photos/xrrr/2478140383/"><img src="https://farm4.static.flickr.com/3211/2478140383_8e2e4ab7a3_m.jpg" alt=""></a>December 23, 2008, was an important day for the Ruby community. People who used to argue and not get along, have decided to sit down, talk and evaluate their differences. The end result is a strong collaboration of two teams who share the exact same goal.</p>
<p>Overall, the news was very well received, just look at the tweets out there and the comments on <a href="https://yehudakatz.com/2008/12/23/rails-and-merb-merge/">Yehuda&rsquo;s</a> and <a href="https://weblog.rubyonrails.org/2008/12/23/merb-gets-merged-into-rails-3">Rails' blogs</a>.</p>
<p>Interestingly enough, the Rails community really embraced this decision and just got totally excited about the perspective of merging merb&rsquo;s philosophy and expertise into Rails. If you re-read David&rsquo;s blog post you can see that it&rsquo;s a <strong>real homage to Merb</strong>.</p>
<p>The rest of the internet sounds pretty happy about the news, here are few posts:</p>
<ul>
<li>
<p><a href="https://arstechnica.com/news.ars/post/20081224-ruby-on-rails-and-merb-to-merge-for-rails-3.html">arstechnica.com</a></p>
</li>
<li>
<p><a href="https://www.internetnews.com/dev-news/article.php/3793296/Merb+Merges+With+Rails.htm">internetnews</a></p>
</li>
</ul>
<p>Even <a href="https://www.zedshaw.com">Zed the entertainer</a> thought it was a good thing:</p>
<blockquote>
<p><a href="https://www.zedshaw.com/blog/index.html">&ldquo;I honestly didnâ€™t think that would ever happen. I just assumed that Merb
would eventually wipe out Rails by being the better framework, or theyâ€™d
wipe each other out soon.</a></p>
</blockquote>
<p><a href="https://www.zedshaw.com/blog/index.html">So, congrats are in order. You guys are finally grown-ups and now have
the chance to make something better.&quot;</a></p>
<p>Some <a href="https://iamruinous.com/2008/12/23/why-merb-becoming-rails-3-is-a-good-thing/">merbists like Jade Meskill</a> really understood what we are trying to do while some other ones got really <a href="https://www.mr-eel.com/archives/158">mad at us</a>.</p>
<p>I think a pattern emerged from the negative reactions:</p>
<ul>
<li>
<p>Why merge when we are about to win?!</p>
</li>
<li>
<p>What does Merb win by being merged into Rails?</p>
</li>
<li>
<p>Why not merge Rails into Merb?</p>
</li>
<li>
<p>You are killing innovation by killing the competition</p>
</li>
<li>
<p>You screwed us over and now I have to go &ldquo;back&rdquo; to Rails</p>
</li>
<li>
<p>Rails 3.0 won&rsquo;t even be as good as Merb 1.x</p>
</li>
<li>
<p>The Rails team won&rsquo;t let you do what you have to do to merge Merb into Rails</p>
</li>
<li>
<p>DHH is a jerk</p>
</li>
</ul>
<p>Let me quote Yehuda:Â  <strong>&ldquo;Calm yourselves ;)&quot;</strong>.</p>
<h2 id="why-merge-when-we-are-about-to-win">Why merge when we are about to win?!</h2>
<p>This is probably the most rational argument. This is also something the Merb core team considered for a little bit.
Merb is gaining huge momentum and the target audience was very reactive to what we did.
<a href="https://flickr.com/photos/mhaithaca/1317815300/"><img src="https://farm2.static.flickr.com/1087/1317815300_095983272e_m.jpg" alt=""></a>People such as Yellow Pages, Wikipedia and even Adobe started using or looking seriously at Merb because of its focus on modularity and performance.
We started building an elite community and we were pretty proud of that.</p>
<p>But take a moment to think about it. Our goal has never been to hurt or compete with Rails. Our goals were to get modularity, performance and a strong API. If the Rails team really wants that, and will work on it, why should we work against each other?
It&rsquo;s not about winning or losing. It&rsquo;s all about the long term plan of your framework, about the people involved and the community behind it. We had to take ourselves out of the equation and consider what would be good for the Ruby community.</p>
<h2 id="what-does-merb-win-by-being-merged-into-rails">What does Merb win by being merged into Rails?</h2>
<p>People seem to easily find things we might lose but have a hard time finding things we are gaining.
<img src="https://merbist.com/wp-content/uploads/2008/12/rails.png" alt="">Looking at it on the very short term, this is probably correct. The merb team will have to learn how to work with the Rails team.
We need to understand the reasons behind every single aspect of the code and find ways of merging things nicely.
On top of that, we still need to work on merb as promised. (see Wycats' post)</p>
<p>However, in the long term we get all the benefits of Rails:</p>
<ul>
<li>stability</li>
<li>community</li>
<li>traction</li>
<li>experience</li>
<li>don&rsquo;t have to always justify why use Merb instead of Rails</li>
</ul>
<p>But more importantly, we extend our team.</p>
<p>Most people using a framework might not realize what it is to work on a big Open Source project.
When you work on an OSS project, people come and go, and that&rsquo;s why you usually have a core team of people you can rely on.
Merb has a lot of contributors but a small core team of 5 people (Yehuda, Carl, Daniel, Michael and myself).
Managing a project, such as merb, requires a tremendous amount of time and patience. Rails has the same problem with its core team of 6 people. People have lives, business, projects etc&hellip;</p>
<p>Joining two teams of experts in developing web frameworks in Ruby is like if in the next Soccer World Cup, the French and Italian teams would go on the fields at the same time to beat other teams. 22 players on 1 side, training and learning together. American readers, please imagine the Giants and the Colts facing the Green Bay Packers (I was told I don&rsquo;t like the Packers).</p>
<p>Long term, you will get better quality and more frequent releases. We also have different world views and backgrounds which means we will learn a lot from each other, again that means better code for you guys :)</p>
<h2 id="why-not-merge-rails-into-merb">Why not merge Rails into Merb?</h2>
<p>That&rsquo;s actually a good question. We discussed maybe using merb-core as a base for Rails 3.0
The truth is that Merb 2.0 would probably be as big as Rails but more modular.
So we have the choice to keep on building on top of Merb 2.0 or deconstruct Rails.
As the Russians say: &lsquo;Ð»Ð¾Ð¼Ð°Ñ‚ÑŒ â€” Ð½Ðµ ÑÑ‚Ñ€Ð¾Ð¸Ñ‚ÑŒ&rsquo;, it&rsquo;s always easier to take things apart ;)</p>
<p><img src="https://farm4.static.flickr.com/3033/2814371262_04b9876490_m.jpg" alt="">Rails already has a test suite, it has already been tested on the wild for a while and its internals are known to many developers. Taking apart the code to make it faster, cleaner and more modular is arguably easier than reinventing the wheel. At the end of the day it doesn&rsquo;t really matter from which end you start as long as you end up with the same result.</p>
<p>Some people even asked to come up with a new name for the merged project. Meails, Mr Ails, Reverb, Reab were suggested. While I thought it was a joke, some people were really serious. Can you imagine if during the recent bailout, banks changed names every time they were purchased by another bank? People would be super confused and would not even know where to send their mortgage payments.
On top of that, Rails has a huge user base compared to Merb and has an immense brand recognition in the world at large, it would be foolish to throw that away.</p>
<p>Let&rsquo;s not be chauvinistic and see what&rsquo;s best for all.</p>
<h2 id="you-are-killing-innovation-by-killing-the-competition">You are killing innovation by killing the competition</h2>
<p>Again, a good point but my question to you is: Should we stay in the competition just for the sake of it?</p>
<p>Rails clearly told us: we want what you have and we would love you to work with us. So the options were:</p>
<ul>
<li>
<p>tell them to go to hell and let them try to redo what we already did and know how to do.</p>
</li>
<li>
<p>accept to work with them and make Rails a better framework.</p>
</li>
</ul>
<p><em>Option 1</em> would keep the competition alive, but now you have 2 groups of people trying to do the same thing and being better at different aspects. The community gets confused and communication breaks.</p>
<p><em>Option 2</em>: we lose the Merb vs Rails competition, but we double the amount of people working on Rails and therefore increase the change to make it better faster.</p>
<p>We went for option 2 and we know there is already some competition out there and there will be more coming up soon. I don&rsquo;t think it&rsquo;s realistic to expect us not to merge because we want to keep the competition going.</p>
<h2 id="you-screwed-us-over-and-now-i-have-to-go-back-to-rails">You screwed us over and now I have to go &ldquo;back&rdquo; to Rails</h2>
<p>Yehuda will blog about some more detailed examples as we are making progress, but you need to stop thinking that Merb will just be absorbed into Rails.
If Rails just wanted to add some &ldquo;Merb flavor&rdquo; to Rails, they would have just taken whatever they needed and would not be interested in a merge.
See Rails 3.0 as a new generation of Rails, whatever we promised you for merb 2.0 plus all the goodies from Rails. Rails users will still have their default stack and all choices will be made for them (like in the current Merb stack). The difference for standard Rails user will be better performance, a static API and an option to go off the &ldquo;golden path&rdquo;.
Merbists won&rsquo;t lose the stuff they like in Merb, stacks, full support for DataMapper, Sequel and other ORMS, jQuery or other JS library, opt-in solution using just rails-core, better core isolation, built-in RSpec and webrat support, slices, merb-cache, merb-auth and all the other key plugins that will be ported over.</p>
<p>To be able to achieve all of that, we will have to make some infrastructure and code modifications.</p>
<p>Rails internals should end up:</p>
<ul>
<li>way less magical (even Merb uses some magic, but we&rsquo;ll make sure to keep it to a minimum)</li>
<li>returning shorter and cleaner stack traces</li>
<li>cleaner (required for the new API)</li>
<li>better isolated (required to increase the modularity)</li>
<li>alias_method_chain won&rsquo;t be available at the public API level (we probably still will need some chaining mechanism internally, but that&rsquo;s a different story)</li>
</ul>
<p>So, no, you don&rsquo;t have to go &ldquo;back&rdquo; to Rails. In fact, imagine you could do exactly what Rails does but with the performance and modular architecture of Merb. That&rsquo;s what you will get with Rails 3.0.</p>
<h2 id="rails-30-wont-even-be-as-good-as-merb-1x">Rails 3.0 won&rsquo;t even be as good as Merb 1.x</h2>
<p>I think I mainly replied to this question in my previous answer.
There is no reason why Rails 3.0 won&rsquo;t be better than Merb 1.x.Â  Actually, I believe our API will actually be even better. With the help of David, the existing Rails core team, and the Rails community, we will be able to define an awesome API that will change the way ruby web development will be done.
The merb API is great but we already know some of its limitations and we don&rsquo;t have as many plugin developers to work with. Working with plugin developers is something I&rsquo;m personally excited about. As a Rails developer I have been really frustrated when using 3rd party plugins and trying to develop my own.
Having a well tested, developed against, public API will make all the Rails 3.0 plugins so much better. And because Merb plugins already use an API, we will be able to port all the plugins over, so it will be at least as good as 1.x
Also, we are going to work on real app benchmark tests to make sure the performance gain is at least as good as what we have with Merb.</p>
<p>Migration will be easy and well documented. We are not giving up on the Merb book and it will be very useful to explain the Merb way to new comers wanting an idea of the new stuff in Rails 3.0. It will also be the best source of information to migrate your app to Rails 3.0.</p>
<p>Talking about migration, we promised to give you a sane migration path when it will be time to migrate.
Again, don&rsquo;t freak out because we are changing the name, the spirit of Merb will keep on living.</p>
<h2 id="the-rails-team-wont-let-you-do-what-you-have-to-do-to-merge-merb-into-rails">The Rails team won&rsquo;t let you do what you have to do to merge Merb into Rails</h2>
<p>In all honestly, I was worried about that. I was wondering if all of that was not an evil scam planned by DHH to kill Merb as it was getting a good momentum. I like conspiracy theories and it sounded pretty good.
To my surprised, after a few private conversations with David, I realized that he was genuinely interested in making Rails better for people and fulfill the needs of people who need more flexibility.
Just re-read his blog post <a href="https://weblog.rubyonrails.org/2008/12/23/merb-gets-merged-into-rails-3">https://weblog.rubyonrails.org/2008/12/23/merb-gets-merged-into-rails-3</a>. After what he said, how can he back up and just keep Rails the way it is? And why in the world would he want that to happen?
It&rsquo;s a team effort and we have already spent hours and hours discussing some details. I can promise you that the Rails team is very excited about the new stuff that&rsquo;s coming up. But don&rsquo;t forget that it&rsquo;s a merge and we are reconsidering some of the stuff we did in Merb to better re-implement them in Rails 3.0.
So far, I haven&rsquo;t seen any of the Rails core team member tell us, no you can&rsquo;t do that because that&rsquo;s not the way it&rsquo;s done in Rails or because we just don&rsquo;t like it.</p>
<h2 id="dhh-is-a-jerk">DHH is a jerk</h2>
<p>Recently, in an interview I gave to rubylearning.com <a href="https://rubylearning.com/blog/2008/12/18/matt-aimonetti-why-on-earth-would-you-ignore-merb/">https://rubylearning.com/blog/2008/12/18/matt-aimonetti-why-on-earth-would-you-ignore-merb/</a> I mentioned that a big difference between Merb and Rails was the way we were dealing with the user base.
I quoted David from an Interview he gave to InfoQ <a href="https://www.infoq.com/interviews/David-Hansson">https://www.infoq.com/interviews/David-Hansson</a> back in 2006.</p>
<p>As part of the merging evaluation process we literally spent hours talking back and forth. I had a seriously hard time believing that Rails and David honestly wanted to change their world views. How can you go from saying what you said in 2006 to adopting what Merb is pushing for: letting the framework bend to make what each developer wants if he doesn&rsquo;t want to follow the &ldquo;golden path&rdquo;?</p>
<p>Interestingly enough, David recently addressed this point on his blog. <a href="https://www.loudthinking.com/posts/36-work-on-what-you-use-and-share-the-rest">https://www.loudthinking.com/posts/36-work-on-what-you-use-and-share-the-rest</a></p>
<p>&ldquo;I wanted to take a few minutes to address some concerns of the last 4%. The people who feel like this might not be such a good idea. And in particular, the people who feel like it might not be such a good idea because of various things that I&rsquo;ve said or done over the years.&rdquo;</p>
<p>First thing first, David addresses the minority of people worried about his image and what it means for them.
So, David actually cares about hard core merbists and he wants them to join the fun. I personally see this as something very encouraging!</p>
<p>A recurring theme we hear a lot is that Rails becomes whatever DHH/37signals needs/wants. If DHH needs something new, it will make it to Rails, if he doesn&rsquo;t need it, it won&rsquo;t.</p>
<p>David has a very simple and almost shocking response: DHH != Rails</p>
<p>David is really happy with Rails. Rails satisfies his needs but he knows that some people out there need/want something more/different.</p>
<p>&ldquo;I personally use all of those default choices, so do many other Rails programmers. The vanilla ride is a great one and it&rsquo;ll remain a great one. But that doesn&rsquo;t mean it has to be the only one. There are lots of reasons why someone might want to use Data Mapper or Sequel instead of Active Record. I won&rsquo;t think of them any less because they do. In fact, I believe Rails should have open arms to such alternatives.&rdquo;</p>
<p>So, you can still think whatever you want about David. What&rsquo;s important is that Rails is more than David. It&rsquo;s an entire team of people with different needs and different views.</p>
<p>DHH isn&rsquo;t a dictator and based on concrete examples such as the &ldquo;respond_to vs provides&rdquo; discussion, I can reassure you that David has been very receptive to arguments and never tried to force any decision because he thought it was better.</p>
]]></content>
		</item>
		
		<item>
			<title>rails and merb core team working together</title>
			<link>https://matt.aimonetti.net/posts/2008-12-rails-and-merb-core-team-working-together/</link>
			<pubDate>Wed, 24 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-rails-and-merb-core-team-working-together/</guid>
			<description>This is huge! While people still try to find some drama an in hypothetical war between rails and merb.
The Rails team and the Merb team announced working together on a joined version of the 2 frameworks. This is so exciting, nobody believed it could ever happen (I personally, had my serious doubt).
Yehuda had a great post laying down the plan and explaining things in details. Check out David’s post explaining why he wants us to work together and his vision of a better Ruby world.</description>
			<content type="html"><![CDATA[<h3 id="this-is-huge">This is huge!</h3>
<p><img src="https://merbist.com/wp-content/uploads/2008/12/surprise-296x300.jpg" alt=""></p>
<p>While people still try to find some drama an in hypothetical war between rails and merb.</p>
<p>The Rails team and the Merb team announced working together on a joined version of the 2 frameworks. This is so exciting, nobody believed it could ever happen (I personally, had my serious doubt).</p>
<p>Yehuda had a great post laying down the plan and explaining things in details. Check out David’s post explaining why he wants us to work together and his vision of a better Ruby world.</p>
<p>I have to say that I have been impressed by the Rails core team and especially David (DHH).</p>
<p>I’ve known David for few years now and we had long/heated discussions on topics like i18n/l10n for Rails. David is known to be a very opinionated person. But if you come up with the right arguments, he can be convinced and when that happens, he is willing to move forward and shake things up.</p>
<p>This merge is a concrete example that David and the rest of the Rails team cares about Rails and the Ruby community more than we usually give them credit for. As a unified team, we are going to change the way web development in Ruby is done!</p>
<p>But what does it mean for you?</p>
<p>I put together a FAQ video here is the transcript:</p>
<p>Hi, I’m Matt Aimonetti from the merb core team and as you might have heard, a big announcement was made earlier today.</p>
<p>I did this video to hopefully answer the questions you might have.</p>
<h3 id="q-so-whats-the-big-news">Q: So what’s the big news?</h3>
<ul>
<li>
<p>merb and rails team will work together on the next version of their frameworks</p>
</li>
<li>
<p>merb 2.0 and rails 3.0 share the same common endpoint</p>
</li>
<li>
<p>we realized we now have the same objectives and agreed on all the key principles.</p>
</li>
<li>
<p>merb will provide Rails with agnosticism, modularity, improved performance and a public API.</p>
</li>
<li>
<p>The end product will be called Rails 3.0 but what real matters is that it’s a huge gain for the entire community.</p>
</li>
</ul>
<h3 id="q-what-i-thought-there-was-a-war-going-on-between-rails-and-merb-what-happened">Q: What??? I thought there was a war going on between Rails and merb, what happened?</h3>
<ul>
<li>
<p>There was no war between rails and merb</p>
</li>
<li>
<p>We created merb because rails was not fitting us</p>
</li>
<li>
<p>We wanted better performance, more choices/ more modularity and a Public API.</p>
</li>
<li>
<p>The Rails team now embraces these concepts and want Rails to follow them, so why not work together?</p>
</li>
</ul>
<h3 id="q-wait-does-that-mean-that-merb-is-dead">Q: Wait, does that mean that merb is dead?</h3>
<ul>
<li>
<p>Absolutely not!</p>
</li>
<li>
<p>merb development won’t stop, we are going to keep on releasing updates until rails 3.0</p>
</li>
<li>
<p>clear migration path, and upgrading to rails 3.0 will be as trivial as upgrading from rails 2.x to Rails 3.0</p>
</li>
</ul>
<h3 id="q-what-does-the-timeline-look-like">Q: What does the timeline look like?</h3>
<p>We just started getting together and discuss the technical details. We are shooting for a release at RailsConf 2009. However it’s hard to estimate this kind of things so again, that’s just an estimate <img src="https://merbist.com/wp-includes/images/smilies/icon_smile.gif" alt=":)"></p>
<h3 id="q-i-just-started-a-merb-project-so-what-now">Q: I just started a merb project, so what now?</h3>
<p>I’m sure you had valid reasons to use merb, you needed modularity, performance and a solid API.</p>
<p>Keep on using Merb, we won’t let you down. The good news is that the next version of merb (rails 3.0) will be even awesomer!</p>
<h3 id="q-what-about-my-client-who-was-looking-at-using-merb-for-his-new-project">Q: What about my client who was looking at using merb for his new project?</h3>
<p>If your client is going to be using merb for valid reasons (and not, just because it’s not rails) he should still use merb, but with the full understanding that he/she will end up using Rails in 6 months or so. Again, Rails 3.0 will have what pushed you to use merb.</p>
<h3 id="q-ive-been-involved-with-the-merb-book-what-will-happen-with-this-project">Q: I’ve been involved with the merb-book, what will happen with this project?</h3>
<ul>
<li>
<p>rails 3.0 won’t get released right away</p>
</li>
<li>
<p>still need awesome documentation</p>
</li>
<li>
<p>if we look at rails 3.0 as merb 2.0, we can easily imagine how the current work can be extended to the new version.</p>
</li>
<li>
<p>rails team will also include an evangelism team which I will be part of, so will be able to focus more on projects like the book.</p>
</li>
</ul>
<h3 id="q-ive-been-working-on-a-merb-plugin-what-should-i-do">Q: I’ve been working on a merb plugin, what should I do?</h3>
<p>Keep working on it! We’ll assist you with the migration process and the new solid API.</p>
<h3 id="q-what-if-i-still-have-questions">Q: What if I still have questions?</h3>
<p>Come talk with me, or any members from the new team. We’ll be open to hear your questions, worries, frustrations.</p>
<p>merb always valued its developers and we will continue to do so but at a bigger scale.</p>
<hr>
<p>Concretely, nothing changes for Merb users. People loving Merb should not worry. The way you build merb apps won’t change until merb2.0/rails3.0. We will still work on your favorite framework and improve it.</p>
<p>Lori Holden worked on merb_sequel and we should release a 1.0 release of the plugin in a few days.</p>
<p>I’m sure this news comes as a shock for many of you, but try to not see Rails 3.0 as the way Rails is right now. Imagine a version of Rails with true modularity and agnosticism (sequel, DM and AR will still be supported) and the same type of performance as what you get with Merb. In other words, the rails world is about to discover the power of merb!</p>
<p>Here is what Yehuda explicitly says in his blog post:</p>
<ul>
<li>
<p>Rails will become more modular, starting with a rails-core, and including the ability to opt in or out of specific components. [&hellip;]</p>
</li>
<li>
<p>We will port all of our performance improvements into Rails. This includes architectural decisions that are big performance wins.[..]</p>
</li>
<li>
<p>As of Rails 3, Rails will have a defined public API with a test suite for that API. [..]</p>
</li>
<li>
<p>Rails will still ship with the “stack” version as the default (just as Merb does since 1.0), but the goal is to make it easy to do with Rails what people do with Merb today.</p>
</li>
<li>
<p>Rails will be modified to more easily support DataMapper or Sequel as first-class ORMs. [..]</p>
</li>
<li>
<p>Rails will continue their recent embrace of Rack, which [..] will improve the state of modular, sharable logic between applications.</p>
</li>
<li>
<p>In general, we will take a look at features in Merb that are not in Rails (the most obvious example is the more robust router) and find a way to bring them into Rails.</p>
</li>
</ul>
<h2 id="personal-perspective">Personal perspective</h2>
<p>I’m personally really excited about this opportunity. I had a hard time believing that we could work together but I was proved wrong. We have many challenges in front of us, but watching the two teams working together is very reassuring.</p>
<p>I’m also glad to see that we will have a Rails Evangelism team that I will be part of. I strongly believe that one of the many reasons why merb has been so successful is because we work and listen to our community. We have put a tremendous amount of energy trying to understand what you guys need and what you like and dislike. In return, we saw many people working hard on the wiki and the merb-book.</p>
<p>Can you imagine doing that with almost 4 Million Rails developers?</p>
<p>I’m also looking forward to working with a team and reaching to even more people.</p>
<h2 id="other-news-related-to-the-merge">Other news related to the merge:</h2>
<ul>
<li>
<p>The RubyOnRails website will keep a trace of this historical moment: <a href="https://rubyonrails.org/merb">https://rubyonrails.org/merb</a></p>
</li>
<li>
<p>The <a href="https://merbclass.com/">merb training scheduled for Jan 19-21</a> in partnership with <a href="https://integrumtech.com/">Integrum</a> will still take place, and if you want to get a head start and learn about the things that will make Rails 3.0 totally kick ass, I’d suggest you join us.</p>
</li>
</ul>
<p>If you have any questions, or if you want me to publicly answer questions on your blog please contact me. I’ll do my best to get back to everyone.</p>
]]></content>
		</item>
		
		<item>
			<title>rails and merb merge</title>
			<link>https://matt.aimonetti.net/posts/2008-12-rails-and-merb-merge/</link>
			<pubDate>Tue, 23 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-rails-and-merb-merge/</guid>
			<description>This is huge! While people still try to find some drama in a hypothetical war between Rails and merb &amp;hellip;
The Rails team and the Merb team announced today that they will work together on a joined version of the 2 frameworks. This is so exciting! Nobody believed it could ever happen (I personally, seriously had my doubt).
Yehuda had a great post laying out the plan and explaining things in details.</description>
			<content type="html"><![CDATA[<h3 id="this-is-huge">This is huge!</h3>
<p>While people still try to find some drama in a hypothetical war between Rails and merb &hellip;</p>
<p><img src="https://merbist.com/wp-content/uploads/2008/12/surprise1-296x300.jpg" alt="">The Rails team and the Merb team announced today that they will work together on a joined version of the 2 frameworks. This is so exciting! Nobody believed it could ever happen (I personally, seriously had my doubt).</p>
<p>Yehuda had a <a href="https://yehudakatz.com/2008/12/23/rails-and-merb-merge/">great post</a> laying out the plan and explaining things in details. Check out <a href="https://weblog.rubyonrails.org/2008/12/23/merb-gets-merged-into-rails-3">David&rsquo;s post </a>explaining why he wants us to work together and his vision of a better Ruby world.</p>
<p>I have to say that I have been impressed by the Rails core team and especially David (DHH).</p>
<p>I&rsquo;ve known David for few years now and we had long (sometimes heated) discussions on topics like i18n/l10n for Rails. David is known to be a very opinionated person. But if you come up with the right arguments, he can be convinced and when that happens, he is willing to move forward and shake things up.</p>
<p>This merge is a concrete example that David and the rest of the Rails team care about Rails and the Ruby community more than we usually give them credit for. As a unified team, we are going to change the way web development in Ruby is done!</p>
<p>But what does it mean for you?</p>
<p>I put together a FAQ video which, I hope will answer your questions.</p>
<p><a href="https://vimeo.com/2607919">Matt Aimonetti: message to all merbists</a></p>
<p>Transcript:</p>
<p>Hi, I&rsquo;m Matt Aimonetti from the merb core team and as you might have heard, a big announcement was made earlier today.
I did this video to hopefully answer the questions you might have.</p>
<h3 id="q-so-whats-the-big-news">Q: So what&rsquo;s the big news?</h3>
<ul>
<li>
<p>merb and Rails team will work together on the next version of their frameworks</p>
</li>
<li>
<p>merb 2.0 and Rails 3.0 share the same common endpoint</p>
</li>
<li>
<p>we realized we now have the same objectives and agreed on all the key principles.</p>
</li>
<li>
<p>merb will provide Rails with agnosticism, modularity, improved performance and a public API.</p>
</li>
<li>
<p>The end product will be called Rails 3.0 but what real matters is that it&rsquo;s a huge gain for the entire community.</p>
</li>
</ul>
<h3 id="q-what-i-thought-there-was-a-war-going-on-between-rails-and-merb-what-happened">Q: What??? I thought there was a war going on between Rails and merb, what happened?</h3>
<ul>
<li>
<p>There was no war between Rails and merb</p>
</li>
<li>
<p>We created merb because Rails was not fitting us</p>
</li>
<li>
<p>We wanted better performance, more choices/ more modularity and a Public API.</p>
</li>
<li>
<p>The Rails team now embraces these concepts and want Rails to follow them, so why not work together?</p>
</li>
</ul>
<h3 id="q-wait-does-that-mean-that-merb-is-dead">Q: Wait, does that mean that merb is dead?</h3>
<ul>
<li>
<p>Absolutely not!</p>
</li>
<li>
<p>merb development won&rsquo;t stop, we are going to keep on releasing updates until Rails 3.0</p>
</li>
<li>
<p>clear migration path, and upgrading to Rails 3.0 will be as trivial as upgrading from Rails 2.x to Rails 3.0</p>
</li>
</ul>
<h3 id="q-what-does-the-timeline-look-like">Q: What does the timeline look like?</h3>
<p>We just started getting together to discuss the technical details. We are shooting for a release at RailsConf 2009. However it&rsquo;s hard to estimate this kind of thing so, again, that&rsquo;s just an estimate :)</p>
<h3 id="q-i-just-started-a-merb-project-so-what-now">Q: I just started a merb project, so what now?</h3>
<p>I&rsquo;m sure you had valid reasons to use merb, you needed modularity, performance and a solid API.
Keep on using Merb, we won&rsquo;t let you down. The good news is that the next version of merb (Rails 3.0) will be even awesomer!</p>
<h3 id="q-what-about-my-client-who-was-looking-at-using-merb-for-his-new-project">Q: What about my client who was looking at using merb for his new project?</h3>
<p>If your client is going to be using merb for valid reasons (and not just because it&rsquo;s not Rails) they should still use merb, but with the full understanding that they will end up using Rails in 6 months or so. Again, Rails 3.0 will have what pushed you to use merb.</p>
<h3 id="q-ive-been-involved-with-the-merb-book-what-will-happen-with-this-project">Q: I&rsquo;ve been involved with the merb-book, what will happen with this project?</h3>
<ul>
<li>
<p>Rails 3.0 won&rsquo;t get released right away</p>
</li>
<li>
<p>still need awesome documentation</p>
</li>
<li>
<p>if we look at Rails 3.0 as merb 2.0, we can easily imagine how the current work can be extended to the new version</p>
</li>
<li>
<p>Rails team will also include an evangelism team which I will be part of, so will be able to focus more on projects like the book</p>
</li>
</ul>
<h3 id="q-ive-been-working-on-a-merb-plugin-what-should-i-do">Q: I&rsquo;ve been working on a merb plugin, what should I do?</h3>
<p>Keep working on it! We&rsquo;ll assist you with the migration process and the new solid API.</p>
<h3 id="q-what-if-i-still-have-questions">Q: What if I still have questions?</h3>
<p>Come talk with me, or any member of the new team. We&rsquo;ll be open to hear your questions, worries, frustrations.
merb always valued its developers and we will continue to do so but on a bigger scale.</p>
<hr>
<p>Concretely, nothing changes for merb users. People loving merb should not worry. The way you build merb apps won&rsquo;t change until merb2.0/Rails3.0. We will still work on your favorite framework and improve it.</p>
<p>Lori Holden worked on merb_sequel and we should release a 1.0 release of the plugin in a few days.</p>
<p>I&rsquo;m sure this news comes as a shock for many of you, but try to not see Rails 3.0 as the way Rails is right now. Imagine a version of Rails with true modularity and agnosticism (sequel, DM and AR will still be supported) and the same type of performance as what you get with merb. In other words, the Rails world is about to discover the power of merb!</p>
<p>Here is what Yehuda explicitly says in his blog post:</p>
<ul>
<li>
<p>Rails will become more modular, starting with a rails-core, and including the ability to opt in or out of specific components. [&hellip;]</p>
</li>
<li>
<p>We will port all of our performance improvements into Rails. This includes architectural decisions that are big performance wins.[..]</p>
</li>
<li>
<p>As of Rails 3, Rails will have a defined public API with a test suite for that API. [..]</p>
</li>
<li>
<p>Rails will still ship with the &ldquo;stack&rdquo; version as the default (just as merb does since 1.0), but the goal is to make it easy to do with Rails what people do with merb today.</p>
</li>
<li>
<p>Rails will be modified to more easily support DataMapper or Sequel as first-class ORMs. [..]</p>
</li>
<li>
<p>Rails will continue their recent embrace of Rack, which [..] will improve the state of modular, sharable logic between applications.</p>
</li>
<li>
<p>In general, we will take a look at features in merb that are not in Rails (the most obvious example is the more robust router) and find a way to bring them into Rails.</p>
</li>
</ul>
<h2 id="personal-perspective">Personal perspective</h2>
<p>I&rsquo;m personally really excited about this opportunity. I had a hard time believing that we could work together but I was proved wrong. We have many challenges in front of us, but watching the two teams working together is very reassuring.</p>
<p>I&rsquo;m also glad to see that we will have a Rails Evangelism team that I will be part of. I strongly believe that one of the many reasons why merb has been so successful is because we work and listen to our community. We have put a tremendous amount of energy into trying to understand what you guys need and what you like and dislike. In return, we have seen many people working hard on the wiki and the merb-book.</p>
<p>Can you imagine doing that with almost 4 Million Rails developers?</p>
<p>I&rsquo;m also looking forward to working with a team and reaching to even more people.</p>
<h2 id="other-news-related-to-the-merge">Other news related to the merge:</h2>
<ul>
<li>
<p>The RubyOnRails website will keep a trace of this historical moment: <a href="https://rubyonrails.org/merb">https://rubyonrails.org/merb</a></p>
</li>
<li>
<p>The <a href="https://merbclass.com/">merb training scheduled for Jan 19-21</a>, in partnership with <a href="https://integrumtech.com/">Integrum</a>, will still take place, and if you want to get a head start and learn about the things that will make Rails 3.0 totally kick ass, I&rsquo;d suggest you join us.</p>
</li>
</ul>
<p>If you have any questions, or if you want me to publicly answer questions on your blog please contact me. I&rsquo;ll do my best to get back to everyone.</p>
]]></content>
		</item>
		
		<item>
			<title>meet the merbists jason seifer</title>
			<link>https://matt.aimonetti.net/posts/2008-12-meet-the-merbists-jason-seifer/</link>
			<pubDate>Sat, 20 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-meet-the-merbists-jason-seifer/</guid>
			<description>Today I&amp;rsquo;m interviewing Jason Seifer known for the funny envyads and the weekly RailsEnvy podcast.
Matt Aimonetti: Hi Jason, could you please introduce yourself and tell us what you do for a living?
Jason Seifer: My name is Jason Seifer and I do mostly web development for a living along with podcasting and screencasting.
Matt Aimonetti: How did you get started with Ruby, what&amp;rsquo;s your background?
Jason Seifer: As far as my background goes, I have a degree in Psychology from the University of Central Florida.</description>
			<content type="html"><![CDATA[<p><img src="https://merbist.com/wp-content/uploads/2008/12/jason-seifer-300x225.jpg" alt="Jason Seifer"></p>
<p>Today I&rsquo;m interviewing <a href="https://jasonseifer.com/">Jason Seifer</a> known for the funny <a href="https://www.youtube.com/user/envyads">envyads</a> and the weekly <a href="https://railsenvy.com/">RailsEnvy podcast</a>.</p>
<p><strong>Matt Aimonetti:</strong> Hi Jason, could you please introduce yourself and tell us what you do for a living?</p>
<p><strong>Jason Seifer:</strong> My name is Jason Seifer and I do mostly web development for a living along with podcasting and screencasting.</p>
<p><strong>Matt Aimonetti:</strong> How did you get started with Ruby, what&rsquo;s your background?</p>
<p><strong>Jason Seifer:</strong> As far as my background goes, I have a degree in Psychology from the University of Central Florida. I got started with Ruby by way of learning Rails. I used to do some hacking on perl and php but never anything for full time work until Rails came along. I fell in love with the Ruby language that way.</p>
<p><strong>Matt Aimonetti:</strong> You chose to learn and use Merb, could you please let us know why and how that happened?</p>
<p><strong>Jason Seifer:</strong> Doing the Rails Envy podcast, I&rsquo;ve been keeping up with the latest merb news for a while now. Along the way I&rsquo;ve been extremely impressed by how the merb team handles things, listens to its users, and implements new features. At the same time, I&rsquo;m pretty lazy when it comes to coding so I wanted to wait until the API was stable and version 1.0ish before jumping in to building merb apps. I have a lot of Rails experience so picking it up wasn&rsquo;t too hard.</p>
<p><strong>Matt Aimonetti:</strong> Do you have some Merb projects available online we can look at? what was your experience so far?</p>
<p><strong>Jason Seifer:</strong> I don&rsquo;t have anything online at the moment but I am working on a couple of things that I hope to release in the coming months. Working with merb is a pleasure most of the time, though it&rsquo;s pretty easy to get confused with some common rails functions that differ slightly by name (before/before_filter, etc) if you&rsquo;ve been doing Rails for a while. One thing that&rsquo;s really nice about working with merb is how compact and easy to understand the framework code is. It&rsquo;s very easy to jump in and see how something works if you&rsquo;re having trouble.</p>
<p><strong>Matt Aimonetti:</strong> What is your favorite aspect of the Merb framework?</p>
<p><strong>Jason Seifer:</strong> As far as features go, I love run_later. It&rsquo;s pretty nice not to have to run a message queue for decoupling simple things like sending email from the request/response cycle. There are a number of smaller features like that which make merb nice to work with.</p>
<p>My favorite aspect of merb, though, is the stable api. It&rsquo;s very comforting to know that by upgrading to the next stable point release of the framework that I&rsquo;m not going to have things that break. This of course doesn&rsquo;t mean that a stable and comprehensive test suite isn&rsquo;t important but it is one less worry.</p>
<p><strong>Matt Aimonetti:</strong> Could you please mention an aspect of Merb you hope to see being improved in the near future?</p>
<p><strong>Jason Seifer:</strong> If you had asked me this question a few weeks ago I would have said documentation, but that itch is being scratched by the merb book. Though not exactly merb, I&rsquo;d really love to see DataMapper get JRuby compatibility so we can get the full stack on JRuby for deployment. That would be very exciting what with everything going on in JRuby land at the moment.</p>
<p><strong>Matt Aimonetti:</strong> Thank you for your time. Anything else you would like to add?</p>
<p><strong>Jason Seifer:</strong>
I would encourage people to try merb if they&rsquo;ve been holding out at all. It&rsquo;s a great time to get involved and the community is great, too. Also, I&rsquo;ll be starting a merb podcast soon so stay tuned for that. Thanks very much for talking with me.</p>
]]></content>
		</item>
		
		<item>
			<title>meet the merbists andy delcambre</title>
			<link>https://matt.aimonetti.net/posts/2008-12-meet-the-merbists-andy-delcambre/</link>
			<pubDate>Thu, 18 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-meet-the-merbists-andy-delcambre/</guid>
			<description>Today, Andy Delcambre is our featured merbist.
Matt Aimonetti: Could you please introduce yourself and tell us what you do for a living.
Andy Delcambre: My name is Andy Delcambre and I work for Engine Yard (https://engineyard.com) as a Software Engineer. I work primarily on internal and customer facing projects. These projects are almost exclusively written in Merb. At Engine Yard we take advantage of many of the modular aspects of Merb.</description>
			<content type="html"><![CDATA[<p><a href="https://andy.delcambre.com"><img src="https://merbist.com/wp-content/uploads/2008/12/andy_cafe-224x300.jpg" alt="Andy Delcambre"></a></p>
<p>Today, <a href="https://andy.delcambre.com">Andy Delcambre</a> is our featured merbist.</p>
<p><strong>Matt Aimonetti:</strong> Could you please introduce yourself and tell us what you do for a living.</p>
<p><strong>Andy Delcambre:</strong> My name is Andy Delcambre and I work for Engine Yard
(<a href="https://engineyard.com">https://engineyard.com</a>) as a Software Engineer.  I work primarily on
internal and customer facing projects.  These projects are almost
exclusively written in Merb.  At Engine Yard we take advantage of many
of the modular aspects of Merb.  For example, we use Salesforce for
customer tracking and have a Merb slice which includes the DataMapper
adapters for Salesforce.  This gives us the ability to interact with
salesforce from any application for free.</p>
<p><strong>Matt Aimonetti:</strong> How did you get started with Ruby, and what&rsquo;s your general programming background?</p>
<p><strong>Andy Delcambre:</strong> I majored in Computer Science at college and had been hearing about
Ruby and Ruby on Rails for a while before I finally dove in.  I worked
for the College of Engineering as a Linux Administrator and took the
opportunity to build my first rails application: a tool for managing
our automated deployments.  This was a huge learning experience, I had
done web development in raw php before, but this was my first time
using a framework.  It was both a bit overwhelming and a breath of
fresh air.  When I graduated from University, I decided to pursue Ruby
and Rails as a career path and have yet to look back.</p>
<p><strong>Matt Aimonetti:</strong> You chose to contribute to Merb;  how and why did that happened?</p>
<p><strong>Andy Delcambre:</strong> I was working at Planet Argon (<a href="https://planetargon.com">https://planetargon.com</a>), a small Ruby
on Rails development company and was looking to do some open source
contributions.  I had been hearing quite a lot about Merb in the rails
community, especially that it was smaller, lighter and faster.  I
decided to look in the bug tracker and see if there was something
small I could tackle and found a bug with the way nil and false
default arguments were handled in merb_action_args.  When my patch was
accepted I was fairly hooked.  I have been submitting small patches
ever since.  I also led the inline documentation team at the Merb
sprint in San Diego during the run up to 1.0</p>
<p><strong>Matt Aimonetti:</strong> Do you have any Merb projects available online we can look at? What&rsquo;s your experience been so far?</p>
<p><strong>Andy Delcambre:</strong> All of my merb projects are projects at Engine Yard right now.  I
wrote a simple Merb app to manage the content on the Engine Yard
homepage and the blog is based on the Feather blogging engine, written
in Merb.  My current projects are not yet publicly available but
should be very cool when they come out.</p>
<p><strong>Matt Aimonetti:</strong> What is your favorite aspect of the Merb framework?</p>
<p><strong>Andy Delcambre:</strong> I have two answers, first as a someone who works on merb, then as
someone who works with merb.</p>
<p>Ever since that first patch to action_args, I have loved the ease with
which I can jump in and dig under the hood.  I have dug down into the
router, the dispatcher, the form helpers, and the mailer, all without
much problem understanding the code.</p>
<p>Second, as a developer of merb applications I think the direction merb
is going with the heavy emphasis on modularity is fantastic.  In the
app I am currently working on, we are using four different slices
right now.  One of which is an entirely different merb app modified
slightly and mounted within the application.  One is a custom
merb-auth strategy that we use internally that makes it much much
easier to maintain consistency for our internal applications.  These
would be much much harder to integrate for most other frameworks.  It
is so useful to be able to just plug in these small, specific pieces
of functionality.</p>
<p><strong>Matt Aimonetti:</strong> What parts of Merb you hope to see improved in the near future?</p>
<p><strong>Andy Delcambre:</strong> I am looking forward to the future improvements to the modularity of
merb.  I am really ready for the day that you can mount entire merb
apps inside one another.  Then, once everything uses merb-auth, I can
imagine mounting a blog and a cms inside the same &ldquo;app&rdquo; and have the
users shared across, automatically.  How awesome would that be.</p>
<p><strong>Matt Aimonetti:</strong> Anything else you would like to add?</p>
<p><strong>Andy Delcambre:</strong> I am looking forward to being part of the merb community as this
project just keeps getting better and kicking more butt.  Thanks a lot
for including me in this series.</p>
]]></content>
		</item>
		
		<item>
			<title>meet the merbists lori holden</title>
			<link>https://matt.aimonetti.net/posts/2008-12-meet-the-merbists-lori-holden/</link>
			<pubDate>Wed, 17 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-meet-the-merbists-lori-holden/</guid>
			<description>](https://loriholden.com/)
Today, I&amp;rsquo;m interviewing Lori Holden from YellowPages.com/AT&amp;amp;T Interactive.
I met Lori on IRC a bit before MerbCamp 2008 where she gave a very interesting talk on Sequel.
Matt Aimonetti Hi Lori, could you please introduce yourself and the company you work for?
Lori Holden: Hi Matt, my name is Lori Holden. I originally became interested in software development when I was 10. Since then, I have been a professional developer for over 10 years now and currently work as a Senior Software Engineer for AT&amp;amp;T Interactive.</description>
			<content type="html"><![CDATA[<p><img src="https://merbist.com/wp-content/uploads/2008/12/lori_at_desk-201x300.png" alt="Lori Holden">](<a href="https://loriholden.com/">https://loriholden.com/</a>)</p>
<p>Today, I&rsquo;m interviewing <a href="https://loriholden.com/">Lori Holden</a> from <a href="https://www.yellowpages.com/">YellowPages.com</a>/<a href="https://www.research.att.com/projects.cfm">AT&amp;T Interactive</a>.</p>
<p>I met Lori on IRC a bit before <a href="https://merbcamp.com/">MerbCamp 2008</a> where she gave a very interesting talk on <a href="https://sequel.rubyforge.org/">Sequel</a>.</p>
<p><strong>Matt Aimonetti</strong> Hi Lori, could you please introduce yourself and the company you work for?</p>
<p><strong>Lori Holden:</strong> Hi Matt, my name is Lori Holden.  I originally became interested in software development when I was 10.  Since then, I have been a professional developer for over 10 years now and currently work as a Senior Software Engineer for AT&amp;T Interactive.</p>
<p><strong>Matt Aimonetti</strong> How did you get started with Ruby, what&rsquo;s your background?</p>
<p><strong>Lori Holden:</strong> Years ago I had been hearing talk about an &lsquo;upcoming&rsquo; new language called Ruby.  At the time it didn&rsquo;t have many people in the US working with it, but I really loved how similar to Smalltalk it was.</p>
<p>My core background experience is centered around Ruby, Java, C++, PHP, and Javascript.  Outside of that, I consider myself a language geek&hellip; and have quite a bit of experience in Python, Smalltalk, OCaml, IO Language, and Perl, along with several others.</p>
<p><strong>Matt Aimonetti</strong> You chose to learn, support and use Merb, could you please let us know why and how that happened?</p>
<p><strong>Lori Holden:</strong> I was one of the original Rails developers.  Since then, I have used Rails off and on&hellip; but have found myself growing more and more unsatisfied with it.  On top of that, I have also found myself growing out of touch with the core developers over the last couple years, which I am sure doesn&rsquo;t help things.
Merb is fresh.  I find it carries a lot less baggage with it than Rails.  Even better, the project is still small and I seem to get along quite well with the the other developers on the project.</p>
<p><strong>Matt Aimonetti</strong> You have been contributing to the Merb project and gave a Sequel presentation during MerbCamp 08, what is your motivation?</p>
<p><strong>Lori Holden:</strong> Primarily, I just like the developers.  Everyone seems to be really passionate about Merb and are willing to push it in some really cool directions.  At the same time, Merb still manages to remain slim and with very little bloat.
I really enjoy helping projects push through to release and I was glad to be a part of that for Merb.
Sequel is a really wonderful tool, and I was finding that just not that many people in the Merb community were using it.  I had a lot of experience with getting Merb and Sequel to work with each other, and figured I should share my experience with everyone else.</p>
<p><strong>Matt Aimonetti:</strong> What is your favorite aspect of the Merb framework?</p>
<p><strong>Lori Holden:</strong> This is a really odd one, but my favorite aspect of Merb is that I know it very well inside and out.  If I need to browse the source for some feature, I already know where to go and what to look at.  I attribute this to how slim the merb-core has remained.  I think it is quite easy to work with.</p>
<p><strong>Matt Aimonetti:</strong> Could you please mention an aspect of Merb you hope to see be improved in the near future?</p>
<p><strong>Lori Holden:</strong> Merb is still immature in some areas.  Gem management is one thing that I am finding to be a bit lacking.  The support for Sequel could use a bit more improvement&hellip; but I suppose that&rsquo;s something I should work on.  And finally, something that I hope Merb always works on: Keep it Small. Keep it Simple. Keep it Core. Bloat should be a plugin away, not an upgrade.</p>
<p><strong>Matt Aimonetti:</strong> Thank you for your time. Anything else you would like to add?</p>
<p><strong>Lori Holden:</strong> Thank you Matt. I hope you and your wife have a great winter solstice.</p>
]]></content>
		</item>
		
		<item>
			<title>meet the merbists derek neighbors</title>
			<link>https://matt.aimonetti.net/posts/2008-12-meet-the-merbists-derek-neighbors/</link>
			<pubDate>Mon, 15 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-meet-the-merbists-derek-neighbors/</guid>
			<description>Today, I&amp;rsquo;m starting a new series called meet the the merbists. My goal is to feature various people from our community and ask them a few questions about Ruby, Merb and their projects.
Let&amp;rsquo;s get started with Derek Neighbors from Integrum.
Matt Aimonetti: Hi Derek, could you please introduce yourself and the company you work for?
Derek Neighbors: I am Derek Neighbors and I work for Integrum Technologies, an agile software company based in Chandler, AZ focused on web solutions using Ruby.</description>
			<content type="html"><![CDATA[<p><a href="https://derekneighbors.com/"><img src="https://merbist.com/wp-content/uploads/2008/12/derek_pr2-300x199.jpg" alt="Derek Neighbors"></a></p>
<p>Today, I&rsquo;m starting a new series called <strong>meet the the merbists</strong>. My goal is to feature various people from our community and ask them a few questions about Ruby, Merb and their projects.</p>
<p>Let&rsquo;s get started with <a href="https://derekneighbors.com/">Derek Neighbors</a> from <a href="https://integrumtech.com/">Integrum</a>.</p>
<p><strong>Matt Aimonetti:</strong> Hi Derek, could you please introduce yourself and the company you work for?</p>
<p><strong>Derek Neighbors:</strong> I am Derek Neighbors and I work for Integrum Technologies, an agile software company based in Chandler, AZ focused on web solutions using Ruby.</p>
<p><strong>Matt Aimonetti:</strong> How did you get started with Ruby, what&rsquo;s your background?</p>
<p><strong>Derek Neighbors:</strong> We were doing custom software development using PHP and Python.  We mostly had Python backends with PHP front ends that would communicate via XML-RPC.  While this was working, it just didn&rsquo;t feel productive.  We had heard some inklings about this new framework called Ruby on Rails.  It was nearing 1.0 and so we decided to do an important but relatively simple e-commerce application in it.  We fell in love almost immediately and within 3 months started solely using Ruby for development.  The productivity gain just could not be ignored.</p>
<p><strong>Matt Aimonetti:</strong> You chose to learn, support and use Merb, could you please let us know why?</p>
<p><strong>Derek Neighbors:</strong> We deal with a lot of customers that also have opinions.  When we need to work to integrate into their systems, we need the flexibility to do things their way at times.  Having to dismantle a framework to do little things can be frustrating.  Having a framework with solid engineering practices behind it better allows our developers to help improve or deviate from the framework when necessary.  This is something we were struggling with in Ruby on Rails.</p>
<p><strong>Matt Aimonetti:</strong> Do you have a public project you wrote using Merb that people can look at?</p>
<p><strong>Derek Neighbors:</strong> We have an academic scheduling program we are starting to work on, but have not yet released.</p>
<p><strong>Matt Aimonetti:</strong> What is your favorite aspect of the Merb framework?</p>
<p><strong>Derek Neighbors:</strong> It reminds me of unix.  Lots of small pieces that do their job really well, that when combined make up something pretty spectacular.  If you don&rsquo;t need a piece you can leave it out.  If you like emacs (datamapper) instead of vi (active record) then use it.  In particular, the concept of Merb Slices is very appealing for code re-use.  Something we have struggled with in Ruby on Rails to date.  While plug-ins help with re-use there is nothing that would allow the flexibility that say merb-auth enjoys today as a slice.</p>
<p><strong>Matt Aimonetti:</strong> Could you please mention an aspect of Merb you hope to see be improved in the near future?</p>
<p>**Derek Neighbors: **Documentation is pretty high on the list, but also losing some of the &ldquo;you have to be a ruby hacker to use merb&rdquo; implications. While it is a hacker&rsquo;s framework, things like opinionated stacks and talks of Django-like admin interfaces make it sound pretty appealing to the non-hacker audience as well.  I am looking forward to Merb not being only for hackers, but still preferred by hackers.</p>
<p><strong>Matt Aimonetti:</strong> Thank you for your time. Anything else you would like to add?</p>
<p>**Derek Neighbors: **I just want to thank Merb-Core for their dedication and passion towards Merb.  I think believing in quality and having the determination to make frameworks take it to the next level is what improvement is all about.  I thank them for loving Ruby on Rails enough to push the development of both Merb and Ruby on Rails forward by not being okay with &ldquo;good enough&rdquo;.  People don&rsquo;t tell open source programmers enough how much they are appreciated.  So Merb-Core.. AGAIN, THANK YOU!</p>
]]></content>
		</item>
		
		<item>
			<title>become better at merb</title>
			<link>https://matt.aimonetti.net/posts/2008-12-become-better-at-merb/</link>
			<pubDate>Thu, 11 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-become-better-at-merb/</guid>
			<description>I hear a lot of people asking for better Merb documentation as they are learning Merb. I remember struggling with the very same problem when I started using Rails a few years ago.
The good news is that the core team is working hard on improving the state of documentation.
You have the Merb Book on which I am actively work on with a team of 20 people (writers, editors and translators).</description>
			<content type="html"><![CDATA[<p><a href="https://merbclass.com"><img src="https://merbclass.com/badges/badge_phx_training_200.gif" alt=""></a>I hear a lot of people asking for better Merb documentation as they are learning Merb. I remember struggling with the very same problem when I started using Rails a few years ago.</p>
<p>The good news is that the core team is working hard on improving the state of documentation.</p>
<p>You have the <a href="https://book.merbist.com">Merb Book</a> on which I am actively work on with a team of 20 people (writers, editors and translators).</p>
<p>You also have the <a href="https://docsbeta.merbivore.com/klasses/Merb::Parse">documentation browsing application</a> we are developing to let you browse documentation based on where you are in your app.</p>
<p>And of course, you have the 2 beta books (<a href="https://manning.com/ivey/">Merb in Action</a> and the <a href="https://safari.oreilly.com/9780321601636">Merb way</a>) plus two other ones in the process of being written (<a href="https://www.apress.com/book/view/9781430218234">Beginning Merb</a> and <a href="https://apress.com/book/view/9781430218654">Merb: What You Need to Know</a>).</p>
<p>Finally, you also have other resources like the <a href="https://peepcode.com/products/meet-merb-pdf-draft">Merb peepcode</a>.</p>
<p>The point being that we are actively working on improving the overall state of documentation. However, if you wish to learn more about the internals, how to some more advanced stuff like writing plugins, building your own stack, knowing when to use what component, I would suggest you attend the <a href="https://merbclass.com">training class</a> that <a href="https://yehudakatz.com">Yehuda Katz</a> (Merb lead developer) and myself are giving in <a href="https://merbclass.com">Phoenix, AZ, January 19-21</a>.</p>
<p>This would give you a rare opportunity to spend time with some of people directly involved with the day to day development of the framework as well as other like minded developers.</p>
<p>Website:Â Â Â Â Â Â  <a href="https://merbclass.com">https://merbclass.com</a>
Curriculum:Â    <a href="https://merbclass.com/curriculum.html">https://merbclass.com/curriculum.html</a>
Date:Â Â Â Â Â Â Â Â Â Â Â  Jan 19-21, 2009
Location:Â Â Â Â Â  Phoenix, AZ</p>
<p><a href="https://maps.google.com/maps?f=q&amp;hl=en&amp;geocode=&amp;q=+325+E+Elliot+Rd,+Suite+34+-+Chandler,+AZ+-+85225++&amp;sll=33.361073,-111.838074&amp;sspn=0.104807,0.22316&amp;ie=UTF8&amp;t=h&amp;g=325+E+Elliot+Rd,+Suite+34+-+Chandler,+AZ+-+85225&amp;ll=33.359065,-111.833096&amp;spn=0.021507,0.025749&amp;z=14&amp;iwloc=addr&amp;source=embed">View Larger Map</a></p>
]]></content>
		</item>
		
		<item>
			<title>merb news</title>
			<link>https://matt.aimonetti.net/posts/2008-12-merb-news/</link>
			<pubDate>Mon, 08 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-merb-news/</guid>
			<description>3 days ago, I announced the Merb Open Source Book project. I expected that few people would be interested as we heard complaints about the lack of documentation.
What I did not expect, was more than 60 emails and pull requests in 2 days, people committing pages of content, fixes and offering their services to translate the book. The mailing list already has 60+ members and the GitHub repository is being watched by 150+ people and has 50+ forks.</description>
			<content type="html"><![CDATA[<p>3 days ago, I announced the <a href="https://merbist.com/2008/12/04/annoucing-the-merb-open-source-book/">Merb Open Source Book project</a>. I expected that few people would be interested as we heard complaints about the lack of documentation.</p>
<p>What I did not expect, was more than 60 emails and pull requests in 2 days, people committing pages of content, fixes and offering their services to translate the book. The <a href="https://groups.google.com/group/merb-book">mailing list</a> already has 60+ members and the <a href="https://github.com/mattetti/merb-book/tree/master">GitHub repository</a> is being watched by 150+ people and has 50+ forks.</p>
<p>While this could be almost overwhelming, I think this is very encouraging. I have to say that since 1.0 got released we heard a lot of praises and and lot of complaints. The Merb team has been trying to prioritize and address reported challenges one after the other. We recently announced that user documentation was our top priority and we decided to work on two projects:</p>
<ul>
<li>
<p>better access to the code documentation</p>
</li>
<li>
<p>Open Source book</p>
</li>
</ul>
<h2 id="code-browsing">Code browsing:</h2>
<p>Good news, we have an early beta of the new code browser: <a href="https://docsbeta.merbivore.com/">https://docsbeta.merbivore.com/</a></p>
<p>This is still an early beta and only works properly on FireFox and Safari. You&rsquo;ll notice that currently, only merb-core&rsquo;s public methods are available. merb-more addition is coming soon.</p>
<p>So what&rsquo;s special about this code browser?</p>
<p>Contextual search and API filtering. In lay terms, you can see what public methods are available to you based on what you are doing. (are you in a controller, model, the console?)</p>
<h2 id="open-source-book">Open Source Book</h2>
<p>I put an early beta online: <a href="https://book.merbist.com">https://book.merbist.com
</a></p>
<p>This is not a static version yet meaning that the markdown files get converted for every single request. I&rsquo;m waiting for Geoffrey Grosenbach to finish his <a href="https://github.com/topfunky/merb_static/tree/master">merb_static plugin</a>. Once he will be done with the spidering, his plugin will automatically export the site as static HTML. The PDF version will be exported using a gem called UFO written by wycats. UFO is a JRuby bridge to Flying Saucer, an awesome Java library which can convert HTML to PDF.</p>
<p>As you can see if you browse the book, we don&rsquo;t have a lot of content yet. However, you need to realize that we just started 3 days ago! That is what&rsquo;s so amazing. People didn&rsquo;t sit back and wait for some core team members to write the content. To the contrary, they have been submitting content and have already started the book translation into 10 languages:</p>
<ul>
<li>
<p>English</p>
</li>
<li>
<p>French</p>
</li>
<li>
<p>Japanese</p>
</li>
<li>
<p>Portuguese</p>
</li>
<li>
<p>German</p>
</li>
<li>
<p>Chinese</p>
</li>
<li>
<p>Spanish</p>
</li>
<li>
<p>Russian</p>
</li>
<li>
<p>Bosnian</p>
</li>
<li>
<p>Dutch</p>
</li>
</ul>
<p>I expect to receive the first Italian translations early next week and I was promised some Indian languages too.</p>
<p><strong>Props to the entire community for putting its money where its mouth is!</strong></p>
<h2 id="whats-next">What&rsquo;s next?</h2>
<p><a href="https://yehudakatz.com">Yehuda Katz</a> was in Atlanta at <a href="https://merbday.com/">MerbDay</a> and had a great keynote about the future of Merb:</p>
<p><a href="https://www.slideshare.net/wycats/merb-day-keynote-presentation?type=powerpoint">Merb Day Keynote</a></p>
<p>However, in the short term, we&rsquo;ll still focus on documentation, bug fixes and <a href="https://twitter.com/wycats/status/1044577046">recently added as a top priority</a>: Merb and gem dependencies issues (Rubygems)</p>
<h2 id="datamapper-news">DataMapper news</h2>
<p>Our good friends from the DM team <a href="https://twitter.com/datamapper/status/1044706717">announced</a> DataMapper 0.9.8 and Extlib 0.9.9. What&rsquo;s new?</p>
<ul>
<li>
<p>update_attributes regression fixed</p>
</li>
<li>
<p>JRuby fixes</p>
</li>
<li>
<p>perf boost</p>
</li>
</ul>
<p>Congrats guys!</p>
]]></content>
		</item>
		
		<item>
			<title>annoucing the merb open source book</title>
			<link>https://matt.aimonetti.net/posts/2008-12-annoucing-the-merb-open-source-book/</link>
			<pubDate>Thu, 04 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-annoucing-the-merb-open-source-book/</guid>
			<description>Here is a graph representing the growth of of web searches related to the programming category. This is not a comparison of the amount of searches made.
We can see a huge peak around the time Merb 1.0 got released. More and more people are looking for information about what&amp;rsquo;s already being called the &amp;ldquo;Ruby web framework for the enterprise&amp;rdquo;. This is obviously a very interesting and encouraging trend. The problem is that unfortunately, the reality is that when you search for Merb documentation you don&amp;rsquo;t get very useful results.</description>
			<content type="html"><![CDATA[<p><img src="https://merbist.com/wp-content/uploads/2008/12/google-insights-worldwide-jul-dec-2008.jpg" alt="Matt Aimonetti compares the search growth between Rails and Merb"></p>
<p>Here is a graph representing the growth of of web searches related to the programming category. This is not a comparison of the amount of searches made.</p>
<p>We can see a huge peak around the time Merb 1.0 got released. More and more people are looking for information about what&rsquo;s already being called the &ldquo;Ruby web framework for the enterprise&rdquo;. This is obviously a very interesting and encouraging trend. The problem is that unfortunately, the reality is that when you search for Merb documentation you don&rsquo;t get very useful results.</p>
<p>Worse still, the main complaint we get is the lack of end user documentation. No fancy screensavers, no demo applications, just a simple, well organized but not expansive <a href="https://wiki.merbivore.com">wiki</a>. Don&rsquo;t get me wrong, I&rsquo;m really proud of our wiki. The wiki was restarted from scratch during the 1.0 RC era and we have some really decent documentation including a step by step BDD example with code on GitHub. The problem is that wikis, in general, are not easy to read when you want to learn a new technology. But they are great when you look for answers to a specific question, like: how do I use authentication, how do use transaction specs with RSpec&hellip;</p>
<p>The Ruby community is used to not having great open source documentation and to purchasing books written by experts. I remember when I joined the Ruby community, the company I was working for was looking at three frameworks: one written in PHP, the other in Python and the last one in Ruby. The Python framework was the fastest but didn&rsquo;t have a testing harness. The PHP framework had great documentation but was PHP (no comment).Â  And the Ruby framework almost did not have any documentation but had great momentum. It also had a book released which kind of compensated for the lack of documentation. (I don&rsquo;t think we would have picked the Ruby framework if all the engineers did not fall in love with the language :p)</p>
<p>Merb has 4 books in the process of being written, 2 of them already available in Beta. This is really exciting but it doesn&rsquo;t answer the need of two types of audiences:</p>
<ul>
<li>
<p>People who decide to give Merb a try and don&rsquo;t have much time/patience/money ;)</p>
</li>
<li>
<p>People outside of the English speaking world (yes, even though according to Hollywood, even aliens speak English, the reality is that a lot of people prefer to read documentation in their native language)</p>
</li>
</ul>
<p>Looking at other frameworks, a lot of the well known ones offer free books. <a href="https://www.djangoproject.com/">Django</a> has its famous <a href="https://djangobook.com/">Django Book</a>, <a href="https://www.symfony-project.org">Symfony</a> has its <a href="https://www.symfony-project.org/book/1_2/">book</a>&hellip;</p>
<p>To address the needs of people who want to get started quickly, we probably need to write some great tutorials. I think we will soon focus on that. People have already started writing awesome tutorials on getting started with glassfish and Merb and other cool things. However, most of these tutorials are designed for people who already have some Ruby knowledge. So the core team will probably need to help the community get a bit more organized and write some good simple tutorials for total newbies. However this is not really hard to do.</p>
<p>The real challenge for me is to reach the foreign audience. As you have probably noticed by the amount of English mistakes I make, I&rsquo;m not a native English speaker. I remember learning English by asking my mom to translate computer messages I was getting when using my cousin&rsquo;s <a href="https://en.wikipedia.org/wiki/Amstrad_CPC">Amstrad CPC</a> and my dad&rsquo;s <a href="https://en.wikipedia.org/wiki/PC-1512">Amstrad PC 1512.</a> The first English words I remember learning were: &ldquo;Game Over&rdquo; and &ldquo;insert the floppy disk&rdquo; :)</p>
<p><img src="https://farm1.static.flickr.com/69/206957476_e74acf006e_m.jpg" alt="">Talking with Brazilian Ruby evangelist Fabio Akita about his books, he reminded me how hard it is to get up to date IT documentation in your mother tongue. People talk about Globalization but in a time were knowledge is power, people outside of the US are still getting IT books one to two years after their US release.</p>
<p>PDF books make things a bit easier but you still need to be able to understand and of course you need to hope the online shop will accept your &ldquo;foreign&rdquo; card.</p>
<h2 id="merb-book">Merb book</h2>
<p>The Merb team has decided to support the documentation effort. At first we thought about updating Matthew Ford&rsquo;s <a href="https://merb.4ninjas.org/">Merb 4 ninja book</a>. But the project was started when Merb 0.3.x was released and needed a huge amount of work to be brought up to date.</p>
<p>After talking with Matthew, we decided it was probably better to start a new project backed by the core team. I quickly put together a simple localized Merb app rendering markdown files using awesome <a href="https://maruku.rubyforge.org/">maruku</a>.</p>
<p>The app is simple to use, simple for editors to contribute content, simple for translators to do their job.</p>
<p>We gathered three Merb book authors: Yehuda Katz, Foy Savas and Matthew Ford and worked on an initial <a href="https://github.com/mattetti/merb-book/tree/master/book-content/en/toc.markdown">table of contents</a>. At the same time, I got in contact with Fabio Akita, Mathieu Fosse and Makoto Kuwata to see if they were interested in leading the translation in Portuguese, French and Japanese. Everybody got really excited and wanted to start as soon as possible. Here is a short list of goals for the book:</p>
<ul>
<li>
<p>From the community, for the community</p>
</li>
<li>
<p>Creative Commons share alike type copyright</p>
</li>
<li>
<p>Simple, organized and up to date documentation of the Merb stack</p>
</li>
<li>
<p>Focus on the common use cases</p>
</li>
<li>
<p>Early localization to allow centralized, up to date documentation in various languages</p>
</li>
<li>
<p>Export to static HTML and PDF</p>
</li>
</ul>
<p>The initial work is available in my <a href="https://github.com/mattetti/merb-book/tree/master">GitHub repo</a> and we are planning on publishing an updated version of the book daily. The book will be tagged at the same time as Merb releases, to allow people to go back in time and check the book for a previous version of the framework.</p>
<p>If you are interested in helping, it&rsquo;s very simple:</p>
<p>add/modify content:</p>
<ul>
<li>
<p>clone the book repo</p>
</li>
<li>
<p>modify/add content</p>
</li>
<li>
<p>rebase to avoid conflicts</p>
</li>
<li>
<p>send me a pull request</p>
</li>
</ul>
<p>translate content:</p>
<ul>
<li>
<p>Find out who the translator leader is for your language (check the readme file in the repo)</p>
</li>
<li>
<p>clone the book repo</p>
</li>
<li>
<p>add translations</p>
</li>
<li>
<p>send the leader your pull request</p>
</li>
</ul>
<p>If there is no translator leader for your language, contact me.</p>
<p>I really hope to be able to add Spanish, German and Chinese pretty soon. If you are willing to lead the translation work for these languages, please contact me via email (mattaimonetti at Gmail or via github).</p>
<p>Join the mailing list if you want to get the latest news or discuss the content.</p>
<p><img src="https://groups.google.com/groups/img/3nb/groups_bar.gif" alt="Google Groups"></p>
<p>**Subscribe to the merb book mailing list **</p>
<p>Email:</p>
<p><a href="https://groups.google.com/group/merb-book">Visit this group</a></p>
<p>Finally, Yehuda has been working on another very simple Merb app to let you find available methods and their documentation in context. RDoc is fine, but how do you know what methods are available when you are in a view, and what about in a Model? Once again, the concept is to make your life as developer easier. For a long time we have focused on the framework itself. It&rsquo;s now time we focused on making it easy to use so more people can enjoy the power and flexibility of Merb.</p>
<p>Of course, all of this is done for you. So if you have any comments, concerns, advise, feel free to contact us directly or leave a comment.</p>
]]></content>
		</item>
		
		<item>
			<title>merb loves rails</title>
			<link>https://matt.aimonetti.net/posts/2008-12-merb-loves-rails/</link>
			<pubDate>Tue, 02 Dec 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-12-merb-loves-rails/</guid>
			<description>[caption id=&amp;quot;&amp;quot; align=&amp;ldquo;alignright&amp;rdquo; width=&amp;ldquo;240&amp;rdquo; caption=&amp;ldquo;Love is in the air&amp;rdquo;][/caption]
Yes, it is true and no, I am not being passive aggressive or cynical.
As you might have heard there has been some tension between the Rails team and the Merb team in the last few weeks. Sometimes caused by us, sometimes caused by them. I already addressed this issue in this blog post, so let&amp;rsquo;s move on.
Let me first explain the reason for this blog post.</description>
			<content type="html"><![CDATA[<p>[caption id=&quot;&quot; align=&ldquo;alignright&rdquo; width=&ldquo;240&rdquo; caption=&ldquo;Love is in the air&rdquo;]<a href="https://flickr.com/photos/swamibu/2264617197/"><img src="https://farm3.static.flickr.com/2018/2264617197_df9bf2ee53_m.jpg" alt="Love is in the air"></a>[/caption]</p>
<p>Yes, it is true and no, I am not being <a href="https://en.wikipedia.org/wiki/Passive-aggressive_behavior">passive aggressive</a> or cynical.</p>
<p>As you might have heard there has been some tension between the Rails team and the Merb team in the last few weeks. Sometimes caused by us, sometimes caused by them. I already addressed this issue in <a href="https://merbist.com/2008/11/15/rails-vs-merb-drama/">this blog post</a>, so let&rsquo;s move on.</p>
<p><a href="https://merbist.com/wp-content/uploads/2008/12/mac_pc.png"><img src="https://merbist.com/wp-content/uploads/2008/12/mac_pc-267x300.png" alt="Mac vs PC - Matt Aimonetti"></a>Let me first explain the reason for this blog post.** I believe we have a great community but I also believe we like bashing**.</p>
<p>Like most Rubyists, I use a mac and I often smile when I watch their ads. Then I see Microsoft&rsquo;s response ad and I think &hellip; they don&rsquo;t get it, I&rsquo;m not a Mac, the dude on TV represents the Mac computer. I&rsquo;m a human.</p>
<p>Thinking back to our community, I felt that it quickly became: &lsquo;Hi, I&rsquo;m a Rails developer&rsquo; and &lsquo;Hi I&rsquo;m a Merb developer&rsquo;.</p>
<p><strong>What started as a simple comparison to explain what the difference was between Merb and Rails quickly escalated into arguments about what framework is best and which one people should use.</strong></p>
<p>I hear people in the Ruby community talking trash about Rails and criticize the Rails core team. I even saw people insulting DHH on IRC while he was not even on the channel.</p>
<p>I, myself, have to admit that I have been guilty of crossing the line a few times and have made some comments which can be considered as &ldquo;bashing&rdquo;.</p>
<p><strong>I think now is a good time to apologize and to say that this kind of behavior is not appropriate.</strong></p>
<p>After all, if we wanted to define ourselves as being &ldquo;something&rdquo; we probably should say: &ldquo;Hi, I&rsquo;m a Ruby developer&rdquo;. Rails is not perfect, nor is Merb. I might disagree with some of the decisions made by the Rails core team but I still think Rails is a great framework and the Rails team has done an awesome job and deserves a lot of respect for its efforts. We are all part of the Ruby community and I think it&rsquo;s time we all (starting by myself) act as a unified community.</p>
<p>Without further ado, here is my &hellip;</p>
<h3 id="top-10-reasons-why-we-3-rails">Top 10 reasons why we &lt;3 Rails:</h3>
<ul>
<li>
<p>Without Rails, the Ruby language would not be <a href="https://www.tiobe.com/tiobe_index/index.htm">one of the top 10 programming languages</a></p>
</li>
<li>
<p>Without Rails, we would still be writing <a href="https://www.skywayradio.com/tech/iSeries/wps/admxmsmp.html">thousand-line configuration files in XML</a> to start your small app</p>
</li>
<li>
<p>Without Rails, most developers would not know what <a href="https://en.wikipedia.org/wiki/Model-view-controller">MVC</a> stands for</p>
</li>
<li>
<p>Without Rails, I would not be a Ruby web developer</p>
</li>
<li>
<p>Without Rails, we would not have <a href="https://merbivore.com">Merb</a></p>
</li>
<li>
<p>Without Rails, we would not have all the other cool Ruby frameworks</p>
</li>
<li>
<p>Without Rails, <a href="https://rspec.info">testing</a> would be something only the elite would do</p>
</li>
<li>
<p>Without Rails, serving Ruby web apps would be a pain in the neck</p>
</li>
<li>
<p>Without Rails, <a href="https://www.zedshaw.com/">Zed Shaw</a> would not be famous</p>
</li>
</ul>
<p>Bonus items:</p>
<ul>
<li>
<p>Without Matz, there would be no Ruby</p>
</li>
<li>
<p>Without Ruby, there would be no Rails</p>
</li>
</ul>
<p>Next time you think, I&rsquo;m a Merb or I&rsquo;m a Rails, think twice :)</p>
]]></content>
		</item>
		
		<item>
			<title>latest news from merbland nov 30</title>
			<link>https://matt.aimonetti.net/posts/2008-11-latest-news-from-merbland-nov-30/</link>
			<pubDate>Sun, 30 Nov 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-11-latest-news-from-merbland-nov-30/</guid>
			<description>Wow, It&amp;rsquo;s been two weeks since my last post. I&amp;rsquo;m really sorry about that but at the same time, I really enjoyed Qcon and Thanksgiving which did not give me much time to work on a blog post.
[caption id=&amp;ldquo;attachment_291&amp;rdquo; align=&amp;ldquo;alignleft&amp;rdquo; width=&amp;ldquo;200&amp;rdquo; caption=&amp;ldquo;Mr Bean vs X-mas turkey&amp;rdquo;][/caption]
Thanksgiving is a big thing in America, and after few years I got used to it and I even learned to enjoy this special holiday.</description>
			<content type="html"><![CDATA[<p>Wow, It&rsquo;s been two weeks since my <a href="https://merbist.com/2008/11/16/merb-news-nov-16-2008/">last post</a>. I&rsquo;m really sorry about that but at the same time, I really enjoyed <a href="https://qconsf.com/sf2008/conference/">Qcon</a> and <a href="https://en.wikipedia.org/wiki/Thanksgiving">Thanksgiving</a> which did not give me much time to work on a blog post.</p>
<p>[caption id=&ldquo;attachment_291&rdquo; align=&ldquo;alignleft&rdquo; width=&ldquo;200&rdquo; caption=&ldquo;Mr Bean vs X-mas turkey&rdquo;]<img src="https://merbist.com/wp-content/uploads/2008/11/mr-bean-turkey.jpg" alt="Mr Bean vs X-mas turkey">[/caption]</p>
<p>Thanksgiving is a big thing in America, and after few years I got used to it and I even learned to enjoy this special holiday.</p>
<p>For non North American readers, Thanksgiving is a non-religous/family oriented celebration where people get together, eat a lot of food and usually watch an American football game. It&rsquo;s followed by &ldquo;black-friday&rdquo; the first day of X-mas shopping celebrated by huge sales and more recently &ldquo;cyber-monday&rdquo;, the black firday for the web.</p>
<p>Anyways, I&rsquo;ve been visiting family in Florida and didn&rsquo;t have much time to work on side projects, including Merb :(</p>
<p><a href="https://qconsf.com/sf2008/conference/">Qcon</a> was also an awesome event where I met a lot of very interesting people and could measure the Merb interest in the &ldquo;Enterprise&rdquo; community.</p>
<h2 id="merb-and-the-enterprise">Merb and the enterprise</h2>
<p><a href="https://37signals.com">37signals</a>, the company known for giving Rails to the Ruby community often talked about the &ldquo;Enterprise&rdquo; world and the fact that they want to stay far away from it, here is a <a href="https://www.37signals.com/svn/posts/669-why-enterprise-software-sucks">quote</a> from 37signals blog:</p>
<blockquote>
<p>This is one of the reasons we think enterprise is a dirty word. Itâ€™s also why itâ€™s an absolute pleasure to design products for what we call the Fortune 5,000,000.</p>
</blockquote>
<p>On the other hand, Merb was mainly written by people working at <a href="https://engineyard.com">EngineYard</a>, a company dealing with a lot of so call &ldquo;enterprisey&rdquo; companies. Because we believe we all have different needs we are willing to help you out with your own needs. That&rsquo;s also the reason why, even though none of the core team members use <a href="https://www.netbeans.org/">NetBeans</a> for their day to day coding, we decided to help <a href="https://www.netbeans.org/">NetBeans</a> add Merb support in their next release.</p>
<p>Interesting enough, during the preparation of my talk, I did a simple &ldquo;hello world&rdquo; benchmark and got some really interesting results:</p>
<p><img src="https://merbist.com/wp-content/uploads/2008/11/benchmarks.png" alt=""></p>
<p>Note that Django was tested with mod_python and I was told I could get slightly better results with mod_wsgi.</p>
<p>It was interesting to hear <a href="https://en.wikipedia.org/wiki/Tim_Bray">Tim Bray</a>, known for his implication with XML and ATOM, mention Merb, DataMapper and CouchDB during his keynote!</p>
<p>Actually, the day before, Yehuda and I had supper with Tim Bray and <a href="https://blog.nicksieger.com/">Nick Sieger</a> from JRuby to discuss few topics but particaluarly how could we improve the framework and of course take advantage of JRuby.</p>
<h2 id="merb-and-the-brazilian-community">Merb and the Brazilian community</h2>
<p><a href="https://merbist.com/wp-content/uploads/2008/11/beachgirls.jpg"><img src="https://merbist.com/wp-content/uploads/2008/11/beachgirls-229x300.jpg" alt=""></a>Brazil is well known for his beautiful beaches, girls and music. It&rsquo;s also known for its soccer team and its BBQ. However it&rsquo;s not really known for its software developers and IT community.</p>
<p>Nevertheless, there was a lot of Brazilians during Qcon and especially a team from <a href="https://www.locaweb.com.br/">LocaWeb</a>, the biggest Brazilian web hosting!</p>
<p>You might not know LocaWeb, but but you might have heard of <a href="https://akitaonrails.com/">Fabio Akita</a>. Fabio interviewed a lot of people for his blog and I guess he was bored so he decided to <a href="https://akitaonrails.com/2008/11/21/rails-podcast-brasil-qcon-special-john-straw-yellowpages-com-and-matt-aimonetti-merb">interview me</a> ;)</p>
<p>We also sat down for a little while and went through creating a new Merb app, I think Fabio was pretty impressed ;) He was so impressed he mentioned the possibility of aÂ  Merb book in Portuguese!</p>
<p>LocaWeb also mentioned their interest in offering better Merb hosting with the possibilty to have their own stack for people who decide to host their apps there.</p>
<p><a href="https://merb-br.org/">Here</a> is the site of the Merb community: <a href="https://merb-br.org/">https://merb-br.org/</a></p>
<h2 id="rails-22">Rails 2.2</h2>
<p>Congrats to the Rails team for releasing Rails 2.2! The new features are:</p>
<ul>
<li>
<p>i18n</p>
</li>
<li>
<p>HTTP validators</p>
</li>
<li>
<p>Thread safety</p>
</li>
<li>
<p>JRuby/1.9 compatibility</p>
</li>
</ul>
<p>I heard a lot of questions about the new Rails features and where does Merb stand. So let me take them address them one by one:</p>
<ul>
<li>
<p><strong>Internationalization.</strong> I, myself was involved with the Rails i18n project so you might be surprise to hear that Merb doesn&rsquo;t have a built-in i18n solution.Â  Well, the fact of the matter is that Merb is modular and we don&rsquo;t want to force anyone to have to use a i18n solution which will slow down your app. Instead we offer modules to do that. Of course, Merb itself offers hooks to l10n helpers and other stuff you might need. By default, Merb doesn&rsquo;t offer UTF-8 string manipulation like ActiveSupport does, however, few months ago, <a href="https://github.com/mattetti/multibyte">I extracted AS&rsquo;s feature</a> and you can use the <a href="https://github.com/mattetti/multibyte">extracted gem</a> without the rest of AS while we wait for 1.9 to save the world ;)
Merb makes everything easy for i18n/l10n plugin developers, <a href="https://github.com/mattetti/merb_babel/tree/master">merb_babel</a> and <a href="https://github.com/myabc/merb_global/">merb_global</a> are just 2 of the Merb localization plugins, you&rsquo;ll find <a href="https://r18n.rubyforge.org/">many more</a> and some more are coming up.</p>
</li>
<li>
<p><strong>HTTP validators/etags</strong>. Merb already had this feature for a little while, I put a <a href="https://wiki.merbivore.com/howto/cache/etag">quick example in the wiki</a>, check it out <a href="https://github.com/wycats/merb/tree/ad378ce413769bc1c3d03aefac02e8e32a5432e4/merb-core/lib/merb-core/controller/mixins/conditional_get.rb"></a> to <a href="https://wiki.merbivore.com/howto/cache/etag">see how to use etag and last-modified tags</a>. Note that you can easy add other custom headers by just doing: headers[&quot;<a href="https://tools.ietf.org/html/rfc2616#section-14.9"><code>Cache-Control&quot;] = &quot;max-age=N&quot;</code></a></p>
</li>
<li>
<p><strong>Thread safety</strong>. Well, unlike Rails which added thread safety as an after thought, Merb was built with the concept of thread safety in mind. What does that mean? Well, by default, Merb requests don&rsquo;t go through any locks. How? simply because we do not share any data between requests. thread safety is really hard to deal with. However remember that even though your framework is thread safe, your plugins and your code also need to be thread safe. Watch <a href="https://rubyconf2008.confreaks.com/what-all-rubyist-should-know-about-threads.html">Jim&rsquo;s talk about threads</a> if you want to know more.</p>
</li>
</ul>
<h2 id="merb-bug-fix-releases">Merb bug fix releases</h2>
<p>You might have noticed that Merb is at 1.0.3. We fixed few tiny bugs as well as bumped the generated app dependency to the latest version of DM. (DataMapper&rsquo;s do_sqlite3 had a conflict with ruby-sqlite3 because of the windows dll pacakged with the gem. Everything has been fixed since.)</p>
<blockquote>
<p>Yehuda Katz, explained the release plan in an email to the mailing list:</p>
</blockquote>
<p>We plan to release point-releases to 1.0 as fixes become available, so there may be more such releases than in Rails. The goal is to release often enough to keep the list of changes in each release relatively small and understandable, and you can feel free to upgrade to the latest point release every 2 weeks if you don&rsquo;t want to go through the upgrade process every week (or more frequently). Keep an eye out for point releases that reflect security fixes, because those upgrades should be considered mandatory.</p>
<p>To see <a href="https://merb.lighthouseapp.com/projects/7433-merb/tickets/bins/11568">1.0.4</a> and <a href="https://merb.lighthouseapp.com/projects/7433-merb/tickets/bins/11569">1.1</a> tickets, check <a href="https://merb.lighthouseapp.com/projects/7433-merb/overview">LightHouse</a>. We are planning on a 1.0.4 release for next week.</p>
<h2 id="better-documentation">Better documentation</h2>
<p>Merb&rsquo;s documentation is getting better and better, here is a selection of few blog posts I think you might want to read. (hopefully all the info are or will be available in the wiki)</p>
<ul>
<li>
<p><a href="https://atmos.org/index.php/2008/11/29/merb-10-controller-testing/">Testing your controller from atmos.org</a></p>
</li>
<li>
<p><a href="https://weblogs.java.net/blog/arungupta/archive/2008/11/totd_53_scaffol.html">Merb and Glassfish from java.net</a></p>
</li>
<li>
<p><a href="https://singlecell.angryamoeba.co.uk/post/60951656/an-introduction-to-merb-auth-and-the-wonderful-secrets">Merb Auth from angryamoeba.com</a></p>
</li>
<li>
<p><a href="https://scottmotte.com/archives/tag/merb-mailer">Merb Mailer from scottmotte.com</a></p>
</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>merb news nov 16 2008</title>
			<link>https://matt.aimonetti.net/posts/2008-11-merb-news-nov-16-2008/</link>
			<pubDate>Sun, 16 Nov 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-11-merb-news-nov-16-2008/</guid>
			<description>I&amp;rsquo;ll try to keep the community posted on the latest merb news. Feel free to email me if you want me to feature your app, plugin, tool or blog post.
  Quality time with Yukihiro Matsumoto (ã¾ã¤ã‚‚ã¨ã‚†ãã²ã‚) aka Matz, Ruby author
  Hack time with Aaron Paterson (Nokogiri) and Bryan Helmkamp (Webrat)
  Merb presentation at ORUG
  RailsCamp Australia
  Rails podcast
  Rails vs Merb drama</description>
			<content type="html"><![CDATA[<p>I&rsquo;ll try to keep the community posted on the latest merb news. Feel free to email me if you want me to feature your app, plugin, tool or blog post.</p>
<ul>
<li>
<p>Quality time with Yukihiro Matsumoto (ã¾ã¤ã‚‚ã¨ã‚†ãã²ã‚) aka Matz, <a href="https://ruby-lang.org">Ruby</a> author</p>
</li>
<li>
<p>Hack time with <a href="https://github.com/tenderlove">Aaron Paterson</a> (<a href="https://tenderlovemaking.com/2008/10/30/nokogiri-is-released/">Nokogiri</a>) and <a href="https://flickr.com/photos/obie/3036045613/">Bryan Helmkamp</a> (<a href="https://github.com/brynary/webrat/tree/master">Webrat</a>)</p>
</li>
<li>
<p>Merb presentation at <a href="https://orug.org">ORUG</a></p>
</li>
<li>
<p><a href="https://railscamp08.org">RailsCamp</a> Australia</p>
</li>
<li>
<p><a href="https://podcast.rubyonrails.org/programs/1/episodes/rubyconf-2008">Rails podcast</a></p>
</li>
<li>
<p><a href="https://merbist.com/2008/11/15/rails-vs-merb-drama/">Rails vs Merb drama</a></p>
</li>
<li>
<p>Documentation</p>
</li>
<li>
<p>Merb 1.0.1</p>
</li>
<li>
<p><a href="https://qconsf.com/sf2008/tracks/show_track.jsp?trackOID=172">Qcon</a></p>
</li>
</ul>
<h2 id="quality-time-with-matz">Quality time with Matz</h2>
<p>The day after Ruby Conf, <a href="https://yehudakatz.com">Yehuda Katz</a> and myself (Matt Aimonetti) were hanging out in the lobby of the hotel. <a href="https://obiefernandez.com/">Obie</a>, <a href="https://flickr.com/photos/obie/3036221023/">Rein</a>, <a href="https://flickr.com/photos/obie/3036211957/">Desi</a>, and others were hacking away/chilling. Matz was also there networking before taking off for the airport.</p>
<p>[caption id=&ldquo;attachment_273&rdquo; align=&ldquo;alignleft&rdquo; width=&ldquo;300&rdquo; caption=&ldquo;wycats, matz, mattetti&rdquo;]<img src="https://merbist.com/wp-content/uploads/2008/11/katz_matz_mattetti-300x149.jpg" alt="wycats, matz, mattetti">[/caption]</p>
<p>Matz and I started talking about the fact that unlike what most people believe, Ruby for the web is fast, way faster than any PHP solution. We looked at different benchmarks, discussed the philosophical differences between Merb and Rails, his own view of web development and how Ruby was perceived in Japan. Yehuda joined us and we started talking about Ruby 1.9.</p>
<p>Koichi had a great presentation abou<a href="https://www.flickr.com/photos/notheory/3037535342/in/photostream"><img src="https://farm4.static.flickr.com/3046/3037535342_d35680909d_m.jpg" alt=""></a>t YARV few days before and we spent few hours chatting with the JRuby guys and Laurent Sansonetti from MacRuby. We had some concerns about Ruby 1.9, Matz also asked us about Ruby 1.8.7. It was great to get a direct feedback about what&rsquo;s going on in the Ruby team, their schedule, process etc&hellip; We also realized that we (the Merb team) need to communicate better with the Ruby team when we need something added the language. It was also very interesting to hear Matz' opinion on Ruby Enterprise Edition.Â  As everybody knows Matz is a nice guy and that&rsquo;s why Ruby people should be nice :)Â  I have to agree, Matz is a very kind and patient person.</p>
<h2 id="hack-time-with-aaron-patterson-and-bryan-helmkamp">Hack time with Aaron Patterson and Bryan Helmkamp</h2>
<p>[caption id=&quot;&quot; align=&ldquo;alignleft&rdquo; width=&ldquo;240&rdquo; caption=&ldquo;Yehuda (Merb), Charles (JRuby) and Laurent (MacRuby)&quot;]<a href="https://www.flickr.com/photos/notheory/3037534604/in/photostream/"><img src="https://farm4.static.flickr.com/3051/3037534604_fe74986020_m.jpg" alt="Yehuda (Merb), Charles(JRuby) and Laurent(MacRuby)"></a>[/caption]</p>
<p>One of the reasons why RubyConf was awesome is that every other guy was the author/maintainer of a major Ruby library. As you know Merb plays well with a lot of various libraries and having some time to seat down with the maintenairs of these libraries make things way easier.</p>
<p><a href="https://tenderlovemaking.com/2008/10/30/nokogiri-is-released/">Nokogiri</a> As already mentioned, we switched to nokogiri before 1.0. Nokogiri is based on libxml2 which is a fast and reliable XML parser. I won&rsquo;t get into the hpricot vs nokogiri argument, but let&rsquo;s just say that nokogiri was fitting our needs better. (Nokogiri is only used in the specs, and therefore is not needed to run Merb)</p>
<p>[caption id=&rdquo;&quot; align=&ldquo;alignright&rdquo; width=&ldquo;240&rdquo; caption=&ldquo;David Chelimsky (RSpec), Matt Aimonetti (Merb)&quot;]<a href="https://www.flickr.com/photos/notheory/3036694117/"><img src="https://farm4.static.flickr.com/3053/3036694117_13b53141d7_m.jpg" alt="David Chelimsky(RSpec), Matt Aimonetti(Merb)"></a>[/caption]</p>
<p><a href="https://github.com/brynary/webrat/tree/master">Webrat</a> is an awesome library that let you test your app by using a virtual browser or by integrating with <a href="https://selenium.seleniumhq.org/">Selenium</a>. Webrat also switched to Nokogiri and we moved some of our matchers directly to webrat since webrat became a Merb development dependency. Thanks to webrat you can write tests that will fill up forms, follow links, select options&hellip; basically act as a user. What&rsquo;s even better is that you can run these test directly in your browser thanks to Selenium!Â  Because we think Webrat is totally awesome, we decided to offer framework support so people wanting to use webrat functionalities could do it without struggling, it there out of the box.</p>
<p>I have to say that both Bryan and Aaron are great guys, even though they both had their girlfriends with them, they spent time with us working out some details and discussion options. Thanks a lot guys!</p>
<p>(p.s: both projects also work great with Rails)</p>
<h2 id="merb-presentation-at-orug">Merb presentation at ORUG</h2>
<p><a href="https://orug.org">Orlando Ruby Group</a> meets once a month and this month I was invited to talk about Merb. Just before me, Thomas Meeks gave a great talk on Nanite. It was really nice to meet a lot of the local Merbists. Most of them went to RubyConf, but I didn&rsquo;t get to meet everyone, so it was great to a sescond chance to network.</p>
<p><a href="https://www.slideshare.net/mattetti/merb-presentation-at-orug-presentation">My slides are available on slideshare.net</a> You might be interested in looking at the different Merb app formats (very_flat, flat, core and stack) examples starting slide 45.</p>
<p><a href="https://www.slideshare.net/mattetti/merb-presentation-at-orug-presentation?type=powerpoint">Merb presentation at ORUG</a></p>
<h2 id="railscamp-australia">RailsCamp Australia</h2>
<p>[caption id=&ldquo;attachment_275&rdquo; align=&ldquo;alignright&rdquo; width=&ldquo;150&rdquo; caption=&ldquo;Daniel giving a talk on Merb&rdquo;]<img src="https://merbist.com/wp-content/uploads/2008/11/hassox-railscamp1-150x150.jpg" alt="Daniel giving a talk on Merb">[/caption]</p>
<p><a href="https://railscamp08.org">RailsCamp</a> Australia took place in Adelaide this year. Of course our Australian core team member couldn&rsquo;t miss the event. Daniel Neighman aka hassox, the man being merb-auth made it to the event and talked about Merb. (RailsCamp is more of a RubyCamp than a Rails conf so nobody really complained, hassox got a lot of good feedbacks)</p>
<h2 id="rails-podcast">Rails Podcast</h2>
<p><a href="https://nubyonrails.com/">Geoffrey Grosenbach</a>, one of the first merbists and very well known figure of the Ruby/Rails community <a href="https://podcast.rubyonrails.org/programs/1/episodes/rubyconf-2008">recorded a podcast</a> during RubyConf. Geoffrey interviewed me about Merb 1.0 as well as Blake from <a href="https://sinatra.rubyforge.org/">Sinatra</a> and josh Peek from <a href="https://rubyonrails.org/">Rails</a>.</p>
<h2 id="rails-vs-merb-drama">Rails vs Merb drama</h2>
<p>I already explained the whole story in <a href="https://merbist.com/2008/11/15/rails-vs-merb-drama/">a previous post</a>. It seems that Yehuda and David agree on something: <a href="https://yehudakatz.com/2008/11/16/mythbusting-we-agree-ruby-is-awesome/">Ruby is awesome</a>. <a href="https://www.loudthinking.com/">David</a> is still ignoring Merb, but is answering indirectly via an interesting series of <a href="https://www.loudthinking.com/posts/29-the-rails-myths">Rails Myths</a>. Over on Twitter, <a href="https://twitter.com/adzap/statuses/1007999209">adzap suggests</a> that Yehuda was just following DHH advise, and was trying to create a conflict because, <a href="https://www.37signals.com/svn/archives2/conflict_is_good_for_business.php">according to 37signals conflict is good for business</a>. I don&rsquo;t think that&rsquo;s what Yehuda had in mind when he replied to Jeremy, but that would explain why DHH ignores <em>(Â¿on purprose?)</em> the Merb community.</p>
<h2 id="documentation">Documentation</h2>
<p>Since 1.0 is out, our main focus has been documentation. However we can&rsquo;t write all the documentation ourselves. So we focused on helping people on IRC/Mailing list so they can help us with the documentation. The Japanese merbists started their own wiki, the Chinese, French and Japanese merbists started their own mailing list. <a href="https://jijixi.azito.com/cgi-bin/diary/index.rb?date=20081112">Here is an example</a> of Japanese thread covering some of Merb basics.</p>
<p>The <a href="https://wiki.merbivore.com">wiki</a> is also growing, I personally added a glossary to the &ldquo;<a href="https://wiki.merbivore.com/faq_converting_a_rails_app_to_merb">Rails to Merb guide</a>&rdquo;. Showing you the Merb equivalent of some of Rails idioms. I also posted a <a href="https://wiki.merbivore.com/example_apps/simple_app">merb example app</a> with sources available on <a href="https://github.com/mattetti/simple_merb_example_app/tree/master">github</a>.Â  While this is not a full app, the example covers:</p>
<ul>
<li></li>
</ul>
<p>generating an application</p>
<ul>
<li></li>
</ul>
<p>generating a resource</p>
<ul>
<li></li>
</ul>
<p>specing/testing a model</p>
<ul>
<li></li>
</ul>
<p>adding model validation</p>
<ul>
<li></li>
</ul>
<p>specing/testing requests</p>
<ul>
<li></li>
</ul>
<p>modifying views and layouts</p>
<ul>
<li></li>
</ul>
<p>passing flash messages (messages passed from one action to another)</p>
<ul>
<li></li>
</ul>
<p>adding authenticated routes</p>
<ul>
<li></li>
</ul>
<p>testing authenticated requests</p>
<p>Feel free to fork the project, add more branches (one step per branch please, so people can look at the diffs) etc&hellip;</p>
<p>My goal in writing this example was to show people the basics to get started and especilly how to test a merb app. Note that this is NOT the only way, but I feel strong about TDD and by providing you with simple examples you might also give it a try ;)</p>
<p>My next victim will be a Merb slice, I&rsquo;ll show you how to easily write and test a Merb slice to use, reuse and abuse your code.</p>
<p><a href="https://peepcode.com"><img src="https://peepcode.com/images/logo/peepcode.png" alt=""></a></p>
<p>Peepcode released <a href="https://peepcode.com/products/meet-merb-pdf-draft">an updated PDF covering Merb 1.0</a></p>
<p>I saw the draft of the upcoming Merb screencast, and once again, Geoffrey does an awesome job teaching you what you need to know.</p>
<p>(p.s: this blog is not sponsored by peepcode ;) )</p>
<p><a href="https://www.manning.com/ivey/"><img src="https://www.manning.com/ivey/ivey_cover150.jpg" alt=""></a><a href="https://www.manning.com/ivey/">Yehuda&rsquo;s beta book on Merb</a> also got updated to cover Merb 1.0.</p>
<p>The first chapter is available <a href="https://www.manning.com/ivey/katz_meapch1.pdf">for free</a>, the 3 other available chapters cover:</p>
<p>Getting started With Merb
Using Merb with a database
Automated testing</p>
<p>Since it&rsquo;s a beta book, you receive update/new chapters automatically.</p>
<p>(print version available later on)</p>
<p><a href="https://blog.obiefernandez.com/content/2008/08/announcing-the-merb-way-by-foy-savas.html"><img src="https://merbist.com/wp-content/uploads/2008/11/merb_way_cover-150x150.jpg" alt=""></a></p>
<p>Merb contributor,<a href="https://foysavas.com"> Foy Savas</a> told me he made a lot of progress on his book and he hopes to have a PDF version out before the end of the year.</p>
<p>You can meet Foy in person in Boston on November 17-20 at the Addison-Wesley <a href="https://www.voicesthatmatter.com/ruby2008/">Voices that Matter: Professional Ruby Conference</a>.</p>
<p>(I can&rsquo;t remember who is writing the third book on Merb, please contact me so I can update this section)</p>
<p>I also noticed a bunch of guys on IRC writing plugins and slices, I hope to see even more tutorials very soon.</p>
<h2 id="merb-101">Merb 1.0.1</h2>
<p>Merb 1.0.1 is in the work and should be released in the next few days. It&rsquo;s just a maintenance release, so nothing new but we expect to ship with the new upcoming version of DataMapper, optimized generator (you will be able to use spaces in between arguments if you follow the unix standard) and some bug fixes.</p>
<h2 id="qcon">Qcon</h2>
<p><a href="https://qconsf.com/sf2008/speaker/Gregg+Pollack"><img src="https://www.infoq.com/styles/i/logo.gif" alt="">Gregg Pollack</a> from the <a href="https://www.railsenvy.com/">RailsEnvy hall of fame</a>, is organizing a Ruby track during <a href="https://qconsf.com/sf2008/tracks/show_track.jsp?trackOID=172">Qcon</a>, the <a href="https://www.infoq.com/">infoQ</a> conference taking place in SanFrancisco this week. Both Yehuda and I are scheduled to talk. My talk is on Merb for the Enterprise and Yehuda&rsquo;s is on testing. If you are around, come say hi.</p>
]]></content>
		</item>
		
		<item>
			<title>merb 10 tips part 1</title>
			<link>https://matt.aimonetti.net/posts/2008-11-merb-10-tips-part-1/</link>
			<pubDate>Fri, 14 Nov 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-11-merb-10-tips-part-1/</guid>
			<description>Â As you must know by now, last week,Merb 1.0 got released.

Because we wanted to assure the release was fine, we asked Engine Yard, Apple and YellowPages.com to help us by hiring the NSA to monitor Merb users. After all, we need to know what people complain about so we can fix it ASAP.
Turns out all the echelon monitoring sites were already busy. So we had to go back to good old IRC and twitter search ;)</description>
			<content type="html"><![CDATA[<p>Â </p>
<p>As you must know by now, last week,<a href="https://merbist.com/2008/11/09/merb-1-0-released"> Merb 1.0 got released</a>.</p>
<p><a href="https://merbist.com/wp-content/uploads/2008/11/nsa_logo.gif"><img src="https://merbist.com/wp-content/uploads/2008/11/nsa_logo.gif" alt=""></a></p>
<p>Because we wanted to assure the release was fine, we asked <a href="https://engineyard.com">Engine Yard</a>, <a href="https://apple.com">Apple</a> and <a href="https://yellowpages.com">YellowPages.com</a> to help us by hiring the NSA to monitor Merb users. After all, we need to know what people complain about so we can fix it ASAP.</p>
<p>Turns out all the <a href="https://en.wikipedia.org/wiki/ECHELON">echelon monitoring sites</a> were already busy. So we had to go back to good old IRC and <a href="https://search.twitter.com/search?q=merb">twitter search</a> ;)</p>
<p>The release looks pretty solid, thanks to all the people reported bugs during the release candidate cycle. Thanks guys!</p>
<p>However there are still few points of confusion I&rsquo;d like to address.</p>
<h2 id="how-do-i-requirerequestload-a-plugin">How do I require/request/load a plugin?</h2>
<p>I saw this question few times on IRC and someone after my <a href="https://orug.org">ORUG</a> merb presentation tonight asked me exactly the same thing. I promised <a href="https://peepcode.com/">Geoffrey Grosenbach</a> that I would update the RDoc but in the meantime here is quick explanation.</p>
<p>You should almost never use the require method to load a gem. Rubygems has a method called gem that takes a version as an argument:</p>
<p><code> require &quot;rubygems&quot; gem &quot;merb-core&quot;, &quot;~&gt; 1.0&quot;</code></p>
<p>Using gem you can specify a version of the gem you want to load. Therefore you avoid loading an unexpected version of a gem. A few tricks to know (for regular Ruby code; keep reading for the Merb technique):</p>
<p>You can use &ldquo;=1.0&rdquo; to limit to version 1.0, or &ldquo;&gt;= 1.0&rdquo; to load 1.0 and anything newer. My favorite trick is to use &ldquo;~&gt; 1.0&rdquo; which means load latest version between 1.0 and 2.0</p>
<p>However when using Merb you don&rsquo;t want to load gems just whenever. Merb&rsquo;s bootup process starts by setting up the directory structure, and you typically want to load plugins after this point. To make this transparent to you, we have the #dependency method. The dependency method uses the gem method internally to load specific versions at the right time. Additionally, we may use it in the future to improve Merb&rsquo;s built-in bundling or dependency resolution. As a result, you should always use the dependency method, and not try to use require directly for Merb plugins.</p>
<p>It also comes with two tricks you should know about. Let&rsquo;s say you want to require a gem from github:</p>
<p><code> dependency &quot;mattetti-awesomeâ€, &quot;~&gt;1.0&quot;, :require_as =&gt; â€œawesomeâ€</code></p>
<p>The example above is the same as:
<code>gem &quot;mattetti-awesome&quot;, &quot;~1.0&quot; require &quot;awesome&quot;</code>
Apart that it gets loaded when it&rsquo;s appropriate.</p>
<p>You can also pass a block after your dependency call:</p>
<p><code> dependency('jchris-couchrest', &quot;&gt;= 0.5&quot;, :require_as =&gt; &quot;couchrest&quot;) do Â Â require &quot;lib/custom_hack.rb&quot; endÂ </code></p>
<p>The block will be executed after the gem is loaded and required. Use a block if you want to perform some action after the dependency is loaded.</p>
<p>Finally the last trick lets you load a gem right when you declare the dependency:</p>
<p><code> dependency &quot;nokogiriâ€, &quot;~&gt;0.5&quot;, :immediate =&gt; true</code></p>
<h2 id="i-have-issues-with-merb--i-and-cant-run-the-specs">I have issues with merb -i and can&rsquo;t run the specs</h2>
<p>Few things here, first off, Merb forces you to use rubygems 1.3 because 1.2 is very buggy and the Rubygems maintainer suggested we do so. Rubygems let you define development-only dependencies, dependencies you don&rsquo;t need to have to run your library in production. These dependencies were designed to be used when developing a library, but in the case of Merb, they are used to define dependencies that you only need at development-time, but not in production.</p>
<p>In our case we defined webrat as a development dependency. That means you need Webrat to run your specs, but won&rsquo;t need it in production. Now here is something you should know, whenever you install a gem to develop it, you should use:</p>
<p><code>gem install &quot;merb-core&quot; --development</code></p>
<p>The &ndash;development flag will install all the dev dependencies declared by the gem.  Now merb -i loads the code needed to make the request object available in the console, the problem is that this code also loads some test helpers which require webrat. We have a ticket open for that and will get to that soon.</p>
<p>In the mean time, make sure you have webrat and nokogiri installed. (Nokogiri requires you have a somehow recent version of libxml2, which comes with OSX, but not all Linux distributions).</p>
<p>People reported some issues updating rubygems, Robby Colvin wrote a <a href="https://robbycolvin.com/archives/merbrubygems-upgrade-errors/">nice article</a> explaining how to get pass this issue.</p>
<h2 id="issues-with-action-args-not-loading">Issues with action-args not loading</h2>
<p>Some people reported issues with loading action-args. Turns out it&rsquo;s some sort of weird issue with hoe (the library) and a some of action-args deps. If that happens to you, update hoe:<code></code></p>
<p><code>$ sudo gem install hoe</code></p>
<h2 id="i-generated-an-app-and-it-doesnt-work-with-jruby">I generated an app and it doesn&rsquo;t work with JRuby</h2>
<p>If you generate a merb using merb-gen app my-app-name it generates a merb stack app. It&rsquo;s an opinionated bundle with everything you might need including jQuery, DataMapper and a bunch of plugins. The problem is that DataMapper doesn&rsquo;t run on JRuby yet so it won&rsquo;t work.</p>
<p>Instead you should generate a core application:</p>
<p><code>merb-gen core app-name</code></p>
<p>This way you create a blank app with no dependencies. Then add what you need. <a href="https://wiki.merbivore.com/faqs/merb_components">Here is a list of dependencies</a> for a merb stack app and what they do.</p>
<h2 id="thanks">Thanks</h2>
<p>Finally I would like to thank the Ruby community from Japan. First because many people came to RubyConf all the way from Japan. I&rsquo;m personally sorry I couldn&rsquo;t meet you all. Thankfully some people started a new chat channel on lingr: <a href="https://www.lingr.com/room/merb.jp">merb.jp</a> and I could meet more Japanese Merbists. Because the Merb team thinks is important that Merb is being used outside of the English speaking world and because we need feedback from other countries, I decided to make the trip to RubyKaigi 2009. Hopefully we will be able to have some talks about Merb :)Â  I would also want to thank Erubis author, Makoto Kuwata for translating the<a href="https://merbist.com/2008/11/09/merb-1-0-released"> Merb 1.0 annoucement post</a> in Japanese.</p>
<h2 id="finally">Finally</h2>
<p>Here are the slides from my talk at <a href="https://orug.org">Orug</a>, a quick presentation of Merb. I&rsquo;ll be at <a href="https://qconsf.com/sf2008/conference/">QCon</a> next week to talk about <a href="https://qconsf.com/sf2008/tracks/show_track.jsp?trackOID=172">Ruby for the Enterprise</a>. Thanks <a href="https://railsenvy.com/">Gregg</a> for thinking of me!</p>
<p><a href="https://www.slideshare.net/mattetti/merb-presentation-at-orug-presentation?type=powerpoint">Merb presentation at ORUG</a>Â </p>
<p>View SlideShare <a href="https://www.slideshare.net/mattetti/merb-presentation-at-orug-presentation?type=powerpoint">presentation</a></p>
]]></content>
		</item>
		
		<item>
			<title>merb 1 0 released</title>
			<link>https://matt.aimonetti.net/posts/2008-11-merb-1-0-released/</link>
			<pubDate>Sun, 09 Nov 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-11-merb-1-0-released/</guid>
			<description>Japanese translation
On November 7, Yehuda Katz gave a talk at RubyConf and made 3 major announcements:
  Engine Yard to offer Merb support
  m|a agile to offer professional training
  Merb 1.0 released!
  The first announcement is pretty substantial. Engine Yard has been financially supporting Merb by letting some of their staff work on Merb, fly them to different conferences and sponsoring events like Merb Camp.</description>
			<content type="html"><![CDATA[<p><a href="https://flickr.com/photos/absolutely_loverly/120000855/"><img src="https://farm1.static.flickr.com/47/120000855_c7d39781f7_m.jpg" alt=""></a></p>
<p><a href="https://d.hatena.ne.jp/kwatch/20081112/1226448192"><img src="https://merbist.com/wp-content/uploads/2008/11/nihon-japan-48.png" alt=""></a>
<a href="https://d.hatena.ne.jp/kwatch/20081112/1226448192">Japanese translation</a></p>
<p>On November 7, <a href="https://yehudakatz.com/">Yehuda Katz</a> gave a talk at <a href="https://rubyconf.org">RubyConf</a> and made 3 major announcements:</p>
<ul>
<li>
<p><a href="https://engineyard.com">Engine Yard</a> to offer <a href="https://engineyard.com/merbsupport">Merb support</a></p>
</li>
<li>
<p><a href="https://ma-agile.com/">m|a agile</a> to offer <a href="https://ma-agile.com/training/">professional training</a></p>
</li>
<li>
<p><strong>Merb 1.0 released!</strong></p>
</li>
</ul>
<p>The first announcement is pretty substantial. <a href="https://engineyard.com">Engine Yard</a> has been financially supporting <a href="https://merbivore.com">Merb</a> by letting some of their staff work on Merb, fly them to different conferences and sponsoring events like <a href="https://merbcamp.com">Merb Camp</a>. Engine Yard didn&rsquo;t yet announce the price structure but <strong>having the option for enterprise level support for Merb is just awesome</strong>.</p>
<p><a href="https://railstips.org">John Nunemaker</a> made an interesting comment during RubyConf <a href="https://pivotallabs.com/">Pivotal</a> Party. Something special about Merb is that it was designed to fit the needs of an audience instead of trying to create a series of tools to build a specific type of website. Having Engine Yard help to finance Merb dev and offer support is very reassuring. It&rsquo;s something already done by many other OSS projects such as Ubuntu, MySQL etc&hellip;</p>
<p><a href="https://ma-agile.com/training"><img src="https://merbist.com/wp-content/uploads/2008/11/merb-training-small-238x300.gif" alt=""></a>The second announcement Yehuda made was about <a href="https://ma-agile.com/training/">Merb Training</a>. I&rsquo;m probably pretty biased since I am at the origin of this project. I know for a fact that a lot of people were waiting for 1.0 to get started with Merb. We are also working on getting more documentation out, and 3 books are coming up. Still, the best way to learn is to sit down with people who know Merb who can teach you the way its intended to be used.</p>
<p>Training will allow you to benefit a lot from being with other people who also share the same desire to <strong>master Ruby&rsquo;s most powerful and flexible web framework</strong>.</p>
<p>What&rsquo;s also really exciting is that <a href="https://yehudakatz.com">Yehuda Katz</a>, Merb&rsquo;s lead developer, agreed to be a tutor for the course. I can&rsquo;t imagine a better way to learn. Check <a href="https://ma-agile.com/training/">this page</a> for more information about the next training session or get in contact with me if you want to organize a training session for your company.</p>
<h3 id="finally-the-big-news-was-the-announcement-of-merb-10">Finally, the <strong>big news was the announcement of Merb 1.0</strong>!</h3>
<p>Merb 1.0 went through 5 release candidates and was finally marked as final. In the last few months, the Merb team worked hard to make things easier for people who want to get started in no time.</p>
<p>Let&rsquo;s quickly look at why Merb is awesome:</p>
<ul>
<li>
<p><strong>Merb is Modular</strong>. Merb is not a monolithic framework. You can pick and choose what you need. Create a 1 file app &ldquo;Ã  la Sinatra&rdquo; or a rich web app &ldquo;Ã  la Rails&rdquo;. Merb has many components. Only requires the ones you need and save precious resources. (Merb doesn&rsquo;t believe in 1 size fits all)</p>
</li>
<li>
<p><strong>Merb is agnostic</strong> (kinda). Because people have different needs and different believes, Merb won&rsquo;t force you to use one ORM or another. Same thing goes for the template engine or for the JavaScript library you want to use. ActiveRecord, DataMapper, Sequel, RelaxDb, Haml, Erb, Prototype, jQuery&hellip; choose which one you want and change whenever you want.</p>
</li>
<li>
<p><strong>Merb <em>can</em> be opinionated</strong>. Merb offers a default stack using DataMapper and jQuery, authentication, exceptions and caching setup for you. However, creating your own stack is dead easy. As a matter of fact, the guys at <a href="https://yellowpages.com">yellowpages.com</a> are using Merb and were talking about creating their own stack using Sequel.</p>
</li>
<li>
<p><strong>Merb let you reuse your code</strong>. Borrowed from <a href="https://www.djangoproject.com/">Django</a>, Merb has something called &ldquo;slices&rdquo;. Slices are mini apps you can run standalone or mounted within another app. A slice is a great way to write code you can reuse. Unlike plugins which extend the framework features, slices are a way to provide encapsulated content. (<a href="https://blog.davidchelimsky.net/">David Chelimsky,</a> RSpec&rsquo;s author and maintainer actually said that slices where his favorite feature in Merb 1.0)</p>
</li>
<li>
<p><strong>Merb has an API</strong>. You might be wondering why having an API is awesome. Well, the truth is that the Merb Team spent time marking methods public, which are guaranteed to not break until the next major release (any change to the public API will be well documented). There is also a plugin API meaning that plugin developers won&rsquo;t have to worry about upgrades if they stick to the plugin API.</p>
</li>
<li>
<p><strong>Merb is fast.</strong> Even though Ruby the language isn&rsquo;t really fast and contrary to popular opinion, Ruby for the web is one of the fastest solutions out there. (Even Rails is <a href="https://www.slideshare.net/wycats/merb-camp-keynote-presentation">way faster than all the mainstream PHP frameworks</a>) And that&rsquo;s what Merb is proving by being one of the fastest web framework available on the market. <a href="https://railsenvy.com/">Jason Seifer</a> will be interested to know that Merb isn&rsquo;t scared to scale ;) As a matter of fact, Merb is going to scale even better in the next few months as we are planning to integrate <a href="https://swiftiply.swiftcore.org/index.html">Swiftiply</a> and do some totally awesome stuff to spawn/reap workers based load. (more about that in few weeks).</p>
</li>
<li>
<p><strong>Matz likes Merb</strong>. Ruby&rsquo;s daddy, Yukihiro Matsumoto told us he likes the flexibility of Merb and the fact that the framework doesn&rsquo;t create a DSL on top of Ruby. He even told us that he&rsquo;s going to introduce his company to Merb! We were obviously very honored and for us, it validates months of work by dozens of contributors. Here is a transcript of Matz comments about Merb and the Ruby web world:</p>
</li>
</ul>
<p>[caption id=&ldquo;attachment_213&rdquo; align=&ldquo;alignleft&rdquo; width=&ldquo;125&rdquo; caption=&ldquo;Yukihiro Matsumoto aka Matz&rdquo;]<a href="https://ruby-lang.org"><img src="https://merbist.com/wp-content/uploads/2008/11/yukihiro_matsumoto_125px.jpg" alt="Yukihiro Matsumoto aka Matz"></a>[/caption]</p>
<blockquote>
<p>&ldquo;Everyone outside of the Ruby community understands that we only have 1 web application framework, named Rails, but it&rsquo;s not true in any sense. We have several post-Rails frameworks, which is very good, and I believe in diversity.</p>
</blockquote>
<p>Merb has a bright future for the people who are not satisfied by the fixed ways in Rails.Â  I think that Merb will give users more freedom in a Ruby-ish way of programming.</p>
<p>I&rsquo;m not really a web-guy, so i don&rsquo;t judge any of them [frameworks], but Rails does some kind of drastic change on the language itself like in Active Support.Â  But Ruby has its own culture and technological atmosphere in the language so that keeping that makes me feel easier.&rdquo;</p>
<ul>
<li>
<p><strong>Merb is memory friendly and therefore cheap</strong>. Merb is Open Source and free, but hosting an application costs money. Merb memory footprint is tiny compared to other solutions and that means that hosting will cost you less. (interesting when you think that EngineYard help developing Merb :p) Using <a href="https://www.rubyenterpriseedition.com/">Ruby Entreprise Edition</a>, you will even use less memory, meaning you save even more money ;) By the way, Matz told me this morning that the Ruby core team is working on their own solution for a better GC and it should be available soon. (Ruby 1.9.x)</p>
</li>
<li>
<p><strong>Merb source code is easy to read</strong>. Because <a href="https://github.com/wycats/merb/tree/master">Merb code</a> is modular and because Merb has a concept of an API, reading Merb&rsquo;s source code is pretty easy. On top of that, Merb itself uses RSpec making tests really easy to read and understand.Â  What&rsquo;s great when the source code is easy to read is that developers can quickly check the source code if they want to understand how things work. We also get better patches from contributors and we keep our code clean. We believe in the theory of the &ldquo;Broken Windows&rdquo; by James Q. Wilson and George L. Kelling:</p>
</li>
</ul>
<blockquote>
<p>&ldquo;Consider a building with a few broken windows. If the windows are not repaired, the tendency is for vandals to break a few more windows. Eventually, they may even break into the building, and if it&rsquo;s unoccupied, perhaps become squatters or light fires inside.</p>
</blockquote>
<p>Or consider a sidewalk. Some litter accumulates. Soon, more litter accumulates. Eventually, people even start leaving bags of trash from take-out restaurants there or breaking into cars.&rdquo;</p>
<p>I guess I could keep on going with other reasons why Merb is so awesome, but let&rsquo;s keep some for another post ;)</p>
<p>In conclusion, on behalf of the Merb core team, I&rsquo;d like to thank all the Merb contributors, Ezra Zygmuntowic (creator of Merb), Yehuda Katz (Merb lead developer), Matz (Ruby creator) and finally DHH &amp; the Rails core team. One more thing:</p>
<p><code>$ sudo gem install merb $ merb-gen app my-awesome-merb-app</code></p>
]]></content>
		</item>
		
		<item>
			<title>merb 10 rc5</title>
			<link>https://matt.aimonetti.net/posts/2008-11-merb-10-rc5/</link>
			<pubDate>Mon, 03 Nov 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-11-merb-10-rc5/</guid>
			<description>As you might have noticed, we&amp;rsquo;ve been pushing a lot of Release Candidates out the door. The reason is that we want to make sure 1.0 is really ready for showtime!
We are also getting a lot of bug reports that help us focusing on the main issues. Today RC5 was pushed to a RubyForge mirror close to you and here is a report from Yehuda Katz, Merb lead developer.</description>
			<content type="html"><![CDATA[<p>As you might have noticed, we&rsquo;ve been pushing a lot of Release Candidates out the door. The reason is that we want to make sure 1.0 is really ready for showtime!</p>
<p>We are also getting a lot of bug reports that help us focusing on the main issues. Today RC5 was pushed to a RubyForge mirror close to you and <a href="https://yehudakatz.com/2008/11/03/merb-rc5-final-rc/">here is a report from Yehuda Katz</a>, <a href="https://merbivore.com">Merb</a> lead developer.</p>
<p>This is the final RC before we ship 1.0 final at <a href="https://rubyconf.org/">RubyConf</a>. Here is a really quick rundown of the bugfixes and improvement added to this release:</p>
<ul>
<li>
<p><a href="https://github.com/brynary/webrat/tree/master">Webrat</a> integration out of the box. (<a href="https://github.com/wycats/merb/tree/master/merb-core/spec/public/webrat/webrat_spec.rb">see example</a>)</p>
</li>
<li>
<p>Improved Merb bundling</p>
</li>
<li>
<p>spec view helpers now use <a href="https://tenderlovemaking.com/2008/10/30/nokogiri-is-released/">nokogiri</a> (with rexml as fallback )</p>
</li>
<li>
<p>new <a href="https://github.com/wycats/merb/tree/master/merb-core/spec/public/test/view_matchers_spec.rb#L16-36">have_selector</a> spec helper using CSS3 compatible selector.</p>
</li>
<li>
<p>The entire Merb spec suite now runs correctly on JRuby &amp; Windows.</p>
</li>
<li>
<p>Once again improved jRuby support.</p>
</li>
</ul>
<p>In other news, we setup a nightly gem server so people who want to be on Edge don&rsquo;t have to deal with git and we call also test gem releases before pushing to RubyForge. More about that coming up during RubyConf.</p>
<p>Talking about <a href="https://rubyconf.org/">RubyConf</a>,Â  <a href="https://yehudakatz.com">Yehuda</a> and <a href="https://merbist.com/about/">I</a> will be in Orlando enjoying a good Ruby meetup. Come and chat with us if you are interested in starting using Merb, or if you have been using Merb. Also, please come and see us if you hate Merb and care tell us why. We&rsquo;re looking forward to meet you all.</p>
]]></content>
		</item>
		
		<item>
			<title>yet another rc release merb 10 rc3</title>
			<link>https://matt.aimonetti.net/posts/2008-10-yet-another-rc-release-merb-10-rc3/</link>
			<pubDate>Wed, 29 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-yet-another-rc-release-merb-10-rc3/</guid>
			<description>Yesterday, Yehuda Katz annouced Merb 1.0 RC3 released and today we re released the same version with a hotfix (some dependencies got broken).
Here is a quick sum up:
  improved the testing framework with full webrat integration.
  merb-action-args works with ParseTree 2.x and 3.x.
  improved merb-auth
  dependency â€œparse_treeâ€, :require_as =&amp;gt; â€œParseTreeâ€ { # do stuff after the gem is loaded }. You can also pass :immediate =&amp;gt; trueÂ Â (great to use gems from GitHub)</description>
			<content type="html"><![CDATA[<p>Yesterday, <a href="https://yehudakatz.com/2008/10/29/merb-10-rc3-released/">Yehuda Katz annouced Merb 1.0 RC3 released</a> and today we re released the same version with a hotfix (some dependencies got broken).</p>
<p>Here is a quick sum up:</p>
<ul>
<li>
<p>improved the testing framework with full <a href="https://github.com/brynary/webrat/tree/master">webrat</a> integration.</p>
</li>
<li>
<p>merb-action-args works with ParseTree 2.x and 3.x.</p>
</li>
<li>
<p>improved merb-auth</p>
</li>
<li>
<p>dependency â€œparse_treeâ€, :require_as =&gt; â€œParseTreeâ€ { # do stuff after the gem is loaded }. You can also pass :immediate =&gt; trueÂ Â  (great to use gems from GitHub)</p>
</li>
<li>
<p>improved Windows and JRuby support</p>
</li>
</ul>
<p>1.0 final is expected to be released during <a href="https://rubyconf.org/">Ruby Conf</a>.<a href="https://merbcamp.com/video"><img src="https://merbcamp.com/images/logo.gif" alt=""></a></p>
<p>On a different note, the <a href="https://merbcamp.com">MerbCamp</a> videos were <a href="https://merbcamp.com/video">released</a> today. Check out the videos <a href="https://merbcamp.com/video">there</a>.</p>
<p>A big thank to <a href="https://mokolabs.com/">Patrick Crowley</a> and <a href="https://notch8.com/">Rob Kaufman</a> for taking care of the encoding videos.</p>
]]></content>
		</item>
		
		<item>
			<title>will_paginate and merb</title>
			<link>https://matt.aimonetti.net/posts/2008-10-will_paginate-and-merb/</link>
			<pubDate>Mon, 27 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-will_paginate-and-merb/</guid>
			<description>Mislav &amp;amp; Pjhyett&amp;rsquo;s will_paginate plugin has been a reference in the Rails world for a little while now. The need for Pagination is arguable, but that&amp;rsquo;s not the point of this post.

There are few existing pagination solutions for Merb, but people moving from Rails and porting a Rails app will be happy to hear that will_paginate is now Merb compatible (DataMapper and ActiveRecord supported).
Mislav worked hard making sure that his next release will be framework agnostic and hopes to support both Rails 2.</description>
			<content type="html"><![CDATA[<p><a href="https://github.com/mislav">Mislav</a> &amp; <a href="https://github.com/pjhyett">Pjhyett</a>&rsquo;s <a href="https://github.com/mislav/will_paginate">will_paginate plugin</a> has been a reference in the Rails world for a little while now. The need for Pagination is arguable, but that&rsquo;s not the point of this post.</p>
<p><a href="https://flickr.com/photos/jacqueline-w/56107224/"><img src="https://farm1.static.flickr.com/26/56107224_a4120dd201_m.jpg" alt=""></a></p>
<p>There are few existing pagination solutions for Merb, but people moving from Rails and porting a Rails app will be happy to hear that will_paginate is now Merb compatible (DataMapper and ActiveRecord supported).</p>
<p>Mislav worked hard making sure that his next release will be framework agnostic and hopes to support both Rails 2.2 and Merb 1.0. You can see where is at by checking on his <a href="https://github.com/mislav/will_paginate/tree/agnostic">agnostic branch</a>.</p>
<p>I did some work over the week end to make sure I could use will_paginate in one of my project. You can see my work <a href="https://github.com/mattetti/will_paginate/tree/merb">there</a>. I also built a <a href="https://github.com/mattetti/will_paginate/tree/merb/tmp_release">temp gem</a> for you to test WP with Merb until mislav releases the final version of the gem (especially if you are lazy and don&rsquo;t want to deal with git).</p>
]]></content>
		</item>
		
		<item>
			<title>merb 10 rc2</title>
			<link>https://matt.aimonetti.net/posts/2008-10-merb-10-rc2/</link>
			<pubDate>Tue, 21 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-merb-10-rc2/</guid>
			<description>As I&amp;rsquo;m writing this post, Merb 1.0 RC2 (v0.9.10) is being propagated through all the RubyForge mirrors.
$ sudo gem install merb will install/update Merb Stack. Merb stack is a meta-gem/package installing all the gems you need to get started (including merb-core, merb-more, datamapper and sqlite3 driver)
The main focus for this release was to fix bugs and make the stack Windows compatible. We didn&amp;rsquo;t get any major bugs in RC1 but fixed a lot of small annoyances and problems with generated resources.</description>
			<content type="html"><![CDATA[<p>As I&rsquo;m writing this post, Merb 1.0 RC2 (v0.9.10) is being propagated through all the <a href="https://rubyforge.org/">RubyForge</a> mirrors.</p>
<p><code>$ sudo gem install merb</code> will install/update Merb Stack. Merb stack is a meta-gem/package installing all the gems you need to get started (including merb-core, merb-more, <a href="https://datamapper.org">datamapper</a> and sqlite3 driver)</p>
<p><a href="https://merbist.com/wp-content/uploads/2008/10/windows_logo.jpg"><img src="https://merbist.com/wp-content/uploads/2008/10/windows_logo-300x218.jpg" alt=""></a>The main focus for this release was to fix bugs and make the stack Windows compatible. We didn&rsquo;t get any major bugs in RC1 but fixed a lot of small annoyances and problems with generated resources. We also made sure Merb itself would work properly with Windows (not using incompatible signals etc..) and we spent some time getting the Data Object sqlite3 drivers compiled on Windows.</p>
<p>You don&rsquo;t need to use <a href="https://datamapper.org">DataMapper</a> with Merb, ActiveRecord works fine. However since we are packaging DM with the Merb Stack, we wanted to make sure Windows people would be able to get started easily.</p>
<p>A quick note, for <a href="https://en.wikipedia.org/wiki/Purgatory">Windows</a> users, like for <a href="https://rubyonrails.org/">Rails</a>, you need to have <a href="https://www.sqlite.org">sqlite3</a> installed. Simply dump the <a href="https://www.sqlite.org/sqlitedll-3_6_4.zip">sqlite3 dll</a> in your system32 folder or your ruby bin folder to get started.</p>
<p>Unfortunately DataMapper isn&rsquo;t running on <a href="https://jruby.codehaus.org/">JRuby</a> yet. We hope to be able to use the DM guys to get their drivers ported over before 1.0 final but can&rsquo;t promise anything yet.</p>
<h2 id="whats-next">What&rsquo;s next?</h2>
<p>Merb 1.0 final by the end of the Month if everything goes as scheduled.</p>
<h2 id="thanks">Thanks</h2>
<p><img src="https://farm1.static.flickr.com/38/81989263_34a2583c75_m.jpg" alt="">A big thank to all the contributors who added valuable information to <a href="https://wiki.merbivore.com/">Merb wiki</a>. <a href="https://jackndempsey.blogspot.com">Jack Dempsey</a> also wrote a <a href="https://jackndempsey.blogspot.com/2008/10/creating-new-merb-stack-with-templater.html">nice blog post</a> about creating your own stack, you might want to check it out if you are not into DataMapper or want something different.</p>
<p>Finally, Merb got a lot of press coverage lately:</p>
<ul>
<li>
<p><a href="https://rubyurl.com/SYmw">SDtimes.com</a></p>
</li>
<li>
<p><a href="https://www.internetnews.com/dev-news/article.php/3778386/Do+Ruby+on+Rails+Developers+Need+Merb.htm">internetnews.com</a></p>
</li>
<li>
<p><a href="https://tinyurl.com/5w3pb9">smarteguru.com</a></p>
</li>
<li>
<p><a href="https://railsenvy.com">RailsEnvy.com</a></p>
</li>
<li>
<p><a href="https://www.infoq.com/news/2008/10/merb-1-0">InfoQ.com</a></p>
</li>
<li>
<p><a href="https://rubyurl.com/EGfQ">gartner.com</a></p>
</li>
</ul>
<p>and many much more.Â  Follow <a href="https://twitter.com/merbivore">@merbivore</a> to get daily news.</p>
<p>To finish this post, here is a video of <a href="https://brainspl.at/">Ezra Zygmuntowicz</a> who recently presented Merb at Google.</p>
]]></content>
		</item>
		
		<item>
			<title>preparing merb 10 rc2</title>
			<link>https://matt.aimonetti.net/posts/2008-10-preparing-merb-10-rc2/</link>
			<pubDate>Thu, 16 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-preparing-merb-10-rc2/</guid>
			<description>1.0RC1 was released less than a week ago and we are already planning to release RC2 next week or so.
Thanks to all the contributors who reported RC1 bugs and submitted patches. RC2 should iron out most of the small bugs and annoyances encountered.
[caption id=&amp;quot;&amp;quot; align=&amp;ldquo;alignright&amp;rdquo; width=&amp;ldquo;180&amp;rdquo; caption=&amp;ldquo;Rosemary has a very old reputation for improving memory.&amp;quot;][/caption]
However, RC2 top priority is to get Merb and DataMapper properly working on Windows.</description>
			<content type="html"><![CDATA[<p><a href="https://merbist.com/2008/10/13/merb-10-rc1/">1.0RC1 was released</a> less than a week ago and we are already planning to release RC2 next week or so.</p>
<p>Thanks to all the contributors who reported RC1 bugs and submitted patches. RC2 should iron out most of the small bugs and annoyances encountered.</p>
<p>[caption id=&quot;&quot; align=&ldquo;alignright&rdquo; width=&ldquo;180&rdquo; caption=&ldquo;Rosemary has a very old reputation for improving memory.&quot;]<a href="https://flickr.com/photos/geishaboy500/133095382/"><img src="https://farm1.static.flickr.com/56/133095382_75068e1a32_m.jpg" alt="Rosemary has a very old reputation for improving memory."></a>[/caption]</p>
<p>However, RC2 top priority is to get Merb and DataMapper properly working on Windows. Some members of the .net community offered their help to compile windows native DM drivers. Supporting Windows is not an easy task but we think it is a critical thing to do.</p>
<p>We are also discussing setting up a nightly gem server so people could test Merb edge without having to use git etc..Â  It&rsquo;s also a great way for us to test gem dependencies before an official release. The only problem with nightly gems is that you need to have a way to track what version is being installed or what version a user reporting a bug is using. We do have some ideas, but please feel free to add a comment with your suggestions.</p>
<p>On a different note, the <a href="https://wiki.merbivore.com/">new wiki</a> is growing nicely, but we do need more content, as you are experimenting with Merb 1.0RC, please think about sharing your knowledge with others by using the <a href="https://wiki.merbivore.com/">wiki</a>.</p>
<p>Finally, people on Edge are reporting issue with gems not loading properly. The problem is that you have generated an app with hardcoded dependencies (check your config/dependencies.rb file). Your app won&rsquo;t load newer gems and therefore migth crash. Make sure to define the proper dependencies. We are working onÂ  documenting this behavior and making the error message clearer.</p>
]]></content>
		</item>
		
		<item>
			<title>replying to some tweets</title>
			<link>https://matt.aimonetti.net/posts/2008-10-replying-to-some-tweets/</link>
			<pubDate>Thu, 16 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-replying-to-some-tweets/</guid>
			<description>I&amp;rsquo;ve been following what people say on twitter about Merb.
I simply used twitter search engine.
Because I only have a private twitter account I can&amp;rsquo;t reply to everyone.
 freels: I keep expecting merb to have a view helper for random things&amp;hellip;
 @freels, feel free to let us know about the view helpers you miss. We might not be able to port them all to merb-helpers but we can certainly work something out and maybe come up with more gems so you don&amp;rsquo;t have to repeat yourself.</description>
			<content type="html"><![CDATA[<p>I&rsquo;ve been following what people say on <a href="https://twitter.com">twitter</a> about <a href="https://search.twitter.com/search?q=merb">Merb</a>.</p>
<p>I simply used <a href="https://search.twitter.com/search?q=merb">twitter search engine</a>.</p>
<p>Because I only have a private twitter account I can&rsquo;t reply to everyone.</p>
<blockquote>
<p>freels: <a href="https://twitter.com/freels/statuses/962887213">I keep expecting merb to have a view helper for random things&hellip;</a></p>
</blockquote>
<p>@freels, feel free to let us know about the view helpers you miss. We might not be able to port them all to merb-helpers but we can certainly work something out and maybe come up with more gems so you don&rsquo;t have to repeat yourself.</p>
<blockquote>
</blockquote>
<blockquote>
<p><a href="https://twitter.com/nmeans">nmeans</a>: <a href="https://twitter.com/nmeans/statuses/961422604">Ye gods!  The <strong>Merb</strong> meta-gem installs an insane number of packages!</a></p>
</blockquote>
<p>@nmeans, as you mentioned it, Merb is a meta-gem installing merb-core, merb-more, dm-core, do_sqlite3, dm-timestamps, dm-types, dm-aggregates, dm-migrations, dm-validations, dm-sweatshop + their dependencies. The reason behind this choice is that merb gem is just a package. You can just use merb-core if you wish and that&rsquo;s one gem. Installing many gems isn&rsquo;t a problem, we could even hide it so you don&rsquo;t see it, but you really care how many gems are installed?</p>
<blockquote>
</blockquote>
<blockquote>
<p><a href="https://twitter.com/cfisk">cfisk</a>: <a href="https://twitter.com/cfisk/statuses/960200526">Oops, now I&rsquo;ve gotten sucked into reading <strong>Merb</strong> stuff on Slideshare.  The whole day got burned up lateralizing over links.</a></p>
</blockquote>
<p>@cfisk we have videos from MerbCamp coming up next week. The wiki is also growing fast and 2 books are being written.</p>
<blockquote>
</blockquote>
<blockquote>
<p><a href="https://twitter.com/sco">sco</a>: <a href="https://twitter.com/sco/statuses/960137912">we relaunched packrat today, completely re-written in <strong>merb</strong>. hit a few snags, but still managed to push out 5 million requests in half a day.</a></p>
</blockquote>
<p>@sco wow, I didn&rsquo;t know <a href="https://www.facebook.com/apps/application.php?id=2431403991">PackRat</a> was built on Merb now. Please let us know if you need help.</p>
<blockquote>
</blockquote>
<blockquote>
<p><a href="https://twitter.com/brycethornton">brycethornton</a>: Installing the <strong>merb</strong> gem a while back has led to an unimaginable number of related gems.  Wow.  I probably only need a few of these.</p>
</blockquote>
<p>@brycethornton you don&rsquo;t have to install the merb gem itself. The Merb gem is a metagem, feel free to only install gems you want. You can generate lighter app by doing merb-gen core app_name or merb-gen flat app_name or a sinatra like app by doing merb-gen very-flat app_name</p>
<blockquote>
</blockquote>
<blockquote>
<p><a href="https://twitter.com/downtowncartel">downtowncartel</a>: <a href="https://twitter.com/downtowncartel/statuses/959906735">We are really excited and proud of the relase of <strong>Merb</strong> 1.0 RC1. Great work to all of those who made it possible.</a></p>
</blockquote>
<p>Thanks, wait for 1.0 and you will enjoy it even more :) Thanks to Ben for merb-cache btw!</p>
<blockquote>
</blockquote>
<blockquote>
<p><a href="https://twitter.com/rafaelbandeira3">rafaelbandeira3</a>: <strong>Merb</strong> is like the factory of inovative concepts and concepts usage&hellip; ruby is nicier now, although ugly, bad formatted and noisy&hellip;</p>
</blockquote>
<p>I&rsquo;m confused, it&rsquo;s probably the first time I hear Ruby us ugly, bad formatted and noisy. I wonder if @rafaelbandeira3 didn&rsquo;t get confused and looked at a different framework/language. Ruby has its pros/cons but ugly/bad formatted and noisy??? really???</p>
<blockquote>
</blockquote>
<blockquote>
<p><a href="https://twitter.com/rarepleasures">rarepleasures</a>: <a href="https://twitter.com/rarepleasures/statuses/959580219"><strong>Merb</strong> is a big fat FAIL</a></p>
</blockquote>
<p>@rarepleasures Ok, this is not really fair because you then <a href="https://twitter.com/rarepleasures/statuses/960240532">twittered</a> and blamed mongrel. Two things about this tweet tho, mongrel is buggy and you probably should be use thin (or fix Mongrel).Â  If you do think Merb is a big fat FAIL or if there is something you don&rsquo;t like about Merb, please let us know so we can try to fix it.</p>
]]></content>
		</item>
		
		<item>
			<title>merb 10 rc1</title>
			<link>https://matt.aimonetti.net/posts/2008-10-merb-10-rc1/</link>
			<pubDate>Mon, 13 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-merb-10-rc1/</guid>
			<description>Few hours ago we finally pushed Merb 1.0 RC1 to rubyforge.
RC stands for Release Candidate. And we will need your help to make a rock solid 1.0 final.
For the occasion, we switched to our new wiki.
Installing Merb stack is now dead easy: $ sudo gem install merb
Here is a tutorial to get you started with Merb in few minutes.
Unfortunately we already found few bugs related to the generated resources.</description>
			<content type="html"><![CDATA[<p><a href="https://www.flickr.com/photos/81335564@N00/2934025410">
</a><a href="https://www.flickr.com/photos/81335564@N00/2050355003"><img src="https://static.flickr.com/2359/2050355003_8b5db33ff0_t.jpg" alt="floor 1"></a> <a href="https://www.flickr.com/photos/49968232@N00/85990435"><img src="https://static.flickr.com/6/85990435_4549262c9b_t.jpg" alt="full stop"></a><a href="https://www.flickr.com/photos/49968232@N00/2114628079"><img src="https://static.flickr.com/2113/2114628079_b00a6ed156_t.jpg" alt="zero"> </a></p>
<p><a href="https://www.flickr.com/photos/92745470@N00/2777560349"><img src="https://static.flickr.com/3122/2777560349_49ea878a74_t.jpg" alt="R"></a> <a href="https://www.flickr.com/photos/92709190@N00/2351343799"><img src="https://static.flickr.com/3151/2351343799_8c399edc55_t.jpg" alt="C is for church"></a> <a href="https://www.flickr.com/photos/49968232@N00/2115385302"><img src="https://static.flickr.com/2267/2115385302_b021bebee7_t.jpg" alt="1"></a></p>
<p>Few hours ago we finally pushed Merb 1.0 RC1 to <a href="https://rubyforge.org/projects/merb">rubyforge</a>.</p>
<p>RC stands for <a href="https://en.wikipedia.org/wiki/Software_release_life_cycle#Release_candidate">Release Candidate</a>. And we will need your help to make a rock solid 1.0 final.</p>
<p>For the occasion, we switched to our <a href="https://wiki.merbivore.com/">new wiki</a>.</p>
<p>Installing Merb stack is now dead easy:
<code>$ sudo gem install merb</code></p>
<p><a href="https://wiki.merbivore.com/howto/gettingstarted/firstapp">Here is a tutorial</a> to get you started with Merb in few minutes.</p>
<p>Unfortunately we already found few bugs related to the generated resources.</p>
<p>Known bugs are documented <a href="https://wiki.merbivore.com/merb_1.0_rc1_known_bugs">here</a> with fixes. We&rsquo;ll keep track of the RC1 known bugs until we release RC2. Fortunately, so far we didn&rsquo;t find any major bugs but hey&hellip; try to prove us wrong as hard as you can. As mentioned earlier we want a rock solid 1.0.</p>
<p>As you have probably we are trying to be as transparent as possible and we know that we aren&rsquo;t perfect and we make mistakes. Our goal is honestly not to build an ego but to provide you with awesome tools.</p>
<p>Talking about awesome talks, as we are waiting for the videos from <a href="https://merbcamp.com">MerbCamp</a>, I&rsquo;d encourage you to check on Yehuda Kats' keynote&rsquo;s slides and get an idea of Merb&rsquo;s future.</p>
<p><a href="https://www.slideshare.net/wycats/merb-camp-keynote-presentation?type=powerpoint">Merb Camp Keynote</a></p>
<p>Other MerbCamp talks: <a href="https://slideshare.net/tag/merbcamp">merbcamp slides</a>)</p>
<p>What I learned from this keynote that you should always double check what people tell you. All the Ruby frameworks tested including Rails are way faster than PHP frameworks such as <a href="https://cakephp.org/">CakePHP</a>, <a href="https://www.symfony-project.org/">Symfony</a>, <a href="https://codeigniter.com/">Code Igniter</a>.</p>
<p>Fibonacci type benchmarks seem to only test a certain aspect of a language, turns out that if you are interested in a fast and flexible web framwork, ruby and especially Merb are seriously the way to go.</p>
<p>UPDATE: looks like someone posted a <a href="https://blip.tv/file/1354733">bootleg version of the keynote </a>;)</p>
]]></content>
		</item>
		
		<item>
			<title>merb 10 rc1 delayed by few hours hopefully</title>
			<link>https://matt.aimonetti.net/posts/2008-10-merb-10-rc1-delayed-by-few-hours-hopefully/</link>
			<pubDate>Mon, 13 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-merb-10-rc1-delayed-by-few-hours-hopefully/</guid>
			<description>Tonight, the core team members present during MerbCamp got together at my place to prepare and release 1.0 RC1.
The problem is that we spent more time joking, laughing and arguing about the new git system that we didn&amp;rsquo;t feel right about pushing a release at 4am :(
The git -core and -more repos got merged into a centralized repo. You will notice an active branch and that&amp;rsquo;s where most of the hacking is going on.</description>
			<content type="html"><![CDATA[<p><a href="https://flickr.com/photos/aihibed/1410398234/"><img src="https://farm2.static.flickr.com/1235/1410398234_c341320704.jpg?v=0" alt=""></a> Tonight, the core team members present during MerbCamp got together at my place to prepare and release 1.0 RC1.</p>
<p>The problem is that we spent more time joking, laughing and arguing about the new git system that we didn&rsquo;t feel right about pushing a release at 4am :(</p>
<p>The git -core and -more repos got merged into a centralized <a href="https://github.com/wycats/merb">repo</a>. You will notice an active branch and that&rsquo;s where most of the hacking is going on.</p>
<p>Each core team member has a fork of the project and we all create a new branch everytime we work on a new feature or bug fix. Branch comments get squashed into 1 comment, merged back into the local rebased active branch. The commit get then pulled by Yehuda or pushed to his active branch. Yehuda then make sure all the commits are clean and merge them back in master (edge).</p>
<p>Releases will have their own branches and tags.</p>
<p>People wanting to hack on a specific feature should really fork a core member branch. Usually a core member involved with what you want to work on. Of course that&rsquo;s optional but whatever you do, if you want to hack on Merb, please use the active branch and not master.</p>
<p>It&rsquo;s 4:15am, and we are still cleaning up the last few quirks before the release, I know we planned on a releasing today but I guess it&rsquo;s better to wait few more hours and to get a solid release.</p>
<p>Sorry about that :(</p>
]]></content>
		</item>
		
		<item>
			<title>end of merbcamp day 1</title>
			<link>https://matt.aimonetti.net/posts/2008-10-end-of-merbcamp-day-1/</link>
			<pubDate>Sat, 11 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-end-of-merbcamp-day-1/</guid>
			<description>[caption id=&amp;quot;&amp;quot; align=&amp;ldquo;alignright&amp;rdquo; width=&amp;ldquo;240&amp;rdquo; caption=&amp;ldquo;MerbCamp registration by Andy Delcambre&amp;rdquo;][/caption]
Day 1 went very fast.
The day started with a Keynote from  Ezra Zygmuntowicz, author of Merb. Ezra covered the past and present of Merb and introduced Nanite: self assembling cluster of ruby processes.
 (Carl Lerche) introduced the awesomeness brought to you by the new router.
 Daniel Neighman introduced Merb&amp;rsquo;s slice system and Merb Authentication plugin.
 Yehuda Kats had 2 talks today, one of how to test your app the Merb Way.</description>
			<content type="html"><![CDATA[<p>[caption id=&quot;&quot; align=&ldquo;alignright&rdquo; width=&ldquo;240&rdquo; caption=&ldquo;MerbCamp registration by Andy Delcambre&rdquo;]<a href="https://flickr.com/photos/adelcambre/2932032491/"><img src="https://farm4.static.flickr.com/3147/2932032491_ccdd7fba0e_m.jpg" alt="MerbCamp registration by Andy Delcambre"></a>[/caption]</p>
<p>Day 1 went very fast.</p>
<p>The day started with a <a href="https://www.slideshare.net/ezmobius/merb-nanite-presentation?src=embed">Keynote</a> from <a href="https://brainspl.at/"><img src="https://merbcamp.com/images/speakers/24/ezra.jpg" alt="Ezra Zygmuntowicz"></a> <a href="https://brainspl.at/">Ezra Zygmuntowicz</a>, author of <a href="https://merbivore.com">Merb</a>. Ezra covered the past and present of Merb and introduced <a href="https://github.com/ezmobius/nanite/tree/master/README">Nanite: self assembling cluster of ruby processes.</a></p>
<p><a href="https://splendificent.com/"><img src="https://merbcamp.com/images/speakers/24/carl.jpg" alt="Carl Lerche"></a> (<a href="https://splendificent.com/">Carl Lerche) </a>introduced the awesomeness brought to you by the <a href="https://www.slideshare.net/carllerche/merb-pluming-the-router-presentation">new router.</a></p>
<p><a href="https://hassox.blogspot.com/"><img src="https://merbcamp.com/images/speakers/24/daniel.jpg" alt="Daniel Neighman"></a> <a href="https://hassox.blogspot.com/">Daniel Neighman</a> introduced Merb&rsquo;s <a href="https://www.slideshare.net/hassox/merb-slices-presentation">slice system</a> and <a href="https://www.slideshare.net/hassox/merb-auth-presentation">Merb Authentication</a> plugin.</p>
<p><a href="https://yehudakatz.com/"><img src="https://merbcamp.com/images/speakers/24/yehuda.jpg" alt="Yehuda Katz"></a> <a href="https://yehudakatz.com/">Yehuda Kats</a> had 2 talks today, one of how to test your app the Merb Way. Here is a quote which sumups the talk pretty well:Â &ldquo;If you have to refactor your tests to refactor your code then your tests do not prove your code actually works.&ldquo;Â  Yehuda also had a 2nd talk later on in the day where he talked about Javascript and why RJS sucks and should be replaced by proper JS (in prototype or jQuery or whatever).</p>
<p>[caption id=&rdquo;&rdquo; align=&ldquo;alignright&rdquo; width=&ldquo;160&rdquo; caption=&ldquo;Matt asking a question by Andy Delcambre&rdquo;]<a href="https://flickr.com/photos/adelcambre/2932035013/"><img src="https://farm4.static.flickr.com/3167/2932035013_715b5814ae_m.jpg" alt="Matt asking a question by Andy Delcambre"></a>[/caption]</p>
<p>There were some other awesome talks like the couchDb talk, the Sequel talk, getting up and running with Merb and obviously awesome DM.</p>
<p><a href="https://www.slideshare.net/mattetti/datamapper-in-20-min-presentation?type=powerpoint">DataMapper In 20 min</a></p>
<p>I have to say that it&rsquo;s probably one of the best conference I have being part of. I&rsquo;m certainly biased but I really enjoyed myself. Having a small group of motivated people makes a big difference. We had a great lunch all together, watch a 3xHD video stream during a break and headed to the beach for a sunset BBQ :)</p>
<p>Can&rsquo;t wait for tomorrow but I need to prep my slides and work test Merb before we release 1.0RC tomorrow.  By the way, we setup a new wiki during Merb Sprint and we will need your help to provide &ldquo;osim&rdquo; content before 1.0 final.</p>
<p>p.s: someone<a href="https://rubypond.com/articles/2008/10/11/merbcamp---notes-from-the-edge/"> live blogged</a> most of the talks.</p>
]]></content>
		</item>
		
		<item>
			<title>merbcamp just started</title>
			<link>https://matt.aimonetti.net/posts/2008-10-merbcamp-just-started/</link>
			<pubDate>Sat, 11 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-merbcamp-just-started/</guid>
			<description>A real quick post to let people know that MerbCamp just started. If you couldn&amp;rsquo;t make it to San Diego, you can follow live. (For FREE)
[caption id=&amp;quot;&amp;quot; align=&amp;ldquo;alignright&amp;rdquo; width=&amp;ldquo;160&amp;rdquo; caption=&amp;ldquo;Ezra during his Keynote&amp;rdquo;][/caption]
Merb 1.0 RC should be released tomorrow with a new option to get started with a Merb stack including Merb Core, Merb More, DataMapper Core with sqlite3 adapter and few plugins from DM more.
You will still be able to only use the modules you want, add/remove components, build a Sinatra like app etc.</description>
			<content type="html"><![CDATA[<p>A real quick post to let people know that <a href="https://merbcamp.com">MerbCamp</a> just started. If you couldn&rsquo;t make it to San Diego, you can follow <a href="https://merbcamp.com/webcast">live</a>. (For FREE)</p>
<p>[caption id=&quot;&quot; align=&ldquo;alignright&rdquo; width=&ldquo;160&rdquo; caption=&ldquo;Ezra during his Keynote&rdquo;]<a href="https://flickr.com/search/?q=merbcamp&amp;ss=2&amp;ct=6"><img src="https://farm4.static.flickr.com/3277/2932034431_48a54ab62d_m.jpg" alt="Ezra during his Keynote"></a>[/caption]</p>
<p>Merb 1.0 RC should be released tomorrow with a new option to get started with a Merb stack including Merb Core, Merb More, DataMapper Core with sqlite3 adapter and few plugins from DM more.</p>
<p>You will still be able to only use the modules you want, add/remove components, build a Sinatra like app etc.. The only difference is that if you wish to do so, we offer a packaged version of Merb that we guarantee working together. The exciting thing about the stack is that we included stuff most people will need such as builtin very flexible authentication, notification exceptions etc&hellip;</p>
<p>Watch the conf to learn more about the goodies in Merb 1.0</p>
<p>Go Merb!</p>
<p>UPDATE: <a href="https://fiveruns.com">FiveRuns</a> MerbCamp sponsor, just <a href="https://blog.fiveruns.com/2008/10/11/fiveruns-tuneup-for-merb">released TuneUp</a> for Merb! Awesome!</p>
]]></content>
		</item>
		
		<item>
			<title>merb sprint day 2 stand up</title>
			<link>https://matt.aimonetti.net/posts/2008-10-merb-sprint-day-2-stand-up/</link>
			<pubDate>Thu, 09 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-merb-sprint-day-2-stand-up/</guid>
			<description>We just finished the first stand-up. A stand-up according to the scrum/xp practices is just an occastion to say what you did yesterday, what you are going to do today and any problems you encountered if any.
The stand-up followed a sprint review &amp;amp; retrospective we had last night.
The amount of work done in few hours is just amazing, Carl is almost done setting up a Continuous Integration system, Merb Stack is almost live, Merb Auth is refactored, inline documentation is moving fast and the up and running team is squashing bugs, optimizing processes and writing documentation.</description>
			<content type="html"><![CDATA[<p>We just finished the first stand-up. A stand-up according to the scrum/xp practices is just an occastion to say what you did yesterday, what you are going to do today and any problems you encountered if any.</p>
<p>The stand-up followed a sprint review &amp; retrospective we had last night.</p>
<p>The amount of work done in few hours is just amazing, Carl is almost done setting up a Continuous Integration system, Merb Stack is almost live, Merb Auth is refactored, inline documentation is moving fast and the up and running team is squashing bugs, optimizing processes and writing documentation.</p>
]]></content>
		</item>
		
		<item>
			<title>merb pre sprint meeting</title>
			<link>https://matt.aimonetti.net/posts/2008-10-merb-pre-sprint-meeting/</link>
			<pubDate>Tue, 07 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-merb-pre-sprint-meeting/</guid>
			<description>Some of Los SeÃ±ores del Merb, AKA the Merb &amp;ldquo;core team&amp;rdquo; met tonight in a secret location in San Diego, CA. Obviously, we had to meet in a Mexican restaurant and enjoy Tuesday Fish Taco night special ;)
While not everybody could make the trip, Yehuda, Andy, Daniel, Carl and myself met to plan the very first Merb Sprint.
Unfortunately, Michael and Fabien could not make it, but will work remotely during the next few days.</description>
			<content type="html"><![CDATA[<p><img src="https://farm4.static.flickr.com/3171/2424765496_43008cbd29.jpg?v=0" alt="">Some of Los SeÃ±ores del Merb, AKA the Merb &ldquo;core team&rdquo; met tonight in a secret location in San Diego, CA. Obviously, we had to meet in a Mexican restaurant and enjoy <a href="https://www.rubios.com/">Tuesday Fish Taco night special</a> ;)</p>
<p>While not everybody could make the trip, Yehuda, Andy, Daniel, Carl and myself met to plan the very first Merb Sprint.</p>
<p>Unfortunately, Michael and Fabien could not make it, but will work remotely during the next few days.</p>
<p>Yehuda sent attendees the following explanations about the Scrum:</p>
<blockquote>
<p>&ldquo;Tomorrow morning, the Merb core team will be setting up around 9am in the sprint room, setting up the git infrastructure for the event, and setting up CI and a wiki for the sprint.</p>
</blockquote>
<p>We&rsquo;re going to be breaking up into a few teams: an inline documentation team, a getting-up-and-running team, and merb-stack team. Each team will be led by a core team member, who will be responsible for pushing the work of the team up to the main merb repository, which will be manned by me throughout the sprint.&rdquo;</p>
<p>The sprint will focus on 4 main points:</p>
<ul>
<li>
<p>inline documentation</p>
</li>
<li>
<p>getting-up-and-running</p>
</li>
<li>
<p>Merb-stack</p>
</li>
<li>
<p>reported tickets (lead remotely by Michael)</p>
</li>
</ul>
<p>This is a really exciting time and things are looking good.</p>
<p>For those wondering about Merb-Stack&hellip; well just wait few days and you&rsquo;ll see ;)</p>
]]></content>
		</item>
		
		<item>
			<title>merb edge update oct 6th 2008</title>
			<link>https://matt.aimonetti.net/posts/2008-10-merb-edge-update-oct-6th-2008/</link>
			<pubDate>Mon, 06 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-merb-edge-update-oct-6th-2008/</guid>
			<description>Mode changes to init.rb, user updating to a newer version or Merb will need to add
c[:log_file] = Merb.root / &amp;ldquo;log&amp;rdquo; / &amp;ldquo;development.log&amp;rdquo;
  to their init.rb file or config/environments/development.rb for instance. (Newly generated apps are already setup properly)
  We made some changes to the way Rake files work. Merb-core doesn&amp;rsquo;t require the rspec tasks anymore so Test::Unit see annoying rspec tasks. Once again people upgrading to the latest version of Merb need to make a small change and add:</description>
			<content type="html"><![CDATA[<ul>
<li>
<p>Mode changes to init.rb, user updating to a newer version or Merb will need to add</p>
<p>c[:log_file] = Merb.root / &ldquo;log&rdquo; / &ldquo;development.log&rdquo;</p>
</li>
</ul>
<p>to their init.rb file or config/environments/development.rb for instance. (Newly generated apps are already setup properly)</p>
<ul>
<li>
<p>We made some changes to the way Rake files work. Merb-core doesn&rsquo;t require the rspec tasks anymore so Test::Unit see annoying rspec tasks. Once again people upgrading to the latest version of Merb need to make a small change and add:</p>
<p>require &lsquo;spec/rake/spectask&rsquo;</p>
</li>
</ul>
<p>to their rake file. Newly generated applications using RSpec already have that line setup.</p>
<ul>
<li>
<p>In the last few days, <a href="https://yehudakatz.com/">Yehuda</a> merged in his branch with the new &ldquo;request-testing feature&rdquo;. This is a new way of testing your apps. It makes testing a real request going through a controller and being rendered in a view, something quite easy, Merb interegration tests here we go!. <a href="https://gist.github.com/14910">Check here</a> to see a example of what you can now do. Rails + Rspec users might be surprised by this choice, and I&rsquo;ve scheduled to interview Yehuda so he can explain why and when you want to use this way of testing your app. (Don&rsquo;t miss his talk at <a href="https://merbcamp.com">MerbCamp</a> next week)</p>
</li>
<li>
<p>Talking about full stack testing, Merb is almost entirely full stack tested. What does that mean? Take a look at <a href="https://github.com/wycats/merb-more/tree/master/merb-helpers">merb-helpers</a> specs in <a href="https://github.com/wycats/merb-more">merb-more</a>. Form builders are tested through a real app available from spec/fixture/app, the views are rendered in the specs and the results are check to make sure they will work for you in your real application. Avoiding using too many mocks and stubs helped us really test things in the contet of a real app and avoid a great amount of ghost bugs. Specs might run a bit slower but we believe Merb now has better testing suite than before. More coming up about this topic.</p>
</li>
<li>
<p>Ohh and we released Merb 0.9.8 &ldquo;Time Machine&rdquo;, last release before 1.0RC1 ;)</p>
</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>few changes in merb edge</title>
			<link>https://matt.aimonetti.net/posts/2008-10-few-changes-in-merb-edge/</link>
			<pubDate>Sun, 05 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-few-changes-in-merb-edge/</guid>
			<description>I thought I should share few changes that my affect your apps if you want to upgrade to Edge.
  merb_helpers which was previously in merb-plugins now moved to merb-more and got renamed merb-helpers.Â What that means for you is that you probably want to install merb-helpers and change the reference in your init.rb from dependencies &amp;ldquo;merb_helpers&amp;rdquo; to dependencies &amp;ldquo;merb-helpers&amp;rdquo;
  People started reporting problems with templates not being reloaded in dev mode etc.</description>
			<content type="html"><![CDATA[<p>I thought I should share few changes that my affect your apps if you want to upgrade to Edge.</p>
<ul>
<li>
<p>merb_helpers which was previously in <a href="https://github.com/wycats/merb-plugins/tree/master">merb-plugins</a> now moved to <a href="https://github.com/wycats/merb-more/">merb-more</a> and got renamed <a href="https://github.com/wycats/merb-more/tree/master/merb-helpers">merb-helpers</a>.Â  What that means for you is that you probably want to install merb-helpers and change the reference in your init.rb from dependencies &ldquo;merb_helpers&rdquo; to dependencies &ldquo;merb-helpers&rdquo;</p>
</li>
<li>
<p>People started reporting problems with templates not being reloaded in dev mode etc.. The reason is that we made some changes to the config/environments/development.rb file few weeks ago and people did not notice. <a href="https://github.com/wycats/merb-more/tree/master/merb-gen/lib/generators/templates/application/merb/config/environments/development.rb">Here is</a> the new generated <a href="https://github.com/wycats/merb-more/tree/master/merb-gen/lib/generators/templates/application/merb/config/environments/development.rb">development.rb</a> file. Note the following interesting change:</p>
<p>c[:reload_templates] = true</p>
</li>
</ul>
<p>You will need to update this setting if you want Merb to auto reload your templates.</p>
<p>Also, if you didn&rsquo;t read it yet, go check on Yehuda&rsquo;s explanation of <a href="https://yehudakatz.com/2008/10/03/merb-master-process/">Merb new master process</a>.</p>
<p>Finally, I have a bit of a bad news. We were hoping to release Merb 1.0 final during <a href="https://merbcamp.com">MerbCamp</a> next week end. Unfortunately it looks like we will only release 1.0RC.</p>
<p>The reason behind this choice is simple, we have been adding a lot of features, fixed a lot of bugs and stabilized the API. However we need more feedback from users to be confident enough to release a final 1.0 release.</p>
]]></content>
		</item>
		
		<item>
			<title>get on merb edge pre 10</title>
			<link>https://matt.aimonetti.net/posts/2008-10-get-on-merb-edge-pre-10/</link>
			<pubDate>Sat, 04 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-get-on-merb-edge-pre-10/</guid>
			<description>Merb 1.0 is almost ready to be pushed out and you might be impatient to start playing with some of the goodies not yet available in the latest stable release. Before getting started, you should know that not everything has been ironed out yet so don&amp;rsquo;t expect to have a fully stable Edge.
The easiest way to get started requires that you have git installed as well as a gem called thor.</description>
			<content type="html"><![CDATA[<p>Merb 1.0 is almost ready to be pushed out and you might be impatient to start playing with some of the goodies not yet available in the latest stable release. Before getting started, you should know that not everything has been ironed out yet so don&rsquo;t expect to have a fully stable Edge.</p>
<p>The easiest way to get started requires that you have <a href="https://git.or.cz/">git</a> installed as well as a gem called <a href="https://github.com/wycats/thor/tree/master">thor</a>.</p>
<p>I let you take care of installing git on your machine, Ruby dev without git became quite challenging since <a href="https://github.com">GitHub</a> started ruling the Ruby OSS world.</p>
<pre><code>&lt;code class=&quot;shell&quot;&gt;sudo gem install wycats-thor -s https://gems.github.com&lt;/code&gt;
</code></pre>
<p>[caption id=&quot;&quot; align=&ldquo;alignright&rdquo; width=&ldquo;240&rdquo; caption=&ldquo;Hops, used primarily as a flavoring and stability agent in beer, and also in other beverages and in herbal medicine.&quot;]<a href="https://flickr.com/photos/fturmog/1438235253/"><img src="https://farm2.static.flickr.com/1418/1438235253_5b10c24732_m.jpg" alt="Hops, used primarily as a flavoring and stability agent in beer, and also in other beverages and in herbal medicine."></a>[/caption]</p>
<p><a href="https://yehudakatz.com/2008/05/12/by-thors-hammer/">Thor</a> is a sort if mix between rake, <a href="https://errtheblog.com/posts/60-sake-bomb">sake</a> with a better argument parser and based on Ruby classes.</p>
<p>Thor on its own won&rsquo;t be very helpful, we need some thor tasks.</p>
<p>Create a folder where you want to store Merb&rsquo;s source code and cd in it.</p>
<p>Once there download the latest merb thor tasks:</p>
<pre><code>&lt;code class=&quot;shell&quot;&gt;curl -L https://merbivore.com/merb.thor &gt; merb.thor
&lt;/code&gt;
</code></pre>
<p>You can now look at the available task by doing</p>
<pre><code>&lt;code class=&quot;shell&quot;&gt;thor -T&lt;/code&gt;
</code></pre>
<p>At this point you be overwhelmed by the multitude of options, we are working on making things a be nicer for 1.0. But anyways, let&rsquo;s get started:</p>
<pre><code>&lt;code class=&quot;shell&quot;&gt;sudo thor merb:edge --install&lt;/code&gt;
</code></pre>
<p>The command above will install extlib, merb-core and merb-more from git HEAD. You now have the latest version of Merb&rsquo;s libs installed locally as gems.</p>
<p>You might also want to install Merb extra plugins, if that&rsquo;s the case do:</p>
<pre><code>&lt;code class=&quot;shell&quot;&gt; sudo thor merb:edge:plugins --install&lt;/code&gt;
</code></pre>
<p>If you decided to use DataMapper instead of ActiveRecord or Sequel, you will also need to install the gems you might need:</p>
<p>Install data_objects and an adapter: (replace mysql by the adapter you want to install)</p>
<pre><code>&lt;code class=&quot;shell&quot;&gt; sudo thor merb:edge:do mysql --install&lt;/code&gt;
</code></pre>
<p>Install DataMapper core from Git HEAD</p>
<pre><code>&lt;code class=&quot;shell&quot;&gt; sudo thor merb:edge:dm_core --install&lt;/code&gt;
</code></pre>
<p>Install DataMapper more from Git HEAD</p>
<pre><code>&lt;code class=&quot;shell&quot;&gt; sudo thor merb:edge:dm_more --install&lt;/code&gt;
</code></pre>
<p>You should be all setup by now.</p>
<p>**
Next time you want to update, just come back to the same folder and do the same thing. Hopefully by then we will have a 1 task solution and will offer a merb-stack version of our gems to let you install everything at once with all setup done.**</p>
<p>p.s: this post is dedicated <a href="https://derekneighbors.com/">Derek Neighbors</a> ;)</p>
]]></content>
		</item>
		
		<item>
			<title>exception handling in merb</title>
			<link>https://matt.aimonetti.net/posts/2008-10-exception-handling-in-merb/</link>
			<pubDate>Wed, 01 Oct 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-10-exception-handling-in-merb/</guid>
			<description>[caption id=&amp;quot;&amp;quot; align=&amp;ldquo;alignright&amp;rdquo; width=&amp;ldquo;224&amp;rdquo; caption=&amp;ldquo;Mint was originally used as a medicinal herb to treat stomach ache and chest pains. (Something developers eating too much pizza know a bit too well)&amp;quot;][/caption]
Paul Sadauskas aka Rando posted a very interesting article showing how he handles exceptions in his JSON webservices built on top of Merb.
  After discussing with NewBamboo guys it was decided to move their merb_exceptions plugin to merb-plugins.</description>
			<content type="html"><![CDATA[<ul>
<li></li>
</ul>
<p>[caption id=&quot;&quot; align=&ldquo;alignright&rdquo; width=&ldquo;224&rdquo; caption=&ldquo;Mint was originally used as a medicinal herb to treat stomach ache and chest pains. (Something developers eating too much pizza know a bit too well)&quot;]<a href="https://flickr.com/photos/kali-ma/124218131/"><img src="https://farm1.static.flickr.com/42/124218131_5c16c08798_m.jpg" alt="Mint was originally used as a medicinal herb to treat stomach ache and chest pains. (Something developers eating too much pizza know a bit too well)"></a>[/caption]</p>
<p><a href="https://theamazingrando.com/blog/">Paul Sadauskas aka Rando</a> posted a <a href="https://www.theamazingrando.com/blog/?p=46">very interesting article</a> showing how he handles exceptions in his JSON webservices built on top of Merb.</p>
<ul>
<li>
<p>After discussing with <a href="https://newbamboo.co.uk/">NewBamboo guys</a> it was decided to move their <a href="https://github.com/wycats/merb-plugins/tree/master/merb_exceptions">merb_exceptions plugin</a> to <a href="https://github.com/wycats/merb-plugins/tree/master">merb-plugins</a>. The notifier currently supports two interfaces, Email Alerts and Web Hooks. Emails are formatted as plain text and sent using your Merb environment&rsquo;s mail settings. Web hooks as sent as post requests. Railists moving over to this side of the fence will not have to develop their own <a href="https://github.com/rails/exception_notification/tree/master">exception_notification plugin</a> anymore. Note the NewBamboo team will keep on maintaining the plugin, we just moved it the set of official plugins.</p>
</li>
<li>
<p>We got some reports of problems killing workers when using DataMapper and HEAD from yesterday, this is a known problem which should be fixed in the next few days at the latest. (use <code>merb -K all</code> to kill your workers instead of ctrl+c)</p>
</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>problems with urls in merb head</title>
			<link>https://matt.aimonetti.net/posts/2008-09-problems-with-urls-in-merb-head/</link>
			<pubDate>Tue, 30 Sep 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-09-problems-with-urls-in-merb-head/</guid>
			<description>I actually run into a small problem when updated an older Merb app. Here was how my router looked like:
Merb::Router.prepare do |r| r.resources :channels do |channels| channels.resources :shows do |shows| shows.resources :episodes end end end  But after updating to the latest version of Merb, I got links looking like:
https://localhost:4000/channels/#&amp;lt;Channel:0x27b7300&amp;gt;/shows  The first thing to do is to read Carl&amp;rsquo;s wiki about the latest Router changes.
Carl explains that things got cleaned up in the router code and my routes should now look like:</description>
			<content type="html"><![CDATA[<p>I actually run into a small problem when updated an older Merb app. Here was how my router looked like:</p>
<pre><code>Merb::Router.prepare do |r|
  r.resources :channels do |channels|
    channels.resources :shows do |shows|
      shows.resources :episodes
    end
  end
end
</code></pre>
<p>But after updating to the latest version of Merb, I got links looking like:</p>
<pre><code>https://localhost:4000/channels/#&lt;Channel:0x27b7300&gt;/shows
</code></pre>
<p>The first thing to do is to read <a href="https://github.com/carllerche/merb-core-enterprise-edition/wikis/whats-new-with-the-router">Carl&rsquo;s wiki about the latest Router changes</a>.</p>
<p>Carl explains that things got cleaned up in the router code and my routes should now look like:</p>
<pre><code>Merb::Router.prepare do |r|
  r.resources :channels do
    resources :shows do |shows|
      resources :episodes
    end
  end
end
</code></pre>
<p>However that won&rsquo;t be enough..  You see my url used to look like that:</p>
<pre><code>url(:channel_shows, :channel_id =&gt; channel)
</code></pre>
<p>Now I can simplify it to:</p>
<pre><code>url(:channel_shows, channel)
</code></pre>
<p>That still won&rsquo;t fix the problem, since the real problem comes from the fact that I was on Merb HEAD but not DataMapper HEAD. Updating DM clears things up. That&rsquo;s the price to pay to be on HEAD ;)</p>
<p>FYI the problem comes from the fact that DM doesn&rsquo;t add a to_params method to its objects. Rails users might recognize that method used to convert an object into a string to create a route, something not really ORM agnostic and frowned upon by the DM/Merb teams.</p>
<p>Merb lets you specify the param to use for your routes using the identify method. Read <a href="https://github.com/carllerche/merb-core-enterprise-edition/wikis/whats-new-with-the-router">Carl&rsquo;s wiki page </a>for more cool stuff and see how to create some cool stuff like url slugs etc..</p>
<p>Note that even if you are using ActiveRecord, you&rsquo;ll need to update merb_activerecord as the new identify rules were updated in the ORM plugins.</p>
]]></content>
		</item>
		
		<item>
			<title>write your own custom datamapper adapter</title>
			<link>https://matt.aimonetti.net/posts/2008-09-write-your-own-custom-datamapper-adapter/</link>
			<pubDate>Mon, 29 Sep 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-09-write-your-own-custom-datamapper-adapter/</guid>
			<description>If you read this blog, you probably know that Merb&amp;rsquo;s best ORM friend is DataMapper.
[caption id=&amp;quot;&amp;quot; align=&amp;ldquo;alignleft&amp;rdquo; width=&amp;ldquo;240&amp;rdquo; caption=&amp;ldquo;compounds in basil oil have potent antioxidant and is used for supplementary treatment of stress&amp;rdquo;][/caption]
Merb works very well with ActiveRecord and Sequel but most of the Merbivores get excited about DataMapper.
DataMapper has a lot of cool stuff going for it. I&amp;rsquo;m planning on writingi few articles about what I particularily like with DM and some of the misconceptions.</description>
			<content type="html"><![CDATA[<p>If you read this blog, you probably know that <a href="https://merbivore.com">Merb</a>&rsquo;s best <a href="https://en.wikipedia.org/wiki/Object-relational_mapping">ORM</a> friend is <a href="https://datamapper.org/">DataMapper</a>.</p>
<p>[caption id=&quot;&quot; align=&ldquo;alignleft&rdquo; width=&ldquo;240&rdquo; caption=&ldquo;compounds in basil oil have potent antioxidant and is used for supplementary treatment of stress&rdquo;]<a href="https://flickr.com/photos/darn/190457943/"><img src="https://farm1.static.flickr.com/55/190457943_8b93fda9e6_m.jpg" alt="compounds in basil oil have potent antioxidant and is used for supplementary treatment of stress"></a>[/caption]</p>
<p>Merb works very well with ActiveRecord and Sequel but most of the Merbivores get excited about <a href="https://datamapper.org/">DataMapper</a>.</p>
<p>DataMapper has a lot of cool stuff going for it. I&rsquo;m planning on writingi few articles about what I particularily like with DM and some of the misconceptions.</p>
<p>I&rsquo;m going to give a talk about DataMapper during <a href="https://merbcamp.com">MerbCamp</a> and something I want to cover is the fact that you can write DM adapters for virtually anything. From an adapter for couchdb (available in dm-more) to an <a href="https://github.com/wycats/dm-adapters/tree/master/salesforce">adapter for SalesForce API</a>. That&rsquo;s the kind of stuff that gets me excited, a bit like what <a href="https://ambition.rubyforge.org/">Ambition</a> does but built-in in DM.</p>
<p>So, I decided to take some advise from <a href="https://yehudakatz.com/">Yehuda</a> and dkubb and wrote my own adapter for <a href="https://video.google.com">Google Video</a>. I had just finished a <a href="https://github.com/mattetti/gvideo">gem to retrieve google videos</a> for a given google user and thought it would be a perfect exercise to mix a <a href="https://en.wikipedia.org/wiki/Screen_scraping">http-scraper</a> with a DM adapter.</p>
<p>Based on the advise I received, I started by defining the API I want to use:</p>
<p>I matched the API calls to the underlying methods I would need to make. I then modified my original gem to support conditional calls.</p>
<p>Once that was done I implemented the required methods for my models to support the Model.first and Model.all calls with conditions.</p>
<p>A custom adapter inherits from <a href="https://github.com/sam/dm-core/tree/master/lib/dm-core/adapters/abstract_adapter.rb">AbstractAdapter</a> and can define the default adapter methods:</p>
<pre><code>&lt;div id=&quot;LC9&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC10&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NotImplementedError&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC11&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC13&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read_many&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC14&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NotImplementedError&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC15&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC17&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC18&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NotImplementedError&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC19&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC21&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC22&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NotImplementedError&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC23&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC25&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC26&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NotImplementedError&lt;/span&gt;&lt;/div&gt;
&lt;div id=&quot;LC27&quot; class=&quot;line&quot;&gt;Â Â Â Â Â Â &lt;span class=&quot;k&quot;&gt;end
&lt;/span&gt;&lt;/div&gt;
</code></pre>
<p>Since my adapter only needs to read data, I just had to implement #read_one and #read_many. I implemented a #read private method accessed by #read_one and #read_many as you can see <a href="https://github.com/mattetti/dm-gvideo-adapter/tree/master/lib/dm-gvideo-adapter.rb#L29-60">here</a>.</p>
<p>Because DM offers a clean and consistent API, things were pretty easy and you can check the <a href="https://github.com/mattetti/dm-gvideo-adapter/tree/master/spec/dm-gvideo-adapter_spec.rb">specs</a> to have a better understanding of how things are expected to work.</p>
<p>As you can see with less than 80LOC, I implemented an adapter that I can use and reuse cleanly in my apps. And on top of that, the adapter uses a standard API known by everyone using DM.</p>
<p><strong>Even though, this adapter has a very limited scope, I hope this example will inspire you and at your turn, will write some more cool adapters to share with the rest of us.</strong></p>
<h2 id="update">UPDATE:</h2>
<p>Sam Smoot, also known as Mr DataMapper made a very good comment. I should explain a bit more how you create a collection of objects to return when a user does a .all or .first call.</p>
<p>The whole collection creation is a bit strange at first.</p>
<p>In my read method, &ldquo;set&rdquo; is a DataMapper::Collection instance that is passed by the #read_one or #read_many method.</p>
<p>The collection needs to be loaded with an array of ordered params.</p>
<p>For instance in this case, to create a Video collection I need to load the collection with an ordered array of params like docid, title etc..Â  However, some params might be lazy loaded and in some instance, the query might be in the form of Video.all(:fields =&gt; :title)</p>
<p>To figure out what fields/params we need, I used:</p>
<pre><code>&lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fields
&lt;/span&gt;
</code></pre>
<p>Which retrieves the required fields. Once you have the fields you need to return the structured data and that&rsquo;s when I used the #result_values method which basically loop through the fields and retrieves the data by sending the param as a method to the result:</p>
<pre><code>&lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;repository_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
</code></pre>
<p>The values once retrieved get loaded, but here is a trick I took from wycat&rsquo;s saleforce API:</p>
<pre><code>&lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))
&lt;/span&gt;
</code></pre>
<p>This snippet is quite simple if we set arr as true, that means we want to return an array so we will keep on looping (used by read_more when we want to return an array of objects). Otherwise we use the break operator which will stop the loop but also return a value. (yes, Ruby is awesome). By returning a single object we do exactly what&rsquo;s expected and don&rsquo;t have to call #first on a returned array. Pretty slick</p>
]]></content>
		</item>
		
		<item>
			<title>quick preview of the work done pre 10</title>
			<link>https://matt.aimonetti.net/posts/2008-09-quick-preview-of-the-work-done-pre-10/</link>
			<pubDate>Fri, 26 Sep 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-09-quick-preview-of-the-work-done-pre-10/</guid>
			<description>Yesterday I spyed on wycats aka Yehuda Katz while he&amp;rsquo;s working on cleaning things up for 1.0 which will be released during MerbCamp Oct 11-12.
Here is the screenshot of how you would see ugly backtraces originating from Merb&amp;rsquo;s core:
[caption id=&amp;ldquo;attachment_83&amp;rdquo; align=&amp;ldquo;aligncenter&amp;rdquo; width=&amp;ldquo;150&amp;rdquo; caption=&amp;ldquo;old backtraces&amp;rdquo;][/caption]
Note: Did you notice that wycats is using Ruby Enterprise Edition? Merb 0.9.8 has been modified to really take advantage of REE!
That&amp;rsquo;s a lot of noise just to tell you that you used an invalid argument</description>
			<content type="html"><![CDATA[<p>Yesterday I spyed on <a href="https://yehudakatz.com/">wycats aka Yehuda Katz</a> while he&rsquo;s working on cleaning things up for 1.0 which will be released during <a href="https://merbcamp.com">MerbCamp</a> Oct 11-12.</p>
<p>Here is the screenshot of how you would see ugly backtraces originating from Merb&rsquo;s core:</p>
<p>[caption id=&ldquo;attachment_83&rdquo; align=&ldquo;aligncenter&rdquo; width=&ldquo;150&rdquo; caption=&ldquo;old backtraces&rdquo;]<a href="https://merbist.com/wp-content/uploads/2008/09/backtraces_before.jpg"><img src="https://merbist.com/wp-content/uploads/2008/09/backtraces_before-150x150.jpg" alt="old backtraces"></a>[/caption]</p>
<p>Note: Did you notice that wycats is using <a href="https://www.rubyenterpriseedition.com/">Ruby Enterprise Edition</a>? Merb 0.9.8 has been modified to really take advantage of REE!</p>
<p>That&rsquo;s a lot of noise just to tell you that you used an invalid argument</p>
<p>Well, part of the prep work for Merb 1.0 is to clean up this things to make development work easier and nicer. Here is how the same error will look like in 1.0</p>
<p>[caption id=&ldquo;attachment_85&rdquo; align=&ldquo;aligncenter&rdquo; width=&ldquo;150&rdquo; caption=&ldquo;new backtraces&rdquo;]<a href="https://merbist.com/wp-content/uploads/2008/09/backtraces-after.jpg"><img src="https://merbist.com/wp-content/uploads/2008/09/backtraces-after-150x150.jpg" alt="new backtraces"></a>[/caption]</p>
<p>As you can see, it&rsquo;s way more elegant and less confusing. You can still see the full trace by using the &ndash;verbose argument.</p>
]]></content>
		</item>
		
		<item>
			<title>merbist scrapbook sept 25</title>
			<link>https://matt.aimonetti.net/posts/2008-09-merbist-scrapbook-sept-25/</link>
			<pubDate>Thu, 25 Sep 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-09-merbist-scrapbook-sept-25/</guid>
			<description>[caption id=&amp;quot;&amp;quot; align=&amp;ldquo;alignright&amp;rdquo; width=&amp;ldquo;182&amp;rdquo; caption=&amp;ldquo;Fennel, one of the primary ingredients of absinthe helps developers&#39; creativity.&amp;quot;][/caption]
  Good news regarding Merb slices: the new router allows you to mount a slice directly as: /the-slice-action (previously it had to be /the-slice/something)
  On IRC, Nagash came up with an interesing snippet allowing you to easily serve static views (like Django&amp;rsquo;s generic views) (Merb::Template.template_for is PRIVATE so use it at your own risk) The Core team is investigating simpler/cleaner ways of achieving the same result and a built-in solution should be available in Merb 1.</description>
			<content type="html"><![CDATA[<p>[caption id=&quot;&quot; align=&ldquo;alignright&rdquo; width=&ldquo;182&rdquo; caption=&ldquo;Fennel, one of the primary ingredients of absinthe helps developers' creativity.&quot;]<a href="https://www.flickr.com/photos/marty_2007/2818914854/"><img src="https://farm4.static.flickr.com/3220/2818914854_1a1f01b3a3_m.jpg" alt="Fennel, one of the primary ingredients of absinthe helps developers creativity."></a>[/caption]</p>
<ul>
<li>
<p><a href="https://merbunity.com/news/42">Good news</a> regarding Merb slices: the new router allows you to mount a slice directly as: /the-slice-action (previously it had to be /the-slice/something)</p>
</li>
<li>
<p>On IRC, Nagash came up with an <a href="https://gist.github.com/12755">interesing snippet</a> allowing you to easily serve static views (like Django&rsquo;s generic views) (Merb::Template.template_for is PRIVATE so use it at your own risk) The Core team is investigating simpler/cleaner ways of achieving the same result and a built-in solution should be available in Merb 1.1</p>
</li>
<li>
<p>Merb 0.9.8 will be optimized for <a href="https://www.rubyenterpriseedition.com/">Ruby Enterprise Edition</a> and will be supporting a <a href="https://github.com/fabien/minigems/tree/master">new way</a> of handling gems without wasting so much memory. (more news coming up soon)</p>
</li>
<li>
<p>Merb 0.9.8 has a new efficient way of dealing with clusters (more news coming soon)</p>
</li>
<li>
<p><a href="https://merbunity.com/tutorials/15">Merb&rsquo;s new caching system</a> will make it to 1.0</p>
</li>
<li>
<p>Merb is going into a feature freeze and the team will focus solely on bug fixes and making the Merb experience more pleasant.</p>
</li>
<li>
<p>A turn key deployment solution is planned for Merb 1.x (deployment recipes plugin)</p>
</li>
<li>
<p><a href="https://datamapper.org/">DataMapper</a> <a href="https://gist.github.com/10735">benchmarks show it&rsquo;s now way faster</a> than <a href="https://ar.rubyonrails.com/">ActiveRecord</a> (on average) Benchmark scripts available in the dm-core repo.</p>
</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>news from the front line sept 24 2008</title>
			<link>https://matt.aimonetti.net/posts/2008-09-news-from-the-front-line-sept-24-2008/</link>
			<pubDate>Wed, 24 Sep 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-09-news-from-the-front-line-sept-24-2008/</guid>
			<description>Dear Merbivores/Merbists/Merbians,
It&amp;rsquo;s hard to believe that in less that 20 days, Merb 1.0 will be released! We are all really happy to to be almost there but we have to be honest and admit that we are also under pressure.
We are all dreaming of a post 1.0 world but in the meantime we have to focus on last minutes bugs and optimization.

During the last week or so, we made a lot of progress, the API is now &amp;ldquo;almost&amp;rdquo; frozen and General Katz is focusing on making sure everything will be fine for D Day.</description>
			<content type="html"><![CDATA[<p>Dear Merbivores/Merbists/Merbians,</p>
<p>It&rsquo;s hard to believe that in <a href="https://merbcamp.com">less that 20 days</a>, Merb 1.0 will be released! We are all really happy to to be almost there but we have to be honest and admit that we are also under pressure.</p>
<p>We are all dreaming of a post 1.0 world but in the meantime we have to focus on last minutes bugs and optimization.</p>
<p><a href="https://flickr.com/photos/16596714@N00/355242291/"><img src="https://farm1.static.flickr.com/128/355242291_40cf729cd9_m.jpg" alt=""></a></p>
<p>During the last week or so, we made a lot of progress, the API is now &ldquo;almost&rdquo; frozen and <a href="https://yehudakatz.com/">General Katz</a> is focusing on making sure everything will be fine for D Day.</p>
<p>That reminds me that Katz showed me something amazing yesterday! I shouldn&rsquo;t really talk about it but I&rsquo;m sure it will stay between us. He was been working on optimizing the general memory consumption and my testing app (real app) went from 120MB of Private Memory used, to 70MB (using 4 processes). I can&rsquo;t wait to use that on the field. I also hope my old Rails comrades will realize that running ~100Mb processes (x4) really isn&rsquo;t efficient and event dangerous for the free Ruby world!</p>
<p>I also heard rumors that the higher officers are now using a new strategic tool called <a href="https://www.pivotaltracker.com">https://www.pivotaltracker.com</a> which should help us streamline the process. We are still using <a href="https://merb.lighthouseapp.com">LightHouse</a> to track bugs and patches though. I&rsquo;m not sure if this new &ldquo;agile&rdquo; tool will help, but I thought the approach is pretty interesting. What do you think?</p>
<p><a href="https://flickr.com/photos/celtico/2556999427/"><img src="https://farm4.static.flickr.com/3138/2556999427_546c5004f6_m.jpg" alt=""></a></p>
<p>You probably also saw my early report on <a href="https://merbist.com/2008/09/23/deploying-a-bundled-merb-app-merb-097/">bundling Merb apps</a>, I&rsquo;m quite happy about the process. Do you think you will deploy bundled/frozen apps or just use the system-wide gems?</p>
<p><a href="https://farm4.static.flickr.com/3097/2884670329_15385e8516.jpg">
</a></p>
<p>Finally I hear a lot of talk about the <a href="https://github.com/carllerche/merb-core-enterprise-edition/wikis/whats-new-with-the-router">new Route</a>r that&rsquo;s available on <a href="https://github.com/wycats/merb-core/tree/master">Edge/HEAD</a>. Officer Lerch wrote a <a href="https://github.com/carllerche/merb-core-enterprise-edition/wikis/whats-new-with-the-router">nice wiki article</a> covering the changes, you might want to <a href="https://github.com/carllerche/merb-core-enterprise-edition/wikis/whats-new-with-the-router">read it</a>.</p>
<p>Ohh before I forget, some courageous privates went to <a href="https://github.com/wycats/merb-core/tree/master">HEAD</a> and use the 3rd party plugin called <a href="https://github.com/hassox/merb-auth/tree/master">merb-auth</a>. What they don&rsquo;t know is that they need to change their routes to use the slices with the new router. (the new router requires no block variable) Also, if they look at the merb-auth branches they will notice a new <a href="https://github.com/hassox/merb-auth/tree/mauth">mauth branch</a> which is the new version of merb-auth, even better, more flexible than the previous version.</p>
<p>I hope everything is well for you, say Hi! to our friends for me.</p>
<ul>
<li>Merbist</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>deploying a bundled merb app merb 097</title>
			<link>https://matt.aimonetti.net/posts/2008-09-deploying-a-bundled-merb-app-merb-097/</link>
			<pubDate>Tue, 23 Sep 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-09-deploying-a-bundled-merb-app-merb-097/</guid>
			<description>Since Merb 0.9.7 the Merb team decided to change the way you can bundle an app. Until 0.9.7 you would use the merb-freezer plugin which was supporting git submodules and gems. The only problem was that you still had to install merb-freezer on your server and it had to stay in sync with your app&amp;hellip; kinda lame :(
[caption id=&amp;quot;&amp;quot; align=&amp;ldquo;alignleft&amp;rdquo; width=&amp;ldquo;240&amp;rdquo; caption=&amp;ldquo;Ginger roots, great for deployment issues&amp;rdquo;][/caption]
Instead, after a lot of discussions, we decided to add this feature to merb-core and let you bundle all your dependencies in a bundled gem folder.</description>
			<content type="html"><![CDATA[<p>Since Merb 0.9.7 the Merb team decided to change the way you can bundle an app. Until 0.9.7 you would use the merb-freezer plugin which was supporting git submodules and gems. The only problem was that you still had to install merb-freezer on your server and it had to stay in sync with your app&hellip; kinda lame :(</p>
<p>[caption id=&quot;&quot; align=&ldquo;alignleft&rdquo; width=&ldquo;240&rdquo; caption=&ldquo;Ginger roots, great for deployment issues&rdquo;]<a href="https://flickr.com/photos/vieuxbandit/1987820964/"><img src="https://farm3.static.flickr.com/2373/1987820964_bc54df0d81_m.jpg" alt="Ginger"></a>[/caption]</p>
<p>Instead, after a lot of discussions, we decided to add this feature to merb-core and let you bundle all your dependencies in a bundled gem folder. No more support for git submodules as they are hard to keep track of and don&rsquo;t handle dependencies very well (not at all).</p>
<p>The new freezing strategy is very well described in <a href="https://merbunity.com/tutorials/18">this merbunity article</a>. However it doesn&rsquo;t really explain how to deploy a bundled app.</p>
<p>So let&rsquo;s imagine for a second that we bundle our app, generated the scripts needed to start merb/rake etc&hellip;</p>
<p>The key thing to do is to have a decent deployment recipe. Let&rsquo;s look at my cap recipe:</p>
<p>As you can see there are few key elements:</p>
<ul>
<li>
<p>recompile native gems for the web server</p>
</li>
<li>
<p>call bin/merb and not merb directly</p>
</li>
</ul>
<p>One thing you need to be aware of is that your bundled gems need to be up to date and play well alone. When you test your bundled app locally, you might endup loading system wide gems available which you don&rsquo;t have on your deployment server.</p>
<p>If when you deploy your app everything seems fine but you can&rsquo;t access your app, check that you are recompiling native gems during your deployment and make sure you have bundled all the deps you need and that they work well alone.</p>
<p>One more advise, if you can&rsquo;t figure out what&rsquo;s going, try ssh&rsquo;ing to your server, go to your current folder and try bin/merb -iÂ  to see what&rsquo;s going on.</p>
]]></content>
		</item>
		
		<item>
			<title>merbcamp 2008 sandiego</title>
			<link>https://matt.aimonetti.net/posts/2008-09-merbcamp-2008-sandiego/</link>
			<pubDate>Tue, 16 Sep 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-09-merbcamp-2008-sandiego/</guid>
			<description>That&amp;rsquo;s now finally official, MerbCamp 2008 registration are open! What an exciting time!
History To understand why I&amp;rsquo;m excited, we need to go back few months back. Merb was first released by Ezra has an alternative tool to handle file uploads. Merb came to reality because Ezra needed something fast, light and flexible to handle something that, let&amp;rsquo;s be frank about it, Rails had a hard time dealing with. Rails was king but was not as popular as now.</description>
			<content type="html"><![CDATA[<p><img src="https://merbivore.com/img/merbcamp_badge_200.gif" alt="merbcamp"></p>
<p>That&rsquo;s now finally <a href="https://www.reuters.com/article/pressRelease/idUS113181+09-Sep-2008+PRN20080909">official</a>, <a href="https://merbcamp.com">MerbCamp</a> 2008 <a href="https://merbcamp.com/#registration">registration</a> are open! What an exciting time!</p>
<h2 id="history">History</h2>
<p>To understand why I&rsquo;m excited, we need to go back few months back. Merb was first released by <a href="https://brainspl.at/">Ezra</a> has an alternative tool to handle file uploads. Merb came to reality because Ezra needed something fast, light and flexible to handle something that, let&rsquo;s be frank about it, Rails had a hard time dealing with. Rails was king but was not as popular as now. Merb started as a simple Mongrel handler, in other words an alternative for small, light limited actions. Most people started using Merb simply to handle uploads. But as few cool kids started using Merb, they thought, hey, this thing is super fast, maybe I can use it to build small standalone apps. After all, hardcore developers don&rsquo;t need &ldquo;cool ajax helpers&rdquo; and form builders to create a simple site. <a href="">Geoffrey Grosenback</a> aka topfunky even proudly used Merb to reduild his site!
That was just enough to convince me to start using Merb back at version 0.3.4.</p>
<p>I was an active Rails user and contributor. Having to use a bare bone Ruby web framework was quite refreshing however the lack of testing framework was a real show stopper :( (Being hooked up on RSpec by <a href="https://joshknowles.com">Josh Knowles</a> I ended up only writing a small portion of a Rails app with Merb 0.3.x (uploader backend).)</p>
<p>Quite quickly Merb&rsquo;s philosophy changed and switched. The Mongrel handler framework started dreaming of becoming an alternative to Rails. Merb took the best from Rails but targeted another audience: the Ruby hackers living on the edge.
Merb prides itself in being less opinionated than Rails(that can be argued tho), ORM agnostic (supporting ActiveRecord, Sequel and DataMapper), Javascript framework agnostic and truly modular. People like <a href="https://yehudakatz.com">Yehuda Katz</a>, <a href="https://merb.lighthouseapp.com/users/10354">Michael Klishin aka antares</a> got involved, as more contributors joined the effort, rules were enforced to make sure the framework would be as fast as possible and easy to extend without monkey patching. (ohh and fully tested using RSpec ;)</p>
<p><a href="https://engineyard.com">Engine Yard</a> decided to support the development effort and helped with Merb&rsquo;s major rewrite (0.9 versions). Today, Merb is divided in 3 repositories, merb-core, merb-more and merb-plugins. By letting developers only choose what they want to use and by following a principle of isolation with private/public APIs, I believe Merb is today the most flexible yet powerful Ruby framework available.
Furthermore, even though many people don&rsquo;t understand the purpose of rewriting a &ldquo;new Rails&rdquo; from scratch, the reality is that many progress made by the merb team were ported back to Rails and inspired others (DataMapper for instance)!</p>
<p>Anyway, this is not a sale&rsquo;s speech and I&rsquo;m not trying to convince you to use Merb. My point is that Merb is finally coming to a point where the public API is stable and where one would find most tools he needs to build production ready applications.
And, that&rsquo;s basically a long sum up explaining why I wanted to organize something special to celebrate the 1.0 release and to create more awareness around Merb&rsquo;s awesomeness!</p>
<h2 id="the-team-behind-merbcamp">The Team behind MerbCamp</h2>
<p>I started getting involved with the SDRuby community a couple of years ago. As I got to know more people I realized that many people lead by <a href="https://mokolabs.com">Patrick Crowley</a> (leader of SDRuby and one of the organizers of SD BarCamp) had the desire to organize a local Ruby conf/camp.</p>
<p>At the same time, while I was working daily with Merb and contributing back to Merb&rsquo;s code, many other SDRuby fellows were also getting really excited about Merb (<a href="https://notch8.com">Rob Kaufman</a>, <a href="https://">Ryan Felton</a> to mention a few).</p>
<p>Seeing the opportunity to host the very first Merb event in San Diego (host of RubyConf 2005!) I chatted with <a href="https://yehudakatz.com">yehuda</a> and the rest of the merb team. All the merb people were really excited, Leah Sibler from <a href="https://engineyard.com">Engine Yard</a> even offered her expertise to organize such an event (she&rsquo;s totally awesome at planning/running conferences).</p>
<p>However, setting up such an event isn&rsquo;t something one can do on his own. Before promising anything, I checked that Rubyists from San Diego would be interested and would help. In no time, I got a lot of people offering to help.</p>
<p>The key thing for me was to get someone with a good experience in organizing conferences. A person with resources and contacts. The only person I knew in San Diego who would be good enough to do that was <a href="https://mokolabs.com">Patrick Crowley</a>. We had a quick chat Patrick and I and it turned out that Patrick was very excited about organizing the very first MerbCamp in his town.
Patrick quickly got a team together who agreed on working on the project. We got back to the Merb team and sealed the deal.</p>
<p>Patrick even found the <a href="https://www.calit2.net/">awesome venue</a> that many other cities will envy us! He&rsquo;s been running the show, running here and there, making phone calls to make sure registration would open on time, setup the website etc&hellip;. Thanks Patrick!</p>
<h2 id="the-conf">The Conf</h2>
<p>MerbCamp will be an hybrid between a BarCamp, a conference and an unconference. When the organization team got together, we all agreed that what we like the most during conferences is networking. We certainly also enjoy some good talks and definitely enjoyed the hack-room during the last Rails Conf.  We therefore decided to organize a conf  <em>*we</em>* would love to go.</p>
<ul>
<li>
<p>1 scheduled track with &ldquo;official talks&rdquo; to make sure we have some serious content and to motivate people to signup ;)</p>
</li>
<li>
<p>BBQ at the beach, because we live in San Diego and we love that! (plus, big open meals are the best way to network)</p>
</li>
<li>
<p>BarCamp type impromptu talks</p>
</li>
<li>
<p>hack-rooms so people can work together</p>
</li>
<li>
<p>friendly and small conference (we limited the amount of participants to 200)</p>
</li>
</ul>
<p>To conclude, I hope the &ldquo;history&rdquo; of MerbCamp 08 wasn&rsquo;t too boring. People seem quite excited about this event, we even have guys in London who would get together to watch the talks via a webcam we are going to setup for them.
We hope to see you there, if not, we hope you&rsquo;ll organize your own conference and we will come have fun with you.</p>
]]></content>
		</item>
		
		<item>
			<title>db fixtures replacement solution step by step</title>
			<link>https://matt.aimonetti.net/posts/2008-09-db-fixtures-replacement-solution-step-by-step/</link>
			<pubDate>Sun, 07 Sep 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-09-db-fixtures-replacement-solution-step-by-step/</guid>
			<description>Like most people who started with Rails a while back, I first loved Rails fixtures and ended up hating them (slow, a pain to maintain etc&amp;hellip;).
I went through different experiments, trying different existing libs, writing my own solutions etc&amp;hellip; I wasn&amp;rsquo;t quite satisfied until I found factory_girl from thoughtbot.
You might not feel the need for a decent fixtures solution if you do a lot of mocking/stubbing, but I recently came back from my &amp;ldquo;mock everything you can outside of models&amp;rdquo; approach and I&amp;rsquo;m getting closer to the mock roles, not objects approach.</description>
			<content type="html"><![CDATA[<p>Like most people who started with Rails a while back, I first loved Rails fixtures and ended up hating them (slow, a pain to maintain etc&hellip;).</p>
<p>I went through different experiments, trying different existing libs, writing my own solutions etc&hellip; I wasn&rsquo;t quite satisfied until I found <a href="https://github.com/thoughtbot/factory_girl">factory_girl</a> from <a href="https://www.thoughtbot.com/">thoughtbot</a>.</p>
<p>You might not feel the need for a decent fixtures solution if you do a lot of mocking/stubbing, but I recently came back from my &ldquo;mock everything you can outside of models&rdquo; approach and I&rsquo;m getting closer to the <a href="https://snipr.com/3nwry">mock roles, not objects</a> approach. So, I&rsquo;m loosing my model/controller testing separation but I&rsquo;m gaining by not having to maintain &ldquo;dumb mocks&rdquo; which don&rsquo;t always represent the real API behind. I mean, how many times did I change a Model, messing up my app but all my specs were still passing. Anyway, that&rsquo;s a long discussion, which will be covered by <a href="https://yehudakatz.com/">wycats</a> during <a href="https://merbcamp.com">merbcamp</a></p>
<p>So here is a simple example of how I use <a href="https://github.com/thoughtbot/factory_girl">factory girl</a> in a Merb + DataMapper app. (you can do the same in a Rails app, there is <strong>nothing</strong> specific to Merb in factory_girl).</p>
<ul>
<li>
<p>I. create an empty app, set the ORM etc&hellip;</p>
</li>
<li>
<p>II. git pull and install factory_girl from <a href="https://github.com/thoughtbot/factory_girl/tree/master">https://github.com/thoughtbot/factory</a>_<a href="https://github.com/thoughtbot/factory_girl/tree/master">girl/tree/master</a>. Or install thoughtbot-factory_girl gem using <a href="https://gems.github.com">GitHub gem server</a>.</p>
</li>
<li>
<p><strong>III.</strong> create a spec/factories.rb file. (You might prefer to create a folder called spec/factories and add a factory per model)</p>
</li>
<li>
<p><strong>IV.</strong> modify spec_helper.rb and add the following</p>
<p>require &lsquo;factory_girl&rsquo;
require File.dirname(<strong>FILE</strong>) + &lsquo;/factories&rsquo;</p>
</li>
<li>
<p>V. write some specs against a Client model</p>
</li>
<li>
<p><strong>VI.</strong> Create the Model</p>
</li>
<li>
<p><strong>VII.</strong> create a factory</p>
</li>
<li></li>
</ul>
<p><strong>IIX.</strong> run your specs</p>
<p><img src="https://img.skitch.com/20080907-tf8yy6fi82b23t78stqii3mpbe.jpg" alt="failing specs"></p>
<ul>
<li></li>
</ul>
<p><strong>IX.</strong> fix the model (note that I set <code>dependencies &quot;dm-validations&quot;</code> in my init.rb)</p>
<ul>
<li>X. run the specs</li>
</ul>
<p><img src="https://img.skitch.com/20080907-m7p2r6q1qau4k3qsmeadwu2tur.jpg" alt="passing specs"></p>
<ul>
<li><strong>XI.</strong> add more specs</li>
</ul>
<p>As you can see, Factory.build(:client) only creates a new instance of the Object, while Factory(:client) creates, saves and loads the instance.</p>
<ul>
<li><strong>XII.</strong> get them to pass</li>
</ul>
<p>Factory Girl makes fixtures simple and clean. Here is another example for creating associations:</p>
<p>Factory Girl also supports sequencing, check out FG <a href="https://github.com/thoughtbot/factory_girl">read me</a></p>
<h2 id="in-conclusion-factory-girl-is-a-mature-and-solid-factory-solution-which-will-take-you-less-than-15-minutes-to-get-used-to-it-will-offer-you-loads-of-flexibility-and-less-frustration-than-good-old-yaml-fixtures-you-can-also-use-it-with-existing-fixtures-if-you-want-to-start-using-it-in-an-existing-app">In conclusion, Factory Girl is a mature and solid factory solution which will take you less than 15 minutes to get used to. It will offer you loads of flexibility and less frustration than good old yaml fixtures. You can also use it with existing fixtures if you want to start using it in an existing app.</h2>
]]></content>
		</item>
		
		<item>
			<title>ruby developers don t scale</title>
			<link>https://matt.aimonetti.net/posts/2008-08-ruby-developers-don-t-scale/</link>
			<pubDate>Wed, 27 Aug 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-08-ruby-developers-don-t-scale/</guid>
			<description>Wow, it&amp;rsquo;s been a while since I blogged. With all the cool kids saying that spending time reading RSS feeds is overrated (see Defunkt&amp;rsquo;s keynote for instance) I even wonder if people will ever read this post!
Anyways, I have been quite busy preparing courses for classes I gave to a bunch a great Engineers at one of the Fortune 100 companies based in San Diego. I was also planning my big vacation trip to Europe and wrapping up few projects.</description>
			<content type="html"><![CDATA[<p>Wow, it&rsquo;s been a while since I blogged. With all the cool kids saying that spending time reading RSS feeds is overrated (see <a href="https://rubyhoedown2008.confreaks.com/08-chris-wanstrath-keynote.html">Defunkt&rsquo;s keynote</a> for instance) I even wonder if people will ever read this post!</p>
<p>Anyways, I have been quite busy preparing courses for classes I gave to a bunch a great Engineers at one of the Fortune 100 companies based in San Diego. I was also planning my big vacation trip to Europe and wrapping up few projects.</p>
<p>However, during my exile overseas, I came to the conclusion that <strong>Rubyists don&rsquo;t scale</strong>. Since Twitter became stable again, we don&rsquo;t hear many people ranting about Rails not scaling anymore.  With one of my clients' app handling around <strong>7 million requests/day</strong> I can tell you <strong>Ruby/Merb do scale quite well</strong>! But ruby developers don&rsquo;t seem to scale for some reason.</p>
<p>Maybe saying that we(Rubyists) don&rsquo;t scale isn&rsquo;t technically correct but that&rsquo;s basically what one of my client told me.</p>
<p>Let&rsquo;s go back in time a little bit and follow my client who we will call clientX.</p>
<ul>
<li>
<p>ClientX has a <strong>great concept</strong> and wants to conquer the internet.</p>
</li>
<li>
<p>ClientX hears that <strong>Rails is the way to go</strong>.</p>
</li>
<li>
<p>ClientX hires a contractor/mercenary/freelancer/guns for hire/<strong>consultant</strong> (aka Me)</p>
</li>
<li>
<p>Me builds a <strong>killer app</strong> using <strong>Merb</strong> (killing framework)</p>
</li>
<li>
<p>ClientX raises loads of <strong>$$$</strong></p>
</li>
<li>
<p>ClientX <strong>wants to hire a team</strong> because Me doesn&rsquo;t want to become a FTE</p>
</li>
<li>
<p>ClientX and Me <strong>look for Rubyists</strong> wanting to relocate and get a decent salary</p>
</li>
<li>
<p>ClientX <em>*can&rsquo;t find someone</em> they consider good enough and who would accept their package</p>
</li>
<li>
<p>Many <strong>JAVA guys are available</strong> on location and accept lower packages</p>
</li>
<li>
<p><strong>Ruby app gets ported over to JAVA</strong></p>
</li>
<li>
<p><strong>Me sad</strong> :(</p>
</li>
</ul>
<p>So is it really the Rubyists' fault if we don&rsquo;t want to relocate and only accept higher packages? Should I blame <a href="https://blog.obiefernandez.com/">Obie</a> for telling people to charge more and teaching how to <a href="https://rubyhoedown2008.confreaks.com/07-obie-fernandez-do-the-hustle.html">hustle</a>? Or should we just tell clients that it&rsquo;s time to get used to working remotely?</p>
<p>Honestly, I don&rsquo;t think any of the above explanations are valid. Ruby is the new/hot technology and very few people have the skills and experience to lead major projects. These people make a good living and enjoy their &ldquo;freedom&rdquo; and dream of building their own products. Most of them/us value their work environment, family and are reluctant to move.</p>
<p><img src="https://img.skitch.com/20080827-rwca7tfprhce6hw19uytfqx1bc.jpg" alt="scale"></p>
<p>At the same time, companies do need people locally(at least a core team) and can&rsquo;t always afford the cool kids.</p>
<p>ClientX, quite frustrated by the whole hiring process told me once: <strong>&ldquo;you Ruby folks are too unavailable and difficult to work with! We need a committed team that actually cares about the company/product.&quot;</strong></p>
<p>That hurts when you worked hard on a project and just can&rsquo;t satisfy the client by finding guys willing to relocate and work for them. <strong>It gets even more painful when your code gets entirely ported over to JAVA!</strong></p>
<p>But at the same time I understand ClientX&rsquo;s motivation, PHP guys are cheaper, JAVA guys are more available, why in the word did we go with Ruby and are now struggling finding people?</p>
<p>Once again, there is positive and negative side in everything, by choosing Ruby and a &ldquo;great contractor&rdquo; ClientX was able to <strong>catch up with the competition and even pass them in no time</strong>. They quickly raised good money and got everything they needed to become #1. I don&rsquo;t believe it would have been possible to do the same thing so quickly with JAVA for instance. However choosing a cutting edge technology means you need to look harder for talented people.</p>
<p>It&rsquo;s too bad the code gets rewritten in a different language but at the same time, I do my best to facilitate the process and to keep a good relation with my client. There was nothing personal in the decision, it&rsquo;s just too bad we were not able to keep on using the latest/coolest/awesomess technology available :)</p>
<h2 id="to-finish-on-a-positive-note-here-is-the-solution-to-scale-your-ruby-task-force-provided-to-you-by-the-caboose-wisdom">To finish on a positive note, here is the solution to scale your Ruby task force provided to you by the #caboose wisdom:</h2>
<p>Based on my conversations with other #caboosers who hire other devs, the word in the street is that you just need to get one or two great ruby guys (who will probably cost you a lot) and find a bunch of smart people to train. You&rsquo;ll end up with an awesome team of scalable rubyists ;)</p>
]]></content>
		</item>
		
		<item>
			<title>googlecharts featured on github</title>
			<link>https://matt.aimonetti.net/posts/2008-06-googlecharts-featured-on-github/</link>
			<pubDate>Fri, 27 Jun 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-06-googlecharts-featured-on-github/</guid>
			<description>Github, probably the most famous social code hosting service just redesigned their homepage and are now featuring hosted projects.
I got a very good surprise when Takeo from Powerset &amp;amp; Stafftool hall of fame mentioned to me that Github picked one of my gems as the first featured project!
By the way, Takeo is also a Googlecharts contributor (+ a Merbist) and I had the honor to be the first one he ever forked!</description>
			<content type="html"><![CDATA[<p><a href="https://github.com">Github</a>, probably the most famous social code hosting service just <a href="https://github.com/blog/103-new-homepage">redesigned their homepage</a> and are now featuring hosted projects.</p>
<p>I got a very good surprise when <a href="https://github.com/takeo">Takeo</a> from <a href="https://powerset.com">Powerset</a> &amp; <a href="https://stafftool.com">Stafftool</a> hall of fame mentioned to me that <a href="https://github.com">Github</a> picked one of my gems as the first featured project!</p>
<p><img src="https://img.skitch.com/20080627-r14subqdx2ye3w13qefbx974gc.png" alt="github"></p>
<p>By the way, Takeo is also a Googlecharts contributor (+ a Merbist) and I had the honor to be the first one he ever forked!</p>
<p>Another Googlecharts user, <a href="https://graffletopia.com">Mokolabs</a> from Graffletopia and <a href="https://icalshare.com/">iCal Share</a> also decided to try Git and Github. In no time he had forked my project, made some modifications and sent me a pull request. w00t w00t!</p>
<p>To celebrate, we released version 1.3.4 with cleaner documentation, and enhanced features.</p>
<p><a href="https://googlecharts.rubyforge.org/">Documentation</a> &amp; <a href="https://github.com/mattetti/googlecharts">Code Repo</a></p>
<p>Thanks to everyone involved in this project. And special kudos to the <a href="https://github.com">GitHub</a> team for offering such an awesome service!</p>
]]></content>
		</item>
		
		<item>
			<title>about metaprogramming speed</title>
			<link>https://matt.aimonetti.net/posts/2008-06-about-metaprogramming-speed/</link>
			<pubDate>Wed, 18 Jun 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-06-about-metaprogramming-speed/</guid>
			<description>In a previous article I took an example of bad metaprogramming and I pushed people to think twice before using metaprogramming.
My main points were that:
  you might make your code way slower if you don&amp;rsquo;t know what you are doing
  readability might drop considerably
  maintainability can become an issue
  People left some very good comments about how to write the same module using metaprogramming and keep things fast.</description>
			<content type="html"><![CDATA[<p>In a <a href="https://railsontherun.com/2008/5/4/avoid-using-metaprogramming">previous article</a> I took an example of bad metaprogramming and I pushed people to think twice before using metaprogramming.</p>
<p>My main points were that:</p>
<ul>
<li>
<p>you might make your code way slower if you don&rsquo;t know what you are doing</p>
</li>
<li>
<p>readability might drop considerably</p>
</li>
<li>
<p>maintainability can become an issue</p>
</li>
</ul>
<p>People left some very good comments about how to write the same module using metaprogramming and keep things fast.</p>
<p>Today <a href="https://yehudakatz.com">Wycats</a> pinged me about this post and told me that the issue was define_method and that class_eval is effectively the same as regular code, it gets evaluated in eval.c, just like regular Ruby code. On the other hand, defined_method has to marshall the proc.</p>
<p>I cleaned up my benchmarks using <a href="https://github.com/somebee/rbench/tree/master">rbench</a>, added some of the solutions provided to me and obtained the following results:</p>
<p><img src="https://img.skitch.com/20080618-ju8hy1b1pw8c3hb882ksr3hbed.jpg" alt="results"></p>
<p>Here is the original/bad metaprogramming example:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;MetaTimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    {&lt;span class=&quot;sy&quot;&gt;:second&lt;/span&gt; =&gt; &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;     &lt;span class=&quot;sy&quot;&gt;:minute&lt;/span&gt; =&gt; &lt;span class=&quot;i&quot;&gt;60&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;     &lt;span class=&quot;sy&quot;&gt;:hour&lt;/span&gt; =&gt; &lt;span class=&quot;i&quot;&gt;3600&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;     &lt;span class=&quot;sy&quot;&gt;:day&lt;/span&gt; =&gt; [&lt;span class=&quot;i&quot;&gt;24&lt;/span&gt;,&lt;span class=&quot;sy&quot;&gt;:hours&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;     &lt;span class=&quot;sy&quot;&gt;:week&lt;/span&gt; =&gt; [&lt;span class=&quot;i&quot;&gt;7&lt;/span&gt;,&lt;span class=&quot;sy&quot;&gt;:days&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;     &lt;span class=&quot;sy&quot;&gt;:month&lt;/span&gt; =&gt; [&lt;span class=&quot;i&quot;&gt;30&lt;/span&gt;,&lt;span class=&quot;sy&quot;&gt;:days&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;     &lt;span class=&quot;sy&quot;&gt;:year&lt;/span&gt; =&gt; [&lt;span class=&quot;fl&quot;&gt;364.25&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:days&lt;/span&gt;]}.each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |meth, amount|&lt;tt&gt;
&lt;/tt&gt;      define_method &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;meth&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        amount = amount.is_a?(&lt;span class=&quot;co&quot;&gt;Array&lt;/span&gt;) ? amount[&lt;span class=&quot;i&quot;&gt;0&lt;/span&gt;].send(amount[&lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;]) : amount&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt; * amount&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      alias_method &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;meth&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;.intern, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;meth&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;Numeric&lt;/span&gt;.send &lt;span class=&quot;sy&quot;&gt;:include&lt;/span&gt;, &lt;span class=&quot;co&quot;&gt;MetaTimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>The no metaprogramming module is available <a href="https://pastie.textmate.org/217046">there</a></p>
<p>Refactored:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;RefaMetaTimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  {&lt;span class=&quot;sy&quot;&gt;:second&lt;/span&gt; =&gt; &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;   &lt;span class=&quot;sy&quot;&gt;:minute&lt;/span&gt; =&gt; &lt;span class=&quot;i&quot;&gt;60&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;   &lt;span class=&quot;sy&quot;&gt;:hour&lt;/span&gt; =&gt; &lt;span class=&quot;i&quot;&gt;3600&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;   &lt;span class=&quot;sy&quot;&gt;:day&lt;/span&gt; =&gt; [&lt;span class=&quot;i&quot;&gt;24&lt;/span&gt;,&lt;span class=&quot;sy&quot;&gt;:hours&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;   &lt;span class=&quot;sy&quot;&gt;:week&lt;/span&gt; =&gt; [&lt;span class=&quot;i&quot;&gt;7&lt;/span&gt;,&lt;span class=&quot;sy&quot;&gt;:days&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;   &lt;span class=&quot;sy&quot;&gt;:month&lt;/span&gt; =&gt; [&lt;span class=&quot;i&quot;&gt;30&lt;/span&gt;,&lt;span class=&quot;sy&quot;&gt;:days&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;   &lt;span class=&quot;sy&quot;&gt;:year&lt;/span&gt; =&gt; [&lt;span class=&quot;fl&quot;&gt;364.25&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:days&lt;/span&gt;]}.each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |meth, amount|&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.class_eval &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&lt;&lt;-RUBY&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;      def r_&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;meth&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;amount.is_a?(&lt;span class=&quot;co&quot;&gt;Array&lt;/span&gt;) ? &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;amount[&lt;span class=&quot;i&quot;&gt;0&lt;/span&gt;]&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;amount[&lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;]&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; : &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;amount&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;      end&lt;tt&gt;
&lt;/tt&gt;      alias_method :r_&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;meth&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;s, :r_&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;meth&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;    RUBY&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;co&quot;&gt;Numeric&lt;/span&gt;.send &lt;span class=&quot;sy&quot;&gt;:include&lt;/span&gt;, &lt;span class=&quot;co&quot;&gt;RefaMetaTimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>the refactor 2 or eval based solution provided by <a href="https://pastie.caboo.se/191414">Matt Jones</a> which uses class_eval like the previous refactor.</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;EvalMetaTimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;self&lt;/span&gt;.included(base)&lt;tt&gt;
&lt;/tt&gt;      base.class_eval &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        [ [&lt;span class=&quot;sy&quot;&gt;:e_second&lt;/span&gt;, &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;          [&lt;span class=&quot;sy&quot;&gt;:e_minute&lt;/span&gt;, &lt;span class=&quot;i&quot;&gt;60&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;          [&lt;span class=&quot;sy&quot;&gt;:e_hour&lt;/span&gt;, &lt;span class=&quot;i&quot;&gt;3600&lt;/span&gt;], &lt;tt&gt;
&lt;/tt&gt;          [&lt;span class=&quot;sy&quot;&gt;:e_day&lt;/span&gt;, [&lt;span class=&quot;i&quot;&gt;24&lt;/span&gt;,&lt;span class=&quot;sy&quot;&gt;:e_hours&lt;/span&gt;]], &lt;tt&gt;
&lt;/tt&gt;          [&lt;span class=&quot;sy&quot;&gt;:e_week&lt;/span&gt;, [&lt;span class=&quot;i&quot;&gt;7&lt;/span&gt;,&lt;span class=&quot;sy&quot;&gt;:e_days&lt;/span&gt;]], &lt;tt&gt;
&lt;/tt&gt;          [&lt;span class=&quot;sy&quot;&gt;:e_month&lt;/span&gt;, [&lt;span class=&quot;i&quot;&gt;30&lt;/span&gt;,&lt;span class=&quot;sy&quot;&gt;:e_days&lt;/span&gt;]], &lt;tt&gt;
&lt;/tt&gt;          [&lt;span class=&quot;sy&quot;&gt;:e_year&lt;/span&gt;, [&lt;span class=&quot;fl&quot;&gt;365.25&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:e_days&lt;/span&gt;]]].each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |meth, amount|&lt;tt&gt;
&lt;/tt&gt;            amount = amount.is_a?(&lt;span class=&quot;co&quot;&gt;Array&lt;/span&gt;) ? amount[&lt;span class=&quot;i&quot;&gt;0&lt;/span&gt;].send(amount[&lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;]) : amount&lt;tt&gt;
&lt;/tt&gt;            eval &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;def &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;meth&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;; self*&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;amount&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;; end&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;            alias_method &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;meth&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, meth&lt;tt&gt;
&lt;/tt&gt;          &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;Numeric&lt;/span&gt;.send &lt;span class=&quot;sy&quot;&gt;:include&lt;/span&gt;, &lt;span class=&quot;co&quot;&gt;EvalMetaTimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>and finally, the &ldquo;better metaprogramming&rdquo; version:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt; &lt;span class=&quot;r&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;cl&quot;&gt;GoodMetaTimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;SECOND&lt;/span&gt;  = &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;MINUTE&lt;/span&gt;  = &lt;span class=&quot;co&quot;&gt;SECOND&lt;/span&gt; * &lt;span class=&quot;i&quot;&gt;60&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;HOUR&lt;/span&gt;    = &lt;span class=&quot;co&quot;&gt;MINUTE&lt;/span&gt; * &lt;span class=&quot;i&quot;&gt;60&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;DAY&lt;/span&gt;     = &lt;span class=&quot;co&quot;&gt;HOUR&lt;/span&gt; * &lt;span class=&quot;i&quot;&gt;24&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;WEEK&lt;/span&gt;    = &lt;span class=&quot;co&quot;&gt;DAY&lt;/span&gt; * &lt;span class=&quot;i&quot;&gt;7&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;MONTH&lt;/span&gt;   = &lt;span class=&quot;co&quot;&gt;DAY&lt;/span&gt; * &lt;span class=&quot;i&quot;&gt;30&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;YEAR&lt;/span&gt;    = &lt;span class=&quot;co&quot;&gt;DAY&lt;/span&gt; * &lt;span class=&quot;fl&quot;&gt;364.25&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%w[&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SECOND MINUTE HOUR DAY WEEK MONTH YEAR&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;]&lt;/span&gt;&lt;/span&gt;.each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |const_name|&lt;tt&gt;
&lt;/tt&gt;      meth = const_name.downcase&lt;tt&gt;
&lt;/tt&gt;      class_eval &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&lt;&lt;-RUBY&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;        def g_&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;meth&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; &lt;tt&gt;
&lt;/tt&gt;          self * &lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;const_name&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; &lt;tt&gt;
&lt;/tt&gt;        end &lt;tt&gt;
&lt;/tt&gt;        alias g_&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;meth&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;s g_&lt;/span&gt;&lt;span class=&quot;il&quot;&gt;&lt;span class=&quot;dl&quot;&gt;#{&lt;/span&gt;meth&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;      RUBY&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;co&quot;&gt;Numeric&lt;/span&gt;.send &lt;span class=&quot;sy&quot;&gt;:include&lt;/span&gt;, &lt;span class=&quot;co&quot;&gt;GoodMetaTimeDSL&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>Looking at the refactored version by Wycats, you can see he&rsquo;s right and the major issue with the original version was define_method. Using class_eval does make things almost as fast and even faster than the no metaprogramming version.</p>
<p>Interesting enough, the benchmarks show that some methods from the meta modules are faster than the ones from the no meta module. Overall, an optimized metaprogramming can be more or else as fast as a non meta code. Of course, with the new VMs coming up, things might change a little bit depending on the language implementation.</p>
<p><em>In conclusion, metaprogramming can be as fast as no metaprogramming but that won&rsquo;t help your code readability and maintainability, so make sure to only use this great trick when needed!</em></p>
<p>p.s: <a href="https://pastie.textmate.org/217071">here</a> is the benchmark file if you don&rsquo;t believe me ;)</p>
]]></content>
		</item>
		
		<item>
			<title>news update</title>
			<link>https://matt.aimonetti.net/posts/2008-06-news-update/</link>
			<pubDate>Wed, 18 Jun 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-06-news-update/</guid>
			<description>I realized I haven&amp;rsquo;t updated this blog in a while. Here is a quick update on what&amp;rsquo;s happened and on things to come:
 RailsConf 08. Great conference, probably my last Rails Conf though. I&amp;rsquo;ll be in Orlando for Ruby Conf 08 and I&amp;rsquo;ll focus on 1 or 2 local conferences (probably mountain west and another one).   MerbCamp 08 in San Diego this Fall organized by SD Ruby. Details are not finalized yet but Yehuda Katz announced it during his Merb talk at RailsConf.</description>
			<content type="html"><![CDATA[<p>I realized I haven&rsquo;t updated this blog in a while. Here is a quick update on what&rsquo;s happened and on things to come:</p>
<ul>
<li><a href="https://en.oreilly.com/rails2008/public/content/home">RailsConf 08</a>. Great conference, probably my last Rails Conf though. I&rsquo;ll be in Orlando for <a href="https://rubyconf.org/">Ruby Conf 08</a> and I&rsquo;ll focus on 1 or 2 local conferences (probably <a href="https://mtnwestrubyconf.org/">mountain west</a> and another one).</li>
</ul>
<ul>
<li>MerbCamp 08 in San Diego this Fall organized by <a href="https://sdruby.com">SD Ruby</a>. Details are not finalized yet but <a href="https://yehudakatz.com/">Yehuda Katz</a> announced it during his Merb talk at RailsConf.</li>
</ul>
<ul>
<li>Moved this blog to a new <a href="https://joyent.com">Joyent accelerator</a> with git support and finally have the possibility to use Ambition! (planning on moving from Mephisto to <a href="https://crazycool.co.uk/2008/04/26/announcing-feather">Feather</a>)</li>
</ul>
<ul>
<li>Launched a client&rsquo;s Merb app and getting around 3 million hits/day. Merb is just awesome. (more info when the client&rsquo;s app gets out of beta)</li>
</ul>
<ul>
<li>I&rsquo;ll join <a href="https://railsenvy.com/">Gregg Pollack</a> from <a href="https://railsenvy.com/">https://railsenvy.com/</a> during <a href="https://qcon.infoq.com">Qcon</a> and take part in the <a href="https://qcon.infoq.com/sanfrancisco-2008/tracks/show_track.jsp?trackOID=172">Ruby for the Enterprise</a> track. <a href="https://qcon.infoq.com/sanfrancisco-2008/speaker/Matt+Aimonetti">My talk</a> will focus on Merb usage in real life.</li>
</ul>
<ul>
<li>Renamed my github username, new repo url: <a href="https://github.com/mattetti">https://github.com/mattetti</a> (sorry about that)</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>avoid using metaprogramming</title>
			<link>https://matt.aimonetti.net/posts/2008-05-avoid-using-metaprogramming/</link>
			<pubDate>Sun, 04 May 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-05-avoid-using-metaprogramming/</guid>
			<description>Ruby is sexy, Ruby is cool and its metaprogramming potential offers some really cook features. However you might not realize that your cleverness is slowing down your code.
Today I was working on cleaning up merb_helper a Merb plugin that brings a lot of the stuff Rails developers are used to. In Merb we aim for speed and try to avoid magic.
merb_plugin didn&amp;rsquo;t receive a lot of love from the main contributors but few features were added by different contributors and the code became hard to maintain.</description>
			<content type="html"><![CDATA[<p>Ruby is sexy, Ruby is cool and its metaprogramming potential offers some really cook features. However you might not realize that your cleverness is slowing down your code.</p>
<p>Today I was working on cleaning up merb_helper a Merb plugin that brings a lot of the stuff Rails developers are used to. In Merb we aim for speed and try to avoid magic.</p>
<p>merb_plugin didn&rsquo;t receive a lot of love from the main contributors but few features were added by different contributors and the code became hard to maintain.</p>
<p>Looking at the code I quickly found this bad boy:</p>
<p>(Old Merb Time DSL using metaprogramming)</p>
<pre><code>module MetaTimeDSL

    {:second =&gt; 1,
     :minute =&gt; 60,
     :hour =&gt; 3600,
     :day =&gt; [24,:hours],
     :week =&gt; [7,:days],
     :month =&gt; [30,:days],
     :year =&gt; [364.25, :days]}.each do |meth, amount|
      define_method &quot;m_#{meth}&quot; do
        amount = amount.is_a?(Array) ? amount[0].send(amount[1]) : amount
        self * amount
      end
      alias_method &quot;m_#{meth}s&quot;.intern, &quot;m_#{meth}&quot;
    end

  end
  Numeric.send :include, MetaTimeDSL
</code></pre>
<p>The above code looks awful to me and I decided to rewrite it a way I thought would be more efficient:</p>
<pre><code> module TimeDSL

    def second
      self * 1
    end
    alias_method :seconds, :second

    def minute
      self * 60
    end
    alias_method :minutes, :minute

    def hour
      self * 3600
    end
    alias_method :hours, :hour

    def day
      self * 86400
    end
    alias_method :days, :day

    def week
      self * 604800
    end
    alias_method :weeks, :week

    def month
      self * 2592000
    end
    alias_method :months, :month

    def year
      self * 31471200
    end
    alias_method :years, :year

  end
  Numeric.send :include, TimeDSL
</code></pre>
<p>To make sure I was right, I run the following benchmarks:</p>
<pre><code>require 'benchmark'
TIMES = (ARGV[0] || 100_000).to_i

Benchmark.bmbm do |x|

  x.report(&quot;metaprogramming 360.seconds&quot;) do
    TIMES.times do
      360.m_seconds
    end
  end

  x.report(&quot;no metaprogramming 360.hours&quot;) do
    TIMES.times do
      360.seconds
    end
  end

  x.report(&quot;metaprogramming 360.minutes&quot;) do
    TIMES.times do
      360.m_minutes
    end
  end

  x.report(&quot;no metaprogramming 360.minutes&quot;) do
    TIMES.times do
      360.minutes
    end
  end

  x.report(&quot;metaprogramming 360.hours&quot;) do
    TIMES.times do
      360.m_hours
    end
  end

  x.report(&quot;no metaprogramming 360.hours&quot;) do
    TIMES.times do
      360.hours
    end
  end

  x.report(&quot;metaprogramming 360.days&quot;) do
    TIMES.times do
      360.m_days
    end
  end

  x.report(&quot;no metaprogramming 360.days&quot;) do
    TIMES.times do
      360.days
    end
  end

  x.report(&quot;metaprogramming 360.weeks&quot;) do
    TIMES.times do
      360.m_weeks
    end
  end

  x.report(&quot;no metaprogramming 360.weeks&quot;) do
    TIMES.times do
      360.weeks
    end
  end

  x.report(&quot;metaprogramming 18.months&quot;) do
    TIMES.times do
      18.m_months
    end
  end

  x.report(&quot;no metaprogramming 18.months&quot;) do
    TIMES.times do
      18.months
    end
  end

  x.report(&quot;metaprogramming 7.years&quot;) do
    TIMES.times do
      7.m_years
    end
  end

  x.report(&quot;no metaprogramming 7.years&quot;) do
    TIMES.times do
      7.years
    end
  end

end


 Rehearsal ------------------------------------------------------------------
metaprogramming 360.seconds      0.130000   0.000000   0.130000 (  0.133164)
no metaprogramming 360.hours     0.050000   0.000000   0.050000 (  0.042655)
metaprogramming 360.minutes      0.130000   0.000000   0.130000 (  0.133327)
no metaprogramming 360.minutes   0.040000   0.000000   0.040000 (  0.042401)
metaprogramming 360.hours        0.140000   0.000000   0.140000 (  0.134312)
no metaprogramming 360.hours     0.040000   0.000000   0.040000 (  0.043125)
metaprogramming 360.days         0.130000   0.000000   0.130000 (  0.134949)
no metaprogramming 360.days      0.050000   0.000000   0.050000 (  0.043745)
metaprogramming 360.weeks        0.130000   0.000000   0.130000 (  0.135581)
no metaprogramming 360.weeks     0.050000   0.000000   0.050000 (  0.043544)
metaprogramming 18.months        0.130000   0.000000   0.130000 (  0.135234)
no metaprogramming 18.months     0.050000   0.000000   0.050000 (  0.044354)
metaprogramming 7.years          0.140000   0.000000   0.140000 (  0.144062)
no metaprogramming 7.years       0.050000   0.000000   0.050000 (  0.044392)
--------------------------------------------------------- total: 1.260000sec

                                     user     system      total        real
metaprogramming 360.seconds      0.130000   0.000000   0.130000 (  0.132567)
no metaprogramming 360.hours     0.040000   0.000000   0.040000 (  0.042777)
metaprogramming 360.minutes      0.140000   0.000000   0.140000 (  0.132554)
no metaprogramming 360.minutes   0.040000   0.000000   0.040000 (  0.043193)
metaprogramming 360.hours        0.130000   0.000000   0.130000 (  0.133027)
no metaprogramming 360.hours     0.050000   0.000000   0.050000 (  0.042613)
metaprogramming 360.days         0.130000   0.000000   0.130000 (  0.138637)
no metaprogramming 360.days      0.050000   0.000000   0.050000 (  0.043213)
metaprogramming 360.weeks        0.130000   0.000000   0.130000 (  0.134049)
no metaprogramming 360.weeks     0.040000   0.000000   0.040000 (  0.043713)
metaprogramming 18.months        0.140000   0.000000   0.140000 (  0.134941)
no metaprogramming 18.months     0.040000   0.000000   0.040000 (  0.043980)
metaprogramming 7.years          0.150000   0.000000   0.150000 (  0.143389)
no metaprogramming 7.years       0.040000   0.000000   0.040000 (  0.044585)
 0.136591)
</code></pre>
<p>The metaprogramming version of the same implementation is almost 3 times slower!</p>
<p>Moral of the story: be careful when using metaprogramming, you might end up slowing down your code considerably.</p>
]]></content>
		</item>
		
		<item>
			<title>barcamp san diego rev 3</title>
			<link>https://matt.aimonetti.net/posts/2008-04-barcamp-san-diego-rev-3/</link>
			<pubDate>Sun, 27 Apr 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-04-barcamp-san-diego-rev-3/</guid>
			<description>Just a reminder, this coming week end, San Diego presents BarCamp for the third time.
This time, the chosen Venue is Microsoft in La Jolla
I was thinking about preparing 2 intro talks, one on Merb and one on Unobtrusive Javascript (jQuery, Prototype + LowPro etc&amp;hellip;), then we&amp;rsquo;ll see the crowd and what people are interested in. Feel free to give me your feedback, suggestions&amp;hellip;
I also heard that on top of the awesome people from san Diego, some other important people are coming just for the event:</description>
			<content type="html"><![CDATA[<p><img src="https://www.barcampsd.org/badges_for_bcsd3/orange.png" alt="BarCamp"></p>
<p>Just a reminder, this coming week end, San Diego presents <a href="https://www.barcampsd.org/">BarCamp</a> for the third time.</p>
<p>This time, the chosen Venue is <a href="https://www.technicaltrainingresources.com/">Microsoft</a> in <a href="https://maps.google.com/maps?hl=en&amp;ie=UTF8&amp;f=d&amp;daddr=9255+Towne+Centre+Dr+San+Diego,+CA+92121">La Jolla</a></p>
<p>I was thinking about preparing 2 intro talks, one on <a href="https://merbivore.com">Merb</a> and one on <a href="https://en.wikipedia.org/wiki/Unobtrusive_JavaScript">Unobtrusive Javascript</a> (jQuery, Prototype + LowPro etc&hellip;), then we&rsquo;ll see the crowd and what people are interested in. Feel free to give me your feedback, suggestions&hellip;</p>
<p>I also heard that on top of the awesome people from san Diego, some other important people are coming just for the event:</p>
<ul>
<li>
<p><a href="https://glu.ttono.us/">Kevin Clark</a> from the <a href="https://www.powerset.com/">Powerset</a> hall of fame.</p>
</li>
<li>
<p><a href="https://derekneighbors.com/">Derek Neighbors</a> representing Phoenix&rsquo;s top Rails shop: <a href="https://integrumtech.com">Integrum</a></p>
</li>
</ul>
<h2 id="warning">Warning</h2>
<p>Based on previous BarCamps, you might end up seeing <a href="https://www.flickr.com/photos/kirinqueen/1993483057/sizes/m/in/pool-393912@N21/">a guy wearing a kilt who talks about how he is his own imaginary friend</a>, having to look at  <a href="https://www.flickr.com/photos/techslut/2043825771/sizes/l/in/pool-393912@N21/">ActionScript code</a>, meet <a href="https://www.flickr.com/photos/acphonehome/532658193/in/pool-barcampsd/">a lot</a> of <a href="https://www.flickr.com/photos/kirinqueen/531272887/in/pool-barcampsd">interesting people</a> and even maybe learn about <a href="https://www.flickr.com/photos/techslut/545216043/in/pool-barcampsd">lock picking</a>.</p>
<p><a href="https://farm2.static.flickr.com/1053/527321111_763e4ad085.jpg"><img src="https://farm2.static.flickr.com/1053/527321111_763e4ad085_m.jpg" alt="last year barcamp sd crowd"></a></p>
<p><a href="https://farm3.static.flickr.com/2004/2044606386_2ee84dcce3.jpg"><img src="https://farm3.static.flickr.com/2004/2044606386_2ee84dcce3_m.jpg" alt="outside"></a></p>
<p><a href="https://farm2.static.flickr.com/1082/529394507_f34d9015c0.jpg"><img src="https://farm2.static.flickr.com/1082/529394507_f34d9015c0_m.jpg" alt="powerpoint karaoke"></a></p>
<p><a href="https://farm2.static.flickr.com/1114/527020113_cbe6393372.jpg"><img src="https://farm2.static.flickr.com/1114/527020113_cbe6393372_m.jpg" alt="tshirt printing"></a></p>
<p><a href="https://farm3.static.flickr.com/2351/1994270564_3a0a2f5319.jpg"><img src="https://farm3.static.flickr.com/2351/1994270564_3a0a2f5319_m.jpg" alt="presentation"></a></p>
<p>I even heard rumors saying that <a href="https://blog.aisleten.com/">Ryan Felton</a> is organizing another <a href="https://www.flickr.com/photos/kirinqueen/1994487718/in/pool-barcampsd">wii tournament</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>freezing rails with git</title>
			<link>https://matt.aimonetti.net/posts/2008-04-freezing-rails-with-git/</link>
			<pubDate>Wed, 16 Apr 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-04-freezing-rails-with-git/</guid>
			<description>As you&amp;rsquo;ve probably heard, Rails now moved to its own GitHub repo.
If, like me you were a heavy piston user, you are wondering how you will be able to do the same thing if you switch to git.
First off, you need to know that Piston will soon support git. As a matter a fact it already does. At least you can download a beta version from François&amp;rsquo;s blog.</description>
			<content type="html"><![CDATA[<p>As you&rsquo;ve <a href="https://blog.rubyonrails.com/2008/4/11/rails-premieres-on-github">probably heard</a>, Rails now moved to <a href="https://github.com/rails/rails">its own GitHub repo</a>.</p>
<p>If, like me you were a heavy <a href="https://piston.rubyforge.org/">piston</a> user, you are wondering how you will be able to do the same thing if you switch to git.</p>
<p>First off, you need to know that Piston will soon support git. As a matter a fact it already does. At least you can download a beta version from <a href="https://blog.teksol.info/tags/piston">François&rsquo;s blog</a>.</p>
<p>You can also go with <a href="https://evil.che.lu/projects/braid">giston/braids</a> which was meant to make the svn/switch easy on you. I heard rumors that <a href="https://evil.che.lu">evilchelu</a> might not keep on developing this project. You might want to check with him.</p>
<p>Personally I didn&rsquo;t really like using any of these solutions. Rails also came with its' own approach. (<a href="https://github.com/rails/rails/commit/4b17082107aced980fc4b511028ee763247bc5ab">rake rails:freeze:edge</a>)</p>
<p>When I recently worked on <a href="https://railsontherun.com/2008/4/15/merb-tip-how-to-freeze-a-project">Merb&rsquo;s freezer</a>, I discovered the power of <a href="https://www.kernel.org/pub/software/scm/git/docs/git-submodule.html">git submodules</a>.</p>
<p>Submodules allow you to import &ldquo;modules&rdquo; from other git repos inside your own repo. Basically they do what piston does for SVN, apart that submodules are built-in git. Of course it has an expected limitation, you can only add git submodules.</p>
<p>The good news is that Rails moved to git and now you can &ldquo;freeze&rdquo; Rails as a submodule and update really easily!</p>
<p>First thing first, you need to move your project to git. If you are not confident it&rsquo;s a good move yet, you can use &ldquo;git-svn&rdquo;. However, I would personally recommend you don&rsquo;t. I did that for few months and when I finally moved to git only, it was a pain to restructure the entire path of the app.</p>
<p>Anyways, let&rsquo;s say you created a new <a href="https://github.com">github</a> project and if still wish to use git svn do:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;




&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; git-svn import svn&lt;span class=&quot;sy&quot;&gt;:/&lt;/span&gt;/path-to-your-svn-repo project-name&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; cd project-name&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; git remote add origin git&lt;span class=&quot;iv&quot;&gt;@github&lt;/span&gt;.com&lt;span class=&quot;sy&quot;&gt;:mattetti&lt;/span&gt;/project-name.git&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; git push origin master&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>Your project is now under git, but if you pistonized Rails, you can&rsquo;t update it anymore :(</p>
<p>Do not fear my dear friend and do as follows:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;




&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; rm -rf vendor/rails&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; git commit&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; git submodule add git&lt;span class=&quot;sy&quot;&gt;:/&lt;/span&gt;/github.com/rails/rails.git vendor/rails&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; git submodule init&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; git commit&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt;
</code></pre>
<p>That&rsquo;s it you are done :)</p>
<p>Next time you want to update just do:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;




&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; cd vendor/rails&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; git remote update&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; git merge origin/master
</code></pre>
<p>or you can also do</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;




&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; cd vendor/rails&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;er&quot;&gt;$&lt;/span&gt; git pull
</code></pre>
<p>(yes, each plugin acts a a normal git repo)</p>
<p>A quick note for gitHub users. If you browse your repo you won&rsquo;t see the vendor/rails folder and might freak out. Don&rsquo;t! Git is smart and wants to stay slim, instead of copying the files over, it just creates a reference to the original repo. If you try to pull your project in another folder you will see that the Rails folder gets created as expected.</p>
<p>Personally, when plugins are not available in a git repo I usually do a simple svn export to my project vendor&rsquo;s folder. If I need to modify one of these plugins, I just import it to <a href="https://github.com">github</a> and work on it from there.</p>
<p>You might still want to stick to Piston or Braids and that&rsquo;s fine, but now you won&rsquo;t have an excuse not to switch to Git :)</p>
<p>UPDATE: I just found out that Graeme wrote a <a href="https://woss.name/2008/04/09/using-git-submodules-to-track-vendorrails/">nice detailed post</a> about tracking plugins using git, <a href="https://woss.name/2008/04/09/using-git-submodules-to-track-vendorrails/">check it out</a></p>
]]></content>
		</item>
		
		<item>
			<title>merb tip how to freeze a project</title>
			<link>https://matt.aimonetti.net/posts/2008-04-merb-tip-how-to-freeze-a-project/</link>
			<pubDate>Tue, 15 Apr 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-04-merb-tip-how-to-freeze-a-project/</guid>
			<description>THIS CONTENT is OUTDATED and can&amp;rsquo;t be used with Merb 1.0 or more recent
Merb doesn&amp;rsquo;t really have a core team per say. It&amp;rsquo;s actually managed the same way Rubinius is managed meaning that few people such as Ezra, Wycats and Ivey lead the development while many other contributors have commit rights to the different repos.
Patches are handled via GitHub pull Request and LightHouse tickets. Read the following contribution documentation for more info.</description>
			<content type="html"><![CDATA[<p><strong>THIS CONTENT is OUTDATED and can&rsquo;t be used with Merb 1.0 or more recent</strong></p>
<p><a href="merbivore">Merb</a> doesn&rsquo;t really have a core team per say. It&rsquo;s actually managed the same way <a href="https://rubini.us">Rubinius</a> is managed meaning that few people such as <a href="https://github.com/ezmobius">Ezra</a>, <a href="https://github.com/wycats">Wycats</a> and <a href="https://github.com/ivey">Ivey</a> lead the development while many other contributors have commit rights to the different repos.</p>
<p>Patches are handled via <a href="https://github.com">GitHub pull Request</a> and <a href="https://merb.lighthouseapp.com/">LightHouse tickets</a>. Read the following <a href="https://merbivore.com/contribute.html">contribution documentation</a> for more info.</p>
<p><img src="https://www.music-lyrics-chord.com/cover/Vanilla_Ice_Cool_as_Ice.jpg" alt="vanilla ice"></p>
<p>Anyway, I&rsquo;ve been working on a <a href="https://github.com/wycats/merb-more">merb-more</a> gem called <a href="https://github.com/wycats/merb-more/tree/master/merb-freezer">merb-freezer</a>.</p>
<p>We don&rsquo;t have a logo for the plugin yet so I picked a &ldquo;cool&rdquo; star from the late 80&rsquo;s to represent.</p>
<p><em>Vanilla Ice!</em></p>
<p>Right, so you might wonder what&rsquo;s the connection between a <a href="https://en.wikipedia.org/wiki/Kitsch">kitsch</a> white rapper and a new <a href="merbivore">Merb</a> Gem? Not much, apart that they are both cool (or kinda cool).</p>
<p>Let&rsquo;s forget about &ldquo;ice ice Baby&rdquo; and focus on <a href="https://github.com/wycats/merb-more/tree/master/merb-freezer">merb-freezer</a>.</p>
<p><a href="https://github.com/wycats/merb-more/tree/master/merb-freezer">merb-freezer</a> has a simple goal: let you &ldquo;freeze&rdquo; your application and run it without dependencies.</p>
<h2 id="why-would-you-want-to-freeze-your-app">Why would you want to freeze your app?</h2>
<p><em>(This is only valid for Merb 0.9.3 and 0.9.2 edge as of April 14)</em></p>
<ul>
<li>
<p>You might have multiple applications on the same server/slice/cluster. Different applications might require different versions of Merb or some other Merb gems.</p>
</li>
<li>
<p>You might work with a team of developers and want everyone to be using the same version of the gems.</p>
</li>
<li>
<p>You are using Merb Edge and want to make sure that your coworkers are developing/testing against the same revision.</p>
</li>
</ul>
<h2 id="how-to-freeze-your-app">How to freeze your app?</h2>
<p>First thing, in your init.rb file you need to require merb-freezer</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;merb-freezer&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>Now that you required the plugin when you get new rake tasks:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  rake freeze&lt;span class=&quot;sy&quot;&gt;:core&lt;/span&gt;            &lt;span class=&quot;c&quot;&gt;# Freeze core from git://github.com/wycats/merb...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  rake freeze&lt;span class=&quot;sy&quot;&gt;:more&lt;/span&gt;            &lt;span class=&quot;c&quot;&gt;# Freeze more from git://github.com/wycats/merb...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  rake freeze&lt;span class=&quot;sy&quot;&gt;:plugins&lt;/span&gt;         &lt;span class=&quot;c&quot;&gt;# Freeze plugins from git://github.com/wycats/m...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>The rake freeze tasks use by default git submodules to freeze the various components. That means that you need to have your project under git to use that feature. However, if you didn&rsquo;t switch to git yet, do no worry, we have a plan B.</p>
<p>When you run the freeze tasks a framework directory is created at the root of the folder and the gems are checked out there.</p>
<p>Not a git user? We thought of you and added an option for you to use rubygems.</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  rake freeze&lt;span class=&quot;sy&quot;&gt;:core&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;MODE&lt;/span&gt;=rubygems&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>When doing that, you are freezing the latest version available on the rubygems server or installed locally.
Note that when using the default mode, you are pulling the latest version of Merb from the official git repo. If you want to do that using rubygems you will need to checkout the git repos locally and install the gems yourself before freezing them.</p>
<p>Also it&rsquo;s worth noting that you can also do all of that manually, as long as you follow the same conventions you should be fine.</p>
<h2 id="how-to-use-the-freezing-gems">How to use the freezing gems?</h2>
<p>If you are a Rails user, you might expect that Merb uses the frozen gems by default, at least that what I expected. Turns out, it&rsquo;s not the case since Merb avoids too much magic and unless you ask for it, Merb will use the available system gems.</p>
<p>So how to start a frozen merb app? Easy enough:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




frozen-merb
</code></pre>
<p>That&rsquo;s it, you can uninstall merb-core from your system and as long as you froze merb-core, you can start your app.</p>
<h2 id="how-to-update-a-frozen-app">How to update a frozen app?</h2>
<p>simply re-freeze but with the UPDATE=true param</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  rake freeze&lt;span class=&quot;sy&quot;&gt;:core&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;UPDATE&lt;/span&gt;=&lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>This option works for in both modes (rubygems and git submodules).</p>
<h2 id="whats-next">What&rsquo;s next?</h2>
<p>I&rsquo;d like to add a locking mechanism that would allow you to force your app to only run on specific versions of few gems. The main advantage of this approach is that you wouldn&rsquo;t need to freeze files in your repo as long as you have the required versions on your machine.</p>
<p>I would also like to extend the freezer to let you use the submodules to freeze other gems.</p>
<p>Other suggestions? Found a bug? Want to submit a patch?  Leave me a comment or use <a href="https://merb.lighthouseapp.com/">the Merb LightHouse ticketing system</a></p>
]]></content>
		</item>
		
		<item>
			<title>rails or merb what s best for you</title>
			<link>https://matt.aimonetti.net/posts/2008-04-rails-or-merb-what-s-best-for-you/</link>
			<pubDate>Thu, 10 Apr 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-04-rails-or-merb-what-s-best-for-you/</guid>
			<description>If you follow my blog, you already know what Merb is.
I love Rails and I truly believe it has changed web development. At least it has changed the way I do web development.
But Merb looks slick, apparently is way faster than Rails, and has less &amp;ldquo;fluff&amp;rdquo; and less magic.
Now that we are getting really close to a Merb 1.0 (scheduled for Rails Conf &amp;lsquo;08) it&amp;rsquo;s time to evaluate if Merb is the good choice for some of my clients&amp;rsquo; projects.</description>
			<content type="html"><![CDATA[<p><img src="https://brainspl.at/louiecon.gif" alt=""></p>
<p>If you follow my blog, you already know what <a href="https://merbivore.com">Merb</a> is.</p>
<p>I love Rails and I truly believe it has changed web development. At least it has changed the way I do web development.</p>
<p>But Merb looks slick, apparently is way faster than Rails, and has less &ldquo;fluff&rdquo; and less magic.</p>
<p>Now that we are getting really close to a Merb 1.0 (scheduled for Rails Conf &lsquo;08) it&rsquo;s time to evaluate if Merb is the good choice for some of my clients&rsquo; projects.</p>
<p>However, according to Merb&rsquo;s author, Ezra, at MountainWest RubyConf 2008, <a href="https://mwrc2008.confreaks.com/02zygmuntowicz.html">Rails will get you there faster</a>. In a client&rsquo;s case, they don&rsquo;t need to build a huge app but need a lot of speed and the ability to easily handle a heavy load right away without using caching. Also most of the traffic will go through an API so we won&rsquo;t have to manage too many views.</p>
<h2 id="lets-see-how-fast-merb-really-is">Let&rsquo;s see how fast Merb really is.</h2>
<p>To test Merb&rsquo;s speed, I built the very same prototype using Merb 0.9.2 and Rails Edge (pre 2.1). Both apps use ActiveRecord and are connected to a UTF8 MySQL database, both apps have exactly the same views. (Note that Merb would run way faster using DataMapper, but I don&rsquo;t feel that DM 0.9x is production ready yet, also, using a rack handler would certainly be way faster but my goal was really to compare ActionPack vs Merb.)</p>
<p>Both apps use the same ActiveRecord class, their controllers are a bit different but basically do the same thing.</p>
<p>Here is what was tested:</p>
<ul>
<li>
<p>The Merb/Rails app should receive a GET request with a JSON object in the query.</p>
</li>
<li>
<p>The Merb/Rails app should route the request to a controller and pass the JSON object to an AR class.</p>
</li>
<li>
<p>The AR class should parse the JSON object (which contains an array of objects), extract each object, and try to find them in the database using one of the attributes. If the object isn&rsquo;t found, it should be created, otherwise it should return the AR object. The amount of hits should be incremented by 1 and the object should be saved back to the database.</p>
</li>
<li>
<p>A simple HTML view should be rendered</p>
</li>
</ul>
<h2 id="quick-merb-benchmark">Quick Merb benchmark</h2>
<p><img src="https://merbivore.com/img/header_logo.png" alt="merb"></p>
<p>I setup Merb to run locally on my MacBook 2.16Ghz Core Duo 2, 2Gb Ram. To test the raw performance, Merb is started in production mode.</p>
<p>I then used httperf to make 10000 connections to the server at a rate of 500 (&ndash;rate=500 &ndash;send-buffer=4096 &ndash;recv-buffer=16384 &ndash;num-conns=10000 &ndash;num-calls=1)</p>
<p>Here are the results:</p>
<pre><code>&lt;code&gt;Maximum connect burst length: 29
Total: connections 4377 requests 4221 replies 2932 test-duration 41.629 s
Connection rate: 105.1 conn/s (9.5 ms/conn, &lt;=1022 concurrent connections)
Connection time [ms]: min 41.0 avg 1920.4 max 35390.8 median 898.5 stddev 4887.3
Connection time [ms]: connect 2118.1
Connection length [replies/conn]: 1.000

Request rate: 101.4 req/s (9.9 ms/req)
Request size [B]: 321.0

*Reply rate [replies/s]: min 0.0 avg 73.3 max 143.0 stddev 65.8 (8 samples)*
Reply time [ms]: response 809.0 transfer 18.1
Reply size [B]: header 121.0 content 557.0 footer 0.0 (total 678.0)
*Reply

CPU time [s]: user 0.35 system 36.54 (user 0.8% system 87.8% total 88.6%)
Net I/O: 78.4 KB/s (0.6*10^6 bps)

Errors: total 7068 client-timo 0 socket-timo 0 connrefused 0 connreset 1445
Errors: fd-unavail 5623 addrunavail 0 ftab-full 0 other 0
&lt;/code&gt;
</code></pre>
<p>What we care about is the reply rate/s. We have an average of <em>73.3 requests per second</em> with a standard deviation of 65.8 using 8 samples.</p>
<p>We also make sure that all the replies were successful. (status == 2xx)</p>
<p>I also checked the database, made sure my AR object was created and that the hits were increased. AR object hits: 2932, which matches the amount of replies reported by httperf.</p>
<p>We don&rsquo;t care so much about the rest of the httperf. Let&rsquo;s move on to the Rails benchmark.</p>
<hr>
<h2 id="quick-rails-benchmark">Quick Rails benchmark</h2>
<p><img src="https://www.rubyonrails.org/images/rails.png" alt="rails"></p>
<p>Rails is set the same way, running locally in production mode, same httperf settings.</p>
<p>Here are the results:</p>
<pre><code>&lt;code&gt;Maximum connect burst length: 44

Total: connections 2923 requests 2825 replies 1672 test-duration 37.418 s

Connection rate: 78.1 conn/s (12.8 ms/conn, &lt;=1022 concurrent connections)
Connection time [ms]: min 382.7 avg 5635.4 max 36384.5 median 1887.5 stddev 10103.1
Connection time [ms]: connect 3631.2
Connection length [replies/conn]: 1.000

Request rate: 75.5 req/s (13.2 ms/req)
Request size [B]: 319.0

*Reply rate [replies/s]: min 0.0 avg 43.4 max 75.2 stddev 30.8 (7 samples)*
Reply time [ms]: response 1568.1 transfer 36.7
Reply size [B]: header 471.0 content 581.0 footer 0.0 (total 1052.0)
*Reply

CPU time [s]: user 0.25 system 31.31 (user 0.7% system 83.7% total 84.4%)
Net I/O: 69.4 KB/s (0.6*10^6 bps)

DB hits: 1672
&lt;/code&gt;
</code></pre>
<p>First thing, the database object was created properly and the hits incremented to 1672 which matches the amount of replies reported by httperf.</p>
<p>Then, we notice that on this test, we only got 7 samples, that&rsquo;s more than enough though. The standard deviation is 30.8 which is better than Merb&rsquo;s 65.8. That means that in our benchmarks, the reply speed difference in Merb&rsquo;s requests was bigger than Rails'. Not a big deal, this is not a scientific test but it&rsquo;s good to acknowledge it.</p>
<p>What we really care about is the average reply rate: 43.4</p>
<p>Let&rsquo;s also note that all the replies had a 2xx status, so everything went well.</p>
<h2 id="results">Results</h2>
<p>Based on this really basic benchmark, my Merb app had an average reply rate of <em>73.3 requests per second</em> against Rails' <em>43.4 requests per second</em>.</p>
<p>That means that in this very specific case,</p>
<h2 id="_merb-is-69-faster-than-rails_--sexy"><em>Merb is 69% faster than Rails</em>!  Sexy!</h2>
<p>In other words, my Merb prototype could handle 69% more requests than the Rails prototype in the same amount of time.</p>
<p>I heard people reporting than Merb was 3 to 5 times faster than Rails. Honestly, it really depends on what you do. By using ActiveRecord on both prototypes, I limited the speed difference since AR is not multithread and therefore Merb can&rsquo;t run as fast as it would using Sequel or DataMapper. By actually hitting the database on every single request, I also made sure to really compare ActionPack vs Merb.</p>
<h2 id="conclusion">Conclusion</h2>
<p>The conclusion is simple, I recommended that my client go with Merb. Merb 1.0 is almost ready, the public API has been frozen. My client needs speed and simplicity. Using Merb I get exactly what I need and nothing more. Actually, we&rsquo;ll probably increase the performance by writing a rack handler and bypassing the entire framework for API calls (that should be wicked fast!).  Also, as soon as DataMapper becomes production ready, we&rsquo;ll switch to DM and should get way better performance!</p>
<p>Am I suggesting to give up Rails and switch to Merb?
Absolutely not!  First off, Merb is a &ldquo;lower level&rdquo; framework. It requires a deeper understanding of Web Development in general and being more than just &lsquo;acquainted&rsquo; with the Ruby language. So, unless you are an advanced developer or have time to learn, I would suggest to keep on using Rails (start using Merb on personal projects, it&rsquo;s a perfect way of learning).
If you have a lot of views and/or use loads of AJAX, RJS, built-in helpers, you probably want to stick to Rails and start looking at how you can do all of that from scratch. By default Rails uses nasty helpers that create inline javascript, and is something you really want to avoid. RJS is fun, but it goes against Merb&rsquo;s philosophy, so you need to make sure you can live without it (note that you can reproduce the same behavior in Merb rendering JS, it just requries more work). If you rely a lot of Rails plugins, you might want to delay your switch, Merb is pretty new and doesn&rsquo;t have a mass-load of plugins yet.</p>
<p>Finally, Merb doesn&rsquo;t have a lot of documentation and changed a lot when 0.9 got released. To understand how Merb works, you will need to go through the source code, specs, Google, and ask on the Merb IRC channel.</p>
<p>It turns out that in our case we have experienced developers, a great need for speed, not too many views and are following Merb&rsquo;s development really closely . I honestly think it&rsquo;s the best choice for my client and I&rsquo;m excited they accepted to use Merb.</p>
<p>Merb is addressing different issues than Rails and doing it well. I think there is a bright future for Merb. And don&rsquo;t even think that Rails is going away, that won&rsquo;t happen anytime soon!</p>
<p>Recently, <a href="https://www.us.playstation.com/Corporate/About">Sony Playstation</a> even posted a <a href="https://www2.recruitingcenter.net/Clients/playstation/PublicJobs/controller.cfm?jbaction=JobProfile&amp;Job_Id=11424&amp;esid=az">job post</a> looking for a Rails/Merb developer. This is very promising for the Merb community!</p>
]]></content>
		</item>
		
		<item>
			<title>merb tips 2</title>
			<link>https://matt.aimonetti.net/posts/2008-04-merb-tips-2/</link>
			<pubDate>Tue, 08 Apr 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-04-merb-tips-2/</guid>
			<description>_* this content is now outdated and only applied to Merb 0.9_*
I the previous post I covered few useful tips for Merb 0.9. The good news is that Merb should get its wiki setup over the week end!
Here is another batch of hopefully useful tips:
  In init.rb, you can define a dependency and specify a version number: dependency &amp;ldquo;merb_fu&amp;rdquo;, &amp;ldquo;&amp;gt;= 1.0&amp;rdquo;
  If you want to run your application from a subdirectory, once again, in your init.</description>
			<content type="html"><![CDATA[<p>_* this content is now outdated and only applied to Merb 0.9_*</p>
<p>I the <a href="https://railsontherun.com/2008/4/5/merb-tips-1">previous post</a> I covered few useful tips for Merb 0.9. The good news is that Merb should get its wiki setup over the week end!</p>
<p>Here is another batch of hopefully useful tips:</p>
<ul>
<li>
<p>In init.rb, you can define a dependency and specify a version number: <em>dependency &ldquo;merb_fu&rdquo;, &ldquo;&gt;= 1.0&rdquo;</em></p>
</li>
<li>
<p>If you want to run your application from a subdirectory, once again, in your init.rb file, add: <em>c[:path_prefix] = &ldquo;/your_prefix&rdquo;</em> <em>(note, that you can also do that in a specific environment file.)</em></p>
</li>
<li>
<p>You feel like limiting a route to a specific request such as a DELETE? In your router.rb file add the following:</p>
<p>1<tt>
</tt>2<tt>
</tt></p>
<tt>
</tt>  r.match(<span class="s"><span class="dl">"</span><span class="k">/:bucket_id</span><span class="dl">"</span></span>, <span class="sy">:method</span> => <span class="sy">:delete</span>).to(<span class="sy">:controller</span> => <span class="s"><span class="dl">"</span><span class="k">buckets</span><span class="dl">"</span></span>, <span class="sy">:action</span> => <span class="s"><span class="dl">"</span><span class="k">destroy</span><span class="dl">"</span></span>)<tt>
</tt>
</li>
<li>
<p>Since we are talking about routes, what about an iPhone only route?</p>
<p>1<tt>
</tt>2<tt>
</tt></p>
<tt>
</tt>  r.match(<span class="rx"><span class="dl">%r[</span><span class="k">^/(.+)</span><span class="dl">]</span></span>, <span class="sy">:user_agent</span> => <span class="rx"><span class="dl">/</span><span class="k">iPhone</span><span class="dl">/</span></span>).to(<span class="sy">:controller</span> => <span class="s"><span class="dl">"</span><span class="k">mobile</span><span class="dl">"</span></span>, <span class="sy">:title</span> => <span class="s"><span class="dl">"</span><span class="k">Welcome Apple FanBoy</span><span class="dl">"</span></span>, <span class="sy">:action</span> => <span class="s"><span class="dl">"</span><span class="k">show</span><span class="dl">"</span></span>)<tt>
</tt>
</li>
<li>
<p>what about an admin section for my blogposts?</p>
<p>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt></p>
<tt>
</tt>  r.match(<span class="s"><span class="dl">'</span><span class="k">/admin</span><span class="dl">'</span></span>) <span class="r">do</span> |admin|<tt>
</tt>    admin.resources <span class="sy">:blogposts</span><tt>
</tt>  <span class="r">end</span><tt>
</tt>
</li>
<li>
<p>To finish with the routes, look at the <a href="https://github.com/wycats/merb-core/tree/master/spec/public/router/special_spec.rb#L39-46">following merb-core spec</a></p>
<p>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt><strong>5</strong><tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt></p>
<tt>
</tt>  it <span class="s"><span class="dl">"</span><span class="k">should allow you to restrict routes based on protocol</span><span class="dl">"</span></span> <span class="r">do</span><tt>
</tt>    <span class="co">Merb</span>::<span class="co">Router</span>.prepare <span class="r">do</span> |r|<tt>
</tt>      r.match(<span class="sy">:protocol</span> => <span class="s"><span class="dl">"</span><span class="k">https://</span><span class="dl">"</span></span>).to(<span class="sy">:controller</span> => <span class="s"><span class="dl">"</span><span class="k">foo</span><span class="dl">"</span></span>, <span class="sy">:action</span> => <span class="s"><span class="dl">"</span><span class="k">bar</span><span class="dl">"</span></span>)<tt>
</tt>      r.default_routes<tt>
</tt>    <span class="r">end</span><tt>
</tt>    route_to(<span class="s"><span class="dl">"</span><span class="k">/foo/bar</span><span class="dl">"</span></span>).should have_route(<span class="sy">:controller</span> => <span class="s"><span class="dl">"</span><span class="k">foo</span><span class="dl">"</span></span>, <span class="sy">:action</span> => <span class="s"><span class="dl">"</span><span class="k">bar</span><span class="dl">"</span></span>)<tt>
</tt>    route_to(<span class="s"><span class="dl">"</span><span class="k">/boo/hoo</span><span class="dl">"</span></span>, <span class="sy">:protocol</span> => <span class="s"><span class="dl">"</span><span class="k">https://</span><span class="dl">"</span></span>).should have_route(<span class="sy">:controller</span> => <span class="s"><span class="dl">"</span><span class="k">boo</span><span class="dl">"</span></span>, <span class="sy">:action</span> => <span class="s"><span class="dl">"</span><span class="k">hoo</span><span class="dl">"</span></span>)<tt>
</tt>  <span class="r">end</span><tt>
</tt>
</li>
</ul>
<p>You can set custom routes to only work when connected via SSL, that&rsquo;s just really nice!</p>
<ul>
<li>
<p>Other quick tip. <a href="https://railsontherun.com/2008/4/5/merb-tips-1">Last time</a> we saw how to install locally all the required gems. Well, you can also freeze merb by doing:</p>
<p>1<tt>
</tt>2<tt>
</tt></p>
<tt>
</tt>  merb-gen frozen-merb<tt>
</tt>
</li>
<li>
<p>Another common IRC question, how do I use Merb&rsquo;s logger. It&rsquo;s really easy:</p>
<p>1<tt>
</tt>2<tt>
</tt></p>
<tt>
</tt>  <span class="co">Merb</span>.logger.info(<span class="s"><span class="dl">'</span><span class="k">our stuff</span><span class="dl">'</span></span>)<tt>
</tt>
</li>
</ul>
<p>Where info is the debugging level you want to send your message to.</p>
<ul>
<li>Finally, today in IRC a Rails user asked how reset a session in Merb. Rails has a <em>reset_session</em> method that resets the session by clearing out all the objects stored within and initializing a new session object. Merb simply uses a hash to store sessions, so <em>session.clear</em> will do it ;)</li>
</ul>
<p>Feel free to add a comment with your Merb tips or leave a question regarding something you can&rsquo;t seem to be able to do with Merb.</p>
]]></content>
		</item>
		
		<item>
			<title>merb tips 1</title>
			<link>https://matt.aimonetti.net/posts/2008-04-merb-tips-1/</link>
			<pubDate>Sat, 05 Apr 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-04-merb-tips-1/</guid>
			<description>_* this content is now outdated and only applied to Merb 0.9_*
I&amp;rsquo;m working on a post reporting a recent benchmark I did comparing Rails vs Merb performances for a client&amp;rsquo;s app.
In the meantime, here are few tricks you might need when using Merb 0.9x
  In the init.rb file, uncomment and rename c[:session_id_key] (in the Merb::Config.use block)
  In the same block, add c[:log_level] = :debug to set a log level</description>
			<content type="html"><![CDATA[<p>_* this content is now outdated and only applied to Merb 0.9_*</p>
<p>I&rsquo;m working on a post reporting a recent benchmark I did comparing Rails vs Merb performances for a client&rsquo;s app.</p>
<p>In the meantime, here are few tricks you might need when using Merb 0.9x</p>
<ol>
<li>
<p>In the init.rb file, uncomment and rename <em>c[:session_id_key]</em>  (in the Merb::Config.use block)</p>
</li>
<li>
<p>In the same block, add <em>c[:log_level] = :debug</em>  to set a log level</p>
</li>
<li>
<p>By default, Merb logs to STDOUT, to log to a file, in the config block add <em>c[:log_file] = Merb.log_path + &lsquo;/development.log&rsquo;</em>  (note that you need to create the file yourself, Merb won&rsquo;t do that)</p>
</li>
<li>
<p>to save your gems locally, do: <em>sudo gem install gem_name -i gems</em></p>
</li>
<li>
<p>need basic HTTP auth? <a href="https://github.com/wycats/merb-core/tree/e690bb81bb550e58dad519712de050141b8552d8/lib/merb-core/controller/mixins/authentication.rb#L15-46">it&rsquo;s now available in core</a></p>
</li>
<li>
<p>don&rsquo;t forget to require any plugins, extra gems you need (such as <em>merb_helpers</em> or <em>merb-assets</em>)</p>
</li>
<li>
<p>don&rsquo;t forget to select your ORM before using the generator( so your generated goodies will be adapted to your ORM)</p>
</li>
<li>
<p>routes are easy to use. In the console (merb -i) type <em>merb.show_routes</em> to see all your named routes</p>
</li>
<li>
<p>if you want to use link_to, install <a href="https://github.com/wycats/merb-plugins/tree/master/merb_assets">merb_assets</a></p>
</li>
<li>
<p>nested routes example:</p>
</li>
</ol>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  r.resources &lt;span class=&quot;sy&quot;&gt;:channels&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |channels|&lt;tt&gt;
&lt;/tt&gt;    channels.resources &lt;span class=&quot;sy&quot;&gt;:shows&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |shows|&lt;tt&gt;
&lt;/tt&gt;     shows.resources &lt;span class=&quot;sy&quot;&gt;:episodes&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;   &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>usage:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  url(&lt;span class=&quot;sy&quot;&gt;:channel_shows&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:channel_id&lt;/span&gt; =&gt; channel)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  link_to h(channel.description), url(&lt;span class=&quot;sy&quot;&gt;:channel&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:id&lt;/span&gt; =&gt; channel)&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>That&rsquo;s it for today :)</p>
<p>In the meantime, check this <a href="https://mwrc2008.confreaks.com/02zygmuntowicz.html">Merb presentation by Ezra</a> and <a href="https://mwrc2008.confreaks.com/04katz.html">this DataMapper presentation by Wycats</a></p>
]]></content>
		</item>
		
		<item>
			<title>rails the duplo generation</title>
			<link>https://matt.aimonetti.net/posts/2008-03-rails-the-duplo-generation/</link>
			<pubDate>Mon, 17 Mar 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-03-rails-the-duplo-generation/</guid>
			<description>I&amp;rsquo;m sure, at least once in your life you played with Duplos.
Duplo bricks are eight times the size in volume, twice the length, height and width of traditional Lego bricks, and are easier to handle for younger children. Despite their size, they are still compatible with traditional Lego brick.
Duplos are great to introduce kids to the concept of Lego bricks and to get them to think about building their own creations.</description>
			<content type="html"><![CDATA[<p><img src="https://cache.lego.com/upload/contentTemplating/LifestyleProductsBags/otherfiles/1033/uploadF2767709-6EFA-4D99-93FA-13F75766309B.jpg" alt="duplo">
I&rsquo;m sure, at least once in your life you played with Duplos.</p>
<p><em>Duplo bricks are eight times the size in volume, twice the length, height and width of traditional Lego bricks, and are <strong>easier to handle for younger children</strong>. Despite their size, they are <strong>still compatible</strong> with traditional Lego brick.</em></p>
<p>Duplos are great to introduce kids to the concept of Lego bricks and to get them to think about building their own creations. However you would freak out if your kid would grow up and not want to start playing with Legos and building more advanced/custom stuff.</p>
<p>Unfortunately, that&rsquo;s exactly what&rsquo;s going on in the Rails community right now. We created a generation of Duplo developers.</p>
<p><strong>Rick Olson</strong>, AKA <a href="https://techno-weenie.net/">Technoweenie</a> fathered a great majority of this Duplo generation. Rick is a Rails core member and a prolific Rails plugin developer. He has written very popular plugins and Rails apps such as:</p>
<ul>
<li>
<p><a href="https://github.com/technoweenie/restful-authentication/tree">restful-authentication</a></p>
</li>
<li>
<p><a href="https://github.com/technoweenie/attachment_fu/tree">attachment_fu</a></p>
</li>
<li>
<p><a href="https://github.com/technoweenie/acts_as_versioned/tree">acts_as_versioned</a></p>
</li>
<li>
<p><a href="https://github.com/technoweenie/permalink_fu/tree">permalink_fu</a></p>
</li>
<li>
<p><a href="https://mephistoblog.com/">mephisto blog engine</a></p>
</li>
<li>
<p><a href="https://beast.caboo.se/">Beast forum</a></p>
</li>
</ul>
<p>If Rick is the father, the mother of this generation would obviously be <a href="https://www.loudthinking.com/">David Heinemeier Hansson</a>, creator of the Ruby on Rails framework. David has always wanted to make our lives easier, providing us with tools to avoid repeating ourselves and a mass-load of tools to create web apps in no time.</p>
<p>Rick, David and others worked hard to provide the community with tools that cut our development times by 20% to 30% and that&rsquo;s just awesome. They basically took their <a href="https://www.meccano.com/">meccano</a> applications and extracted Duplo blocks you can play with.</p>
<p>from <img src="https://upload.wikimedia.org/wikipedia/en/thumb/b/b5/Meccano_model_Steam_shovel_excavator.jpg/250px-Meccano_model_Steam_shovel_excavator.jpg" alt="meccano"> to <img src="https://upload.wikimedia.org/wikipedia/en/thumb/e/eb/Duplo_bricks.jpg/250px-Duplo_bricks.jpg" alt="Duplo"></p>
<p><strong>The problem is that a generation of Rubyists has grown up being used to getting everything pre written for them. They haven&rsquo;t yet passed the &ldquo;Duplo stage&rdquo; and basically write applications putting a few blocks together, only writing 10 to 20% and barely understand 5%.</strong></p>
<p>On top of that, what really annoys me is that, these very same developers complain about the existing plugins, always ask for more and don&rsquo;t give anything back to the community.</p>
<p>The problem is that it&rsquo;s always the same people giving and helping. Relatively quickly, the community grows and people supporting it get tired. I won&rsquo;t go as far as <a href="https://www.zedshaw.com/rants/rails_is_a_ghetto.html">Zed and his funny rant</a> but we need to wake up. We need to evolve, learn how Rails magic works, give up the <a href="https://www.therailsway.com/2007/8/1/dangers-of-cargo-culting">cargo culting</a> and start giving back.</p>
<p>The first thing would be to stop complaining about plugins you use on a daily basis and write your own or fork existing ones. <a href="https://github.com">GitHub</a> is a good place to start forking existing projects, if you are a Rails/Ruby beginner, you can help with documentation or submit small patches. <a href="https://hasmanythrough.com">Josh Susser</a> wrote a <a href="https://hasmanythrough.com/layingtracks/LayingTracks.pdf">nice tutorial</a> on how to commit changes (patches/documentation).</p>
<p>Why not blog about issues you have just faced and how you resolved them. Start writing small plugins/gems. Try helping people on the various mailing lists.</p>
<p>And finally, drop the Duplos and start playing with Legos - don&rsquo;t use plugins just because they are available to you, make sure you fully understand what the plugins you use do! Learn more about Rails guts and start using it in a way that makes sense to you.</p>
<p>Why not even switch to meccano and take a look at <a href="https://merbivore.com">Merb</a></p>
]]></content>
		</item>
		
		<item>
			<title>starting the migration to github</title>
			<link>https://matt.aimonetti.net/posts/2008-03-starting-the-migration-to-github/</link>
			<pubDate>Wed, 05 Mar 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-03-starting-the-migration-to-github/</guid>
			<description>I started moving some of my projects to GitHub.
Here is my GitHub account.
Projects moved to GitHub:
  GlobaLite
  ActiveRecord Backup
  mimetype-fu
  I&amp;rsquo;m planning on moving GoogleCharts, RandomWordGenerator and some not released stuff to GitHub so people can have fun forking my projects.
Git and GitHub are the new cool things. GitHub is planning on setting up a gem server while they are already offering tarball download and a post-receive hook.</description>
			<content type="html"><![CDATA[<p>I started moving some of my projects to <a href="https://github.com">GitHub</a>.</p>
<p><a href="https://github.com/matta">Here</a> is my <a href="https://github.com">GitHub</a> account.</p>
<p>Projects moved to <a href="https://github.com">GitHub</a>:</p>
<ul>
<li>
<p><a href="https://github.com/matta/globalite/tree">GlobaLite</a></p>
</li>
<li>
<p><a href="https://github.com/matta/ar-backup/tree">ActiveRecord Backup</a></p>
</li>
<li>
<p><a href="https://github.com/matta/mimetype-fu/tree">mimetype-fu</a></p>
</li>
</ul>
<p>I&rsquo;m planning on moving <a href="https://rubyforge.org/projects/googlecharts/">GoogleCharts</a>, <a href="https://rubyforge.org/projects/random-word-gen/">RandomWordGenerator</a> and some not released stuff to GitHub so people can have fun forking my projects.</p>
<p><a href="https://git.or.cz/">Git</a> and <a href="https://github.com">GitHub</a> are the new cool things. GitHub is planning on setting up a gem server while they are already offering tarball download and a post-receive hook. (they also plan on becoming myspace for geeks, but that&rsquo;s another story)</p>
<p>Do you have to switch to git and github? Honestly, &hellip;no you don&rsquo;t..
Git can act as SVN, but let&rsquo;s be honest, if you switch to a new SCM it needs to do more. I&rsquo;ve been using Git for a couple of months and even though I still don&rsquo;t have a full understanding of this SCM, I really enjoy using it.</p>
<p>So, get over it, learn on your own or purchase <a href="https://peepcode.com/products/git">this excellent peepcode</a></p>
<p>Email me to get a GitHub invite (Tom and Chris gave me some invites for readers) or/and try <a href="https://gitorious.org/">Gitorious</a>.</p>
<p>The fact that some major players (<a href="https://topfunky.com/">Topfunky</a>, <a href="https://weblog.techno-weenie.net/2008/3/4/my-gushing-github-love-letter">technoweenie</a>, <a href="https://errtheblog.com/">Chris &amp; PJ</a>, <a href="https://railstips.org/2008/2/16/git-and-github/">jnunemaker</a> and major projects such as <a href="https://weblog.rubyonrails.com/2008/2/28/capistrano-2-2-0">capistrano</a>, <a href="https://rubyhitsquad.com/Vlad_the_Deployer.html">vlad the deployer</a> and <a href="https://merbivore.com">Merb</a> use and support Git is a sign that it&rsquo;s the next big thing.</p>
<p>Also, I believe that a lot of developers will also be motivated to move their plugins/gems to GitHub because they simply can&rsquo;t always maintain their own libs and/or just hope people will fork their project and contribute back.</p>
]]></content>
		</item>
		
		<item>
			<title>how to use github and submit a patch</title>
			<link>https://matt.aimonetti.net/posts/2008-03-how-to-use-github-and-submit-a-patch/</link>
			<pubDate>Mon, 03 Mar 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-03-how-to-use-github-and-submit-a-patch/</guid>
			<description>If you don&amp;rsquo;t know about git and github yet, it&amp;rsquo;s time you clean up your RSS feeds and find some good source of information.
Github is used by the Merb core team and I&amp;rsquo;ll show you how to use github to fork Merb, make your modifications and &amp;ldquo;submit your patch&amp;rdquo;.
This is the exact reason why github is simply awesome, it makes forking projects just super simple and submitting changes even easier.</description>
			<content type="html"><![CDATA[<p>If you don&rsquo;t know about <a href="https://git.or.cz/">git</a> and <a href="https://github.com">github</a> yet, it&rsquo;s time you clean up your RSS feeds and find some good source of information.</p>
<p><a href="https://github.com">Github</a> is used by the <a href="https://merbivore.com">Merb core team</a> and I&rsquo;ll show you how to use github to fork Merb, make your modifications and &ldquo;submit your patch&rdquo;.</p>
<p>This is the exact reason why github is simply awesome, it makes forking projects just super simple and submitting changes even easier.</p>
<p>First thing, you need to have a github account, if you don&rsquo;t have one yet, email me, I have a couple of invitations left, otherwise, just wait until github gets public.</p>
<p>Now, let&rsquo;s go to <a href="https://github.com/wycats/merb-core/tree/master">Merb&rsquo;s repository</a> and fork Merb-core by clicking on the fork button.</p>
<p><img src="https://img.skitch.com/20080303-q2aceaadcqk59kqck4b199bdmh.jpg" alt="fork merb"></p>
<p>Actually, for this example, I&rsquo;ll fork <a href="https://github.com/wycats/merb-plugins/tree/master">merb-plugins</a> because I want to improve the ActiveRecord rake tasks.</p>
<p>Because I forked merb-plugins, I now have my own forked repo: !<img src="https://img.skitch.com/20080303-g8jas46gq1enn9fhu1t7rsyunj.jpg" alt="my forked repo"></p>
<p>I&rsquo;ll start by checking out/cloning my forked repo locally.</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




git clone git&lt;span class=&quot;iv&quot;&gt;@github&lt;/span&gt;.com&lt;span class=&quot;sy&quot;&gt;:mattetti&lt;/span&gt;/merb-plugins.git
</code></pre>
<p>!<img src="https://img.skitch.com/20080303-rf87t44c3c6m6hqy5b38ksycua.jpg" alt="git clone"></p>
<p>Great I can now make my own changes&hellip;. but wait, what if the merb core team makes a change to the code? Well, I need to track their changes. Here is how:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




git remote add coreteam git&lt;span class=&quot;sy&quot;&gt;:/&lt;/span&gt;/github.com/wycats/merb-plugins.git
</code></pre>
<p>FYI, it adds the following to edit .git/config:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  [remote &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;coreteam&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;  url = git&lt;span class=&quot;sy&quot;&gt;:/&lt;/span&gt;/github.com/wycats/merb-plugins.git&lt;tt&gt;
&lt;/tt&gt;  fetch = +refs/heads/*&lt;span class=&quot;sy&quot;&gt;:refs&lt;/span&gt;/remotes/coreteam/*&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>then</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




git fetch coreteam
</code></pre>
<p>and finally</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




git checkout -b coreteam coreteam/master
</code></pre>
<p>You can now track the latest change and merge them with your branch. Note that you can also track other forks and merge some other changes. (just that feature is worth using git)</p>
<p>Alright, now you can do your stuff, and push your local change to your remote repo at github.</p>
<p>Once you are done, you can simply click on the &ldquo;pull request button&rdquo;</p>
<p><img src="https://img.skitch.com/20080303-xxh5d3a2uu65ksf8u4i9tga59e.jpg" alt="pull request button"></p>
<p>fill up the form and select the recipient. (wycats in this example if you want him to merge your changes into the official version of Merb).</p>
<p><img src="https://img.skitch.com/20080303-dei7bxpt577gqe3d1x4ncpmq6w.jpg" alt="pull request"></p>
<p>p.s: The github guys are working on a gem to make our loves easier, give <a href="https://github.com/defunkt/github-gem/tree/master">https://github.com/defunkt/github-gem/tree/master</a> a try. I&rsquo;ll post about the gem when it will be a bit more stable.</p>
]]></content>
		</item>
		
		<item>
			<title>resolving git svn conflicts</title>
			<link>https://matt.aimonetti.net/posts/2008-02-resolving-git-svn-conflicts/</link>
			<pubDate>Fri, 29 Feb 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-02-resolving-git-svn-conflicts/</guid>
			<description>I&amp;rsquo;ve been using git and git-svn for a little while and never had a problem&amp;hellip; until today.
On one of my project, we have a SVN repo but since I prefer using Git, I&amp;rsquo;m using git-svn.
Git-svn has been great, it let me create my own local branches for each new set of features (that&amp;rsquo;s when I don&amp;rsquo;t forget to create a branch) and to commit all the changes back to svn.</description>
			<content type="html"><![CDATA[<p>I&rsquo;ve been using <a href="https://git.or.cz/">git</a> and <a href="https://www.kernel.org/pub/software/scm/git/docs/git-svn.html">git-svn</a> for a little while and never had a problem&hellip; until today.</p>
<p>On one of my <a href="https://gumgum.com">project</a>, we have a SVN repo but since I prefer using Git, I&rsquo;m using git-svn.</p>
<p>Git-svn has been great, it let me create my own local branches for each new set of features (that&rsquo;s when I don&rsquo;t forget to create a branch) and to commit all the changes back to svn.</p>
<p>The problem today happened after I did a simple git-svn rebase. I had some sort of error and my local repo looked like it got reverted to the head of the svn repo&hellip;.</p>
<pre><code>&lt;code&gt;error: patch failed: trunk/app/models/view.rb:1
error: trunk/app/models/view.rb: patch does not apply
[blah blah]
sing index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
&lt;/code&gt;
</code></pre>
<p>I hadn&rsquo;t committed to SVN for 24 hours and had a lot of work that was just checked in locally&hellip; You can imagine the panic.  <a href="https://notch8.com">Rob</a> started digging in the .git repo to finally find the hash representing the latest delta before the rebase. With the help of the #caboose guys, I did a simple</p>
<pre><code>&lt;code&gt;git reset --hard hash-name
&lt;/code&gt;
</code></pre>
<p>Which restore my repo to the pre SVN commit state. Awesome&hellip; however I still had issues to commit my stuff. After a little while I as able to commit again, worked a bit more and tried to commit again&hellip;. same error :(</p>
<p>But this time I noticed I could simply do</p>
<pre><code>&lt;code&gt;git rebase --abort
&lt;/code&gt;
</code></pre>
<p>to restore the original branch.an</p>
<p>But I still couldn&rsquo;t commit properly&hellip; until I discovered that I just needed to fix the conflicts manually using</p>
<pre><code>&lt;code&gt;git-mergetool
&lt;/code&gt;
</code></pre>
<p>git-mergetool uses whichever merge tool available: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff filemerge</p>
<p>I fixed my conflicts in no time, then did a</p>
<pre><code>&lt;code&gt;git rebase --continue
&lt;/code&gt;
</code></pre>
<p>and finally</p>
<pre><code>&lt;code&gt;git-svn dcommit
&lt;/code&gt;
</code></pre>
<p>Looking back, I wish I knew how to properly deal with conflicts when using git-svn, I wasted a bit of my precious time ;)  hopefully this post will help you.</p>
<p>p.s:  <a href="https://brian.maybeyoureinsane.net/blog/2008/01/31/git-sake-tasks/">here</a> is an interesting use of Sake to handle git-svn</p>
]]></content>
		</item>
		
		<item>
			<title>gumgum launch or how to avoid a disastrous launch</title>
			<link>https://matt.aimonetti.net/posts/2008-02-gumgum-launch-or-how-to-avoid-a-disastrous-launch/</link>
			<pubDate>Thu, 28 Feb 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-02-gumgum-launch-or-how-to-avoid-a-disastrous-launch/</guid>
			<description>For the last few months I worked on a Rails app called GumGum. GumGum is a licensing and distribution platform for online content. GumGum believes paying a flat rate to license content for online use is illogical. Offline, the flat rate model works because distribution is finite. Online, thanks to Google and other search engines, a story lives forever. GumGum has developed two usage models to fairly monetize a license: pay-per-use and ad supported.</description>
			<content type="html"><![CDATA[<p>For the last few months I worked on a Rails app called <a href="https://gumgum.com">GumGum</a>. <a href="https://gumgum.com">GumGum</a> is a licensing and distribution platform for online content. <a href="https://gumgum.com">GumGum</a> believes paying a flat rate to license content for online use is illogical. Offline, the flat rate model works because distribution is finite. Online, thanks to Google and other search engines, a story lives forever. <a href="https://gumgum.com">GumGum</a> has developed two usage models to fairly monetize a license: pay-per-use and ad supported. Pay-per-use allows publishers to license content on a CPM basis. Ad supported subsidizes the licensing revenue through advertisements, providing the publisher a free license.</p>
<p>Simple concept and great team. When Ari Mir and Ophir Tanz approached me to work on their app I was impressed by their understanding of Web Business. It was not their first start up and as a consultant, you usually prefer to work with some experienced clients. Ari, GumGum&rsquo;s CPO was great at defining realistic expectations, and limit the scope of the application which was great since I&rsquo;m an Agile/XP fanboy. I believe that really helped us meeting our dead line without feature creeping the app.</p>
<p>We were finally ready to enter a public beta phase, we were running our production server on a godaddy VPS (no comment) and were on the process of migrating to <a href="https://www.slicehost.com/">slicehost</a> where we were running our staging environment. The plan was to go public on Tuesday 12 and have a feel for the load. We also setup an <a href="https://www.amazon.com/gp/browse.html?node=201590011">EC2</a> image to handle some of the background tasks and were thinking of moving to <a href="https://engineyard.com">Engine Yard</a> within few months.</p>
<p>Everything was ready for a launch, when the day before D Day, Ari calls me telling me: &ldquo;Good news Matt, <a href="https://www.techcrunch.com/">TechCrunch</a> is going to publish a blog post about us!&rdquo;. While he sounded really excited, I couldn&rsquo;t believe me ears.</p>
<ol>
<li>
<p>The app wasn&rsquo;t optimized, darn it all, I hadn&rsquo;t even properly indexed the database, no caching, nothing. (it was in the backlog, things I was planning on doing after the public beta launch)</p>
</li>
<li>
<p>We would never be able to handle the load. Running an app like ours definitely needs more than a 256Mb shared CPU shared host.</p>
</li>
<li>
<p>Ari asked me if they could embed one of our license object in <a href="https://www.techcrunch.com/">TechCrunch</a> home page.</p>
</li>
<li>
<p>I had 12 hours to get stuff ready.</p>
</li>
</ol>
<h1 id="trying-to-be-ready">Trying to be ready:</h1>
<p><a href="https://www.techcrunch.com/">TechCrunch</a> has 688k <a href="https://feeds.feedburner.com/Techcrunch">RSS subscribers</a>! Even though I asked Ari not to embed one of our protected object inside TC&rsquo;s home page, I knew he couldn&rsquo;t say no to <a href="https://www.techcrunch.com/about-michael-arrington/">Mike Arrington</a>. (little did I know, they would end up embedding 2 licenses)</p>
<p>I hurried up and started properly indexing the database, ask advice to some of my <a href="https://blog.caboo.se/">cabooser</a> friends, did some quick re-factoring but obviously didn&rsquo;t have enough time to rewrite the way we handle tags and tooltips (the overlay popup window that displays when you rollover a picture in our browse page). <a href="https://notch8.com">Rob</a> helped me getting ready and we transformed our staging environment into a secondary production server hoping we would split the load.</p>
<p>Since we didn&rsquo;t have a load balancer, we tried to cheat by setting up two A records for gumgum.com. The idea was that browsers would pick an ip randomly and since we were only using 1 database, everything should be fine. That was the theory, during our tests we realized that our Flash object was not using the same IP than the webpage and that was creating random issues with our licensing system.</p>
<p>We were running out of time, I turned on page caching on few actions (home page) so even though my mongrels would die, I knew we would at least be able to display something. Because of our complex authentication system, I couldn&rsquo;t cache much and I didn&rsquo;t have time to re-factor a lot of my code or to setup <a href="https://www.danga.com/memcached/">memcached</a>. (on top of that I knew the product was stable and I didn&rsquo;t want to mess up with it).</p>
<h1 id="the-storm">The Storm:</h1>
<p><a href="https://www.techcrunch.com/2008/02/13/gumgum-launches-new-image-licensing-platform/">The article got published</a> and in seconds we saw the load on the main box going from 0.2 to 2.0! We were still dealing with the DNS issues and some pictures were not getting loaded. When Rails got above 60 req/s we started dropping some requests and returning 500s. That was bad, really bad. Our browse page (not optimized) was down and we handled around 80k requests in a matter of few hours. What you don&rsquo;t know is that each of our flash object generates a couple of requests, and that <a href="https://techcrunch.com">TechCrunch</a> decided to embed 2 objects on their home page.</p>
<p>Remember, it was our launch, which was not meant to be a big launch, we were not prepared for that!</p>
<h1 id="dealing-with-the-load">Dealing with the load:</h1>
<p>The good thing is that my code didn&rsquo;t leak memory, Rails was stable and it was a good sign. We all know that &ldquo;Rails CAN scale&rdquo;, but we also know that you need to have a proper hosting to do that. Godaddy was not handling the load and it was just the beginning. So what do you do when you have to scale and that your code isn&rsquo;t total junk? You call a real hosting company like <a href="https://engineyard.com">EngineYard</a> or <a href="https://joyent.com">Joyent</a>. I was lucky <a href="https://www.workingwithrails.com/person/5421-ezra-zygmuntowicz">Ezra</a> was online. I quickly explained to him the situation, we discussed the reason why our site was not doing so great and defined the bottlenecks. It was simple, we needed more humph. The normal waiting time to get a slice on EY was around 2 weeks back then. Ezra knew that we couldn&rsquo;t wait 2 weeks :p He was simply awesome, managed to find us 2 slices, set them up for us and setup our app in less than 2 hours. He even helped us configuring our old server to get NginX to bounce the requests to EY while the DNS was propagating.</p>
<p>As soon as the switch was done, everything loaded perfectly, not a single request dropped, it was simply great.</p>
<p>Since we are talking about scaling, hosting and facing issues, I&rsquo;d like to make a simple point: $349.00 a month for a slice is NOT expensive for what you get. First off, EY slices are setup superbly, you get awesome performances out of them, they come ready for your app and you don&rsquo;t have to do much. Secondly, I&rsquo;m not a sys admin, I really hate dealing with servers, packages, configuration, compiling crap that won&rsquo;t compile because I&rsquo;m lame&hellip; etc&hellip;</p>
<p>EY has a bunch of experts (both Ruby and Sys admin experts) available 24/7 that always go the extra mile to help you. Last time I checked I couldn&rsquo;t hire a good sys admin for, let&rsquo;s say the price of 3 or 4 slices. Now, we get a team of guys, available, knowing their stuff and helping me for way cheaper than hiring a sys admin dude. The other thing is, I&rsquo;m a consultant, I don&rsquo;t want to deal with servers and charge my clients for that. I also want them to be reassured and know that &ldquo;yes, we can scale&rdquo;. The price of an EY/Joyent slice is the price you pay to be confident you can take the load.</p>
<h1 id="so-what-now">So what now?</h1>
<p>We have a lot of optimization to do, we are working on moving more of our stuff to EC2 to avoid being charged for bandwidth twice (user =&gt; EY =&gt; S3), we are setting up a queuing system and we have a lot of nice features to deploy. But one thing for sure, I can focus on my code since I know EY has my back and I don&rsquo;t have to worry about our servers.</p>
<p>p.s: <a href="https://gumgum.com">GumGum</a> is doing great, a lot of people are really interested in the product, new features are coming up (we already auto import content from some major Paparazzi agencies) and we are getting a <a href="https://blog.gumgum.com/2008/02/gumgums-press.html">good press coverage</a></p>
]]></content>
		</item>
		
		<item>
			<title>misc tips and tricks</title>
			<link>https://matt.aimonetti.net/posts/2008-01-misc-tips-and-tricks/</link>
			<pubDate>Wed, 30 Jan 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-01-misc-tips-and-tricks/</guid>
			<description>I haven&amp;rsquo;t posted for quite a long time. The thing is I moved to a new place and I&amp;rsquo;m really busy on working clients + setting up my new office + dealing with way too much paperwork.
Anyway, enough excuses, here are few tips that I believe will be useful to some of you:
ZenTest Autotest I love autotest, but you might have noticed that sometimes (especially on big projects), ZenTest might start using more CPU than expected.</description>
			<content type="html"><![CDATA[<p>I haven&rsquo;t posted for quite a long time. The thing is I moved to a new place and I&rsquo;m really busy on working clients + setting up my new office + dealing with way too much paperwork.</p>
<p>Anyway, enough excuses, here are few tips that I believe will be useful to some of you:</p>
<h2 id="zentest-autotesthttpswwwzenspidercomzssproductszentest"><a href="https://www.zenspider.com/ZSS/Products/ZenTest/">ZenTest Autotest</a></h2>
<p>I love autotest, but you might have noticed that sometimes (especially on big projects), ZenTest might start using more CPU than expected. On my machine, that results in the fan going off and annoying the crap out of me.</p>
<p>The solution is quite simple, exclude all folders you don&rsquo;t need to monitor. To do that, update ZenTest to version 3.8.X</p>
<pre><code>&lt;code&gt;sudo gem update ZenTest
&lt;/code&gt;
</code></pre>
<p>(older version had a different syntax)</p>
<p>Now, edit your .autotest that should be located in ~/.autotest  (if it doesn&rsquo;t exist, create it).</p>
<p>Finally add the following code:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;Autotest&lt;/span&gt;.add_hook &lt;span class=&quot;sy&quot;&gt;:initialize&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |at|&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%w{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;.svn .hg .git vendor&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;}&lt;/span&gt;&lt;/span&gt;.each {|exception| at.add_exception(exception)}&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>I personally freeze rails in vendor and I autotest is way happier when it doesn&rsquo;t have to monitor some extra files. (note that we also exclude folders such as .git or .svn)
(you can also include files etc&hellip; read more <a href="https://blog.davidchelimsky.net/articles/2008/01/15/rspec-1-1-2-and-zentest-3-8-0">there</a>)</p>
<h2 id="rspechttpsrspecinfo"><a href="https://rspec.info">RSpec</a></h2>
<p>RSpec is certainly my favorite Ruby tool and I&rsquo;m glad to say that most of my <a href="https://sdruby.com/">SD.rb</a> friends finally got convinced!</p>
<p>Now, few people complained to me about spec failures outputting the full stack such as:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt; &lt;span class=&quot;co&quot;&gt;The&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;Sessions&lt;/span&gt; controller should fail since it&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;s a test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;FAILED&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; expected &lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt;, got &lt;span class=&quot;pc&quot;&gt;false&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/expectations.rb:&lt;span class=&quot;i&quot;&gt;52&lt;/span&gt;&lt;span class=&quot;sy&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fail_with'&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/expectations/handler.rb:21:in &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;/span&gt;handle_matcher&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/expectations/extensions/object.rb:34:in `should&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; ./spec/controllers/sessions_controller_spec.rb:&lt;span class=&quot;i&quot;&gt;25&lt;/span&gt;:&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_methods.rb:&lt;span class=&quot;i&quot;&gt;78&lt;/span&gt;&lt;span class=&quot;sy&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;instance_eval'&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_methods.rb:78:in &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;/span&gt;run_with_description_capturing&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_methods.rb:19:in `execute&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; &lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;opt&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;local/lib/ruby/&lt;span class=&quot;fl&quot;&gt;1.8&lt;/span&gt;/timeout.rb:&lt;span class=&quot;i&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;sy&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;timeout'&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_methods.rb:16:in &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;/span&gt;execute&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:288:in `execute_examples&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:&lt;span class=&quot;i&quot;&gt;287&lt;/span&gt;&lt;span class=&quot;sy&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;each'&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:287:in &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;/span&gt;execute_examples&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/example/example_group_methods.rb:121:in `run&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:&lt;span class=&quot;i&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;sy&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;run'&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:21:in &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;/span&gt;each&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/runner/example_group_runner.rb:21:in `run&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/runner/options.rb:&lt;span class=&quot;i&quot;&gt;89&lt;/span&gt;&lt;span class=&quot;sy&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;run_examples'&lt;tt&gt;
&lt;/tt&gt; test_app-git/trunk/vendor/plugins/rspec/lib/spec/runner/command_line.rb:19:in &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;/span&gt;run&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt; script/spec:4:&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  Finished in 6.035147 seconds&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  400 examples, 1 failure&lt;tt&gt;
&lt;/tt&gt;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>We can really easily change that, open you spec.opts file located in your spec folder.</p>
<p>it probably looks like that:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  --colour&lt;tt&gt;
&lt;/tt&gt;  --format&lt;tt&gt;
&lt;/tt&gt;  progress&lt;tt&gt;
&lt;/tt&gt;  --loadby&lt;tt&gt;
&lt;/tt&gt;  mtime&lt;tt&gt;
&lt;/tt&gt;  --reverse&lt;tt&gt;
&lt;/tt&gt;  --backtrace&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>Get rid of &ldquo;&ndash;backtrace&rdquo; and your new failure should look like:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;The Sessions controller The Sessions controller should fail since it&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;s a test&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; FAILED&lt;tt&gt;
&lt;/tt&gt;  expected false, got true&lt;tt&gt;
&lt;/tt&gt;  ./spec/controllers/sessions_controller_spec.rb:25:&lt;tt&gt;
&lt;/tt&gt;  script/spec:4:&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  Finished in 0.269956 seconds&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  15 examples, 1 failure&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<h2 id="other-stuff-you-may-find-interesting-in-no-particular-order">Other stuff you may find interesting (in no particular order):</h2>
<ul>
<li>
<p><a href="https://opensource.thinkrelevance.com/wiki/spec-converter">spec converter</a></p>
</li>
<li>
<p><a href="https://cells.rubyforge.org/overview.html">Rails Cell</a></p>
</li>
<li>
<p><a href="https://jointheconversation.org/railsgit">Git to manage and deploy a Rails app</a></p>
</li>
<li>
<p><a href="https://rufy.com/contacts/doc/">contacts (retrieve user&rsquo;s contacts from yahoo, gmail etc..)</a></p>
</li>
<li>
<p><a href="https://www.hashrocket.com/">Hashrocket</a></p>
</li>
<li>
<p><a href="https://www.amazon.com/Rails-Way-Addison-Wesley-Professional-Ruby/dp/0321445619">one of the best Rails book of the moment</a></p>
</li>
<li>
<p><a href="https://famspam.com/">err&rsquo;s new baby</a></p>
</li>
<li>
<p><a href="https://blog.caboo.se/articles/2008/1/30/caboose-conf-2008">caboose conf 08</a></p>
</li>
<li>
<p><a href="https://github.com/">git hub</a></p>
</li>
<li>
<p><a href="https://swxruby.org/">SWX Ruby (or how to get Rails to talk with Flash even faster)</a></p>
</li>
<li>
<p><a href="https://ruby.reddit.com">Ruby Reddit</a></p>
</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>rspec on rails matchers plugin</title>
			<link>https://matt.aimonetti.net/posts/2008-01-rspec-on-rails-matchers-plugin/</link>
			<pubDate>Fri, 04 Jan 2008 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2008-01-rspec-on-rails-matchers-plugin/</guid>
			<description>RSpec is an awesome testing framework. On top of being the first Ruby BDD framework the core team is doing a great job in enhancing our testing experience and therefore the quality of our code.
This time, I don&amp;rsquo;t want to introduce to the latest changes but instead showing you what Josh Knowles, Bryan Helmkamp and myself came up with.
RSpec on Rails matchers plugin + TextMate Bundle
Matchers are some sort of helpers that will help you cleaning up your tests.</description>
			<content type="html"><![CDATA[<p><a href="https://rspec.info">RSpec</a> is an awesome testing framework. On top of being the first Ruby <a href="https://en.wikipedia.org/wiki/Behavior_driven_development">BDD</a> framework the core team is doing a great job in enhancing our testing experience and therefore the quality of our code.</p>
<p>This time, I don&rsquo;t want to introduce to the <a href="https://rspec.info/changes.html">latest changes</a> but instead showing you what <a href="https://joshknowles.com">Josh Knowles</a>, <a href="https://www.brynary.com/">Bryan Helmkamp</a> and myself came up with.</p>
<p><a href="https://code.google.com/p/rspec-on-rails-matchers/">RSpec on Rails matchers plugin</a> + <a href="https://rspec-on-rails-matchers.googlecode.com/svn/textmate-bundle/RSpecOnRailsMatchers.tmbundle.zip">TextMate Bundle</a></p>
<p>Matchers are some sort of helpers that will help you cleaning up your tests. We simply came up with a collection of matchers that we think will make your like easier.</p>
<p>Categories = [</p>
]]></content>
		</item>
		
		<item>
			<title>retrospective on freelancing consulting</title>
			<link>https://matt.aimonetti.net/posts/2007-12-retrospective-on-freelancing-consulting/</link>
			<pubDate>Mon, 31 Dec 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-12-retrospective-on-freelancing-consulting/</guid>
			<description>Being a consultant is great, being a consultant working exclusively with Ruby is awesome, being a Ruby consultant using Agile methods on great projects with cool clients is just super-awesome. The English language doesn&amp;rsquo;t seem to have a word/expression defining this feeling without using the &amp;ldquo;f-word&amp;rdquo; (at least, there&amp;rsquo;s nothing I can think of right now) I have to say that I owe a lot to the Ruby community and especially the Rails core team.</description>
			<content type="html"><![CDATA[<p>Being a consultant is great, being a consultant working exclusively with Ruby is awesome, being a Ruby consultant using Agile methods on great projects with cool clients is just super-awesome. The English language doesn&rsquo;t seem to have a word/expression defining this feeling without using the &ldquo;f-word&rdquo; (at least, there&rsquo;s nothing I can think of right now)
I have to say that I owe a lot to the Ruby community and especially the Rails core team. Without you/them, I wouldn&rsquo;t be able to do what I do and I would certainly not have so much fun.</p>
<p>Enough blahblah, a retrospective wouldn&rsquo;t be a retrospective if I wouldn&rsquo;t look at ways to improve the process.</p>
<p>Looking at back on 2007, I&rsquo;ll look at what I did good and where I could have done better.</p>
<p><strong>communication wise</strong>, I think things worked out quite well.</p>
<h2 id="daily-stand-up">Daily stand up</h2>
<p>The <strong>daily stand up/scrum</strong> proved to be very efficient on all projects. it usually takes a short adaptation time on the clients side, but once everybody is on the same page, <strong>meetings are short and efficient</strong>.</p>
<h2 id="iterations">Iterations</h2>
<p>Clients adapted more or less well to the whole <strong>Iteration process</strong>. On some occasions, I ended up being in charge of managing iterations, confirming my suggestions with the client during our iteration planning. I wish I was able to get all my clients to fully understand and enjoy the process, but oh well, the reality is that some clients just want the work done and don&rsquo;t care too much how you do it.
In general iteration planning sessions went quite well, they really helped us defining priorities and manage the budget. However, <strong>I feel the need to bring more structure into these meetings</strong>.</p>
<h2 id="weekly-retrospectives">Weekly Retrospectives</h2>
<p>Retrospectives/demos could really be improved. I have to admit that I was not able to organize a single great retrospective with my clients. That&rsquo;s one major draw back of working remotely and being a contractor.
Since I would deploy few times a week, the weekly demo didn&rsquo;t always made sense. I therefore decided to use <a href="https://www.jingproject.com/">Jing</a> and create a weekly screencast of the iteration changes. This way my clients know exactly what was done and can test whenever they want. We still have our demos from time to time especially when major new features are implemented.
In 2008, <strong>I really want to improve clients' retrospective</strong>.</p>
<h2 id="tools">Tools</h2>
<p>While lighthouse helped me keeping track of my iteration user stories, unfortunately, I noticed that clients got confused when using the same tool to report bugs and to manage iterations. I&rsquo;ll still be using lighthouse for bug reports but or I will have to finish my agile project manager or I&rsquo;ll use <a href="https://joshknowles.com">Josh Knowles'</a> of he finally releases his software ;)</p>
<p>Bdd/Rspec was a big winner in &lsquo;07. People might argue about the real benefit of RSpec vs test unit. Well, I can only talk about my own experience, after using RSpec for a year, the way I write my applications totally changed. TDD certainly became a reality. Even my relationship with my clients changed. I now get my clients to write my tests, well, not exactly but almost. I get them to define the expected behaviors using the usual it..should..do syntax. I then just need to transpose my clients expectations in contextualized specs. once the iteration is over, I output a spec report that i give to my client. I never had so much fun writing tests!</p>
<p>One thing I need to focus on in 08: ajax &amp; js tests!</p>
<p>Talking about JavaScript, I finally found a way to write Js and have fun. <a href="https://lowpro.stikipad.com">Lowpro</a> totally changed my view of Js and I can&rsquo;t wait to push things further.(my <a href="https://sdruby.com/">December talk</a> on Unobtrusive Javascript should be online sometimes soon)</p>
<p>Talking about pushing things further, I need to see if I can totally dish svn and only use git + gitosis. if you didn&rsquo;t check Git yet, go check on the awesome <a href="https://peepcode.com/products/git">peepcode</a> put together by <a href="https://nubyonrails.com/">topfunky</a>.</p>
<h2 id="misc-things-that-didnt-work-that-well">Misc things that didn&rsquo;t work that well:</h2>
<ul>
<li>
<p>unreliable subcontractors</p>
</li>
<li>
<p>hard to find designers</p>
</li>
<li>
<p>having to say no to so many cool projects (always a good problem to have though)</p>
</li>
</ul>
<h2 id="various-things-that-i-enjoyed">Various things that I enjoyed:</h2>
<ul>
<li>
<p><a href="https://www.joyent.com/accelerator">Joyent accelerators</a></p>
</li>
<li>
<p><a href="https://twitter.com/">twitter</a></p>
</li>
<li>
<p><a href="https://sdruby.com/">sd.rb</a></p>
</li>
<li>
<p><a href="https://www.zenspider.com/ZSS/Products/ZenTest/">autotest</a></p>
</li>
<li>
<p><a href="https://www.apple.com/iphone/">iPhone</a>
(and probably a lot other stuff that I can&rsquo;t remember right now)</p>
</li>
</ul>
<h2 id="major-changes-planned-for-08">Major changes planned for 08:</h2>
<ul>
<li>
<p>pairing with another <a href="https://workingwithrails.com/person/8526-robert-kaufman">local developer</a> complementing my skills.</p>
</li>
<li>
<p>better weekly retrospectives</p>
</li>
<li>
<p>tech lunch at least once a month</p>
</li>
<li>
<p>learn Erlang or another programming language</p>
</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>timezone selection</title>
			<link>https://matt.aimonetti.net/posts/2007-12-timezone-selection/</link>
			<pubDate>Fri, 21 Dec 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-12-timezone-selection/</guid>
			<description>Supporting TimeZones is a serious pain in a developer&amp;rsquo;s neck. Thankfully, Rails comes with a bunch of tools making our life easier. One of my Rails patch just got merged in Rails Edge (Future Rails 2.1) and I believe it will make my life just a tiny be more enjoyable.
Let&amp;rsquo;s look at a simple scenario, your application has many users and each user has the option of setting his own TimeZone.</description>
			<content type="html"><![CDATA[<p>Supporting TimeZones is a serious pain in a developer&rsquo;s neck. Thankfully, Rails comes with a bunch of tools making our life easier. One of my Rails patch <a href="https://dev.rubyonrails.org/changeset/8473">just got merged</a> in Rails Edge (Future Rails 2.1)  and I believe it will make my life just a tiny be more enjoyable.</p>
<p>Let&rsquo;s look at a simple scenario, your application has many users and each user has the option of setting his own TimeZone. Most of your users are in the US and actually on the West Coast. You probably don&rsquo;t want to list all the time zones on earth, and you don&rsquo;t really want to include a blank option. What we want is to have a list of top priority time zones (US zones) and to pre select the most comment zone. (L.A. / PST)</p>
<p>I won&rsquo;t go into TZ support in the back-end, check <a href="https://weblog.jamisbuck.org/2007/2/2/introducing-tztime">this post</a>, <a href="https://www.caboo.se/articles/2007/2/23/adding-timezone-to-your-rails-app">this other one</a> or yet <a href="https://www.marklunds.com/articles/one/311">that one</a> for more information.</p>
<p>Let&rsquo;s look at our views, option one, you want to use the Rails built-in TimeZones:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;




&lt;% form_for &lt;span class=&quot;sy&quot;&gt;:user&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |f| -&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;p&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;label &lt;span class=&quot;r&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;co&quot;&gt;Name&lt;/span&gt;: &lt;em&gt;(full name)&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;em&gt;&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;label&gt;&lt;br/&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;%= f.text_field &lt;span class=&quot;sy&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;/p&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;p&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;label&gt;&lt;span class=&quot;co&quot;&gt;Default&lt;/span&gt; timezone&lt;span class=&quot;sy&quot;&gt;:&lt;&lt;/span&gt;/label&gt;&lt;br/&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;%= f.time_zone_select (&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;time_zone&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;co&quot;&gt;TimeZone&lt;/span&gt;.us_zones, &lt;tt&gt;
&lt;/tt&gt;                                          &lt;span class=&quot;sy&quot;&gt;:default&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Pacific Time (US &amp; Canada)&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;) &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;/p&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;div &lt;span class=&quot;r&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;%= submit_tag &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;/div&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;% &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; -&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p><img src="https://myskitch.com/matt_a/time_zone_select-20071221-182928.jpg" alt="builtin timezones"></p>
<p>Option 2, we are using <a href="https://rubyforge.org/projects/tzinfo/">TZinfo</a>:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;




&lt;% form_for &lt;span class=&quot;sy&quot;&gt;:user&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |f| -&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;p&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;label &lt;span class=&quot;r&quot;&gt;for&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;co&quot;&gt;Name&lt;/span&gt;: &lt;em&gt;(full name)&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;em&gt;&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;label&gt;&lt;br/&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;%= f.text_field &lt;span class=&quot;sy&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;/p&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;p&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;label&gt;&lt;span class=&quot;co&quot;&gt;Default&lt;/span&gt; timezone&lt;span class=&quot;sy&quot;&gt;:&lt;&lt;/span&gt;/label&gt;&lt;br/&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;%= f.time_zone_select(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;time_zone&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;co&quot;&gt;TZInfo&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Timezone&lt;/span&gt;.us_zones, &lt;tt&gt;
&lt;/tt&gt;                                         &lt;span class=&quot;sy&quot;&gt;:default&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;America/Los_Angeles&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;tt&gt;
&lt;/tt&gt;                                         &lt;span class=&quot;sy&quot;&gt;:model&lt;/span&gt; =&gt; &lt;span class=&quot;co&quot;&gt;TZInfo&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Timezone&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;/p&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;div &lt;span class=&quot;r&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;actions&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;%= submit_tag &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;/div&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;% &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; -&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p><img src="https://myskitch.com/matt_a/timezone_select_tzinfo-20071221-183443.jpg" alt="TZinfo"></p>
<p>Obviously, the default timezone is used only if the user didn&rsquo;t set one already.</p>
<p>Pretty simple feature but hopefully quite helpful!</p>
]]></content>
		</item>
		
		<item>
			<title>rails 2 0 2 with few changes</title>
			<link>https://matt.aimonetti.net/posts/2007-12-rails-2-0-2-with-few-changes/</link>
			<pubDate>Mon, 17 Dec 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-12-rails-2-0-2-with-few-changes/</guid>
			<description>What&amp;rsquo;s new?   Rails default database is now sqlite3. If you are running Leopard, everything is already setup for you. As DHH mentioned, just &amp;ldquo;rails -d mysql your_app_name&amp;rdquo; if you want to generate a new app preconfigured for MySQL. Sqlite3 is great and if the only reason why you didn&amp;rsquo;t give it a try is because you have to use CocoaMySQL, then check out sqlitebrowser
  Other new feature: rake secret to generate a key used to encrypt your session.</description>
			<content type="html"><![CDATA[<h2 id="whats-new">What&rsquo;s new?</h2>
<ul>
<li>
<p>Rails default database is now sqlite3. If you are running Leopard, everything is already setup for you. As DHH mentioned, just &ldquo;rails -d mysql your_app_name&rdquo; if you want to generate a new app preconfigured for MySQL.
Sqlite3 is great and if the only reason why you didn&rsquo;t give it a try is because you have to use CocoaMySQL, then check out <a href="https://sqlitebrowser.sourceforge.net/">sqlitebrowser</a></p>
</li>
<li>
<p>Other new feature: rake secret  to generate a key used to encrypt your session. Really useful task when you&rsquo;re migrating an app to 2.x</p>
</li>
<li>
<p>To improve performance, some changes were made to the template caching and you have to restart your production server after a template modification.</p>
</li>
<li>
<p>Validates acceptance of still works for non-existent tables . (sorry <a href="https://blog.hasmanythrough.com/">Josh</a>, I won&rsquo;t post after 2am, especially when I forget your life changing bug fix ;) )</p>
</li>
<li>
<p>Added option to pass proc to ActionController::Base.asset_host for maximum configurability. Example:</p>
<p>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt><strong>5</strong><tt>
</tt>6<tt>
</tt>7<tt>
</tt></p>
<pre><code>&lt;span class=&quot;co&quot;&gt;ActionController&lt;/span&gt;::&lt;span class=&quot;co&quot;&gt;Base&lt;/span&gt;.asset_host = &lt;span class=&quot;co&quot;&gt;Proc&lt;/span&gt;.new { |source|&lt;tt&gt;
</code></pre>
<p></tt>      <span class="r">if</span> source.starts_with?(<span class="s"><span class="dl">'</span><span class="k">/images</span><span class="dl">'</span></span>)<tt>
</tt>        <span class="s"><span class="dl">&quot;</span><span class="k"><a href="https://images.example.com">https://images.example.com</a></span><span class="dl">&quot;</span></span><tt>
</tt>      <span class="r">else</span><tt>
</tt>        <span class="s"><span class="dl">&quot;</span><span class="k"><a href="https://assets.example.com">https://assets.example.com</a></span><span class="dl">&quot;</span></span><tt>
</tt>      <span class="r">end</span><tt>
</tt>    }</p>
</li>
<li>
<p>Finally, I added 2 new rake tasks: db:migrate:redo and db:migrate:reset</p>
</li>
</ul>
<p>db:migrate:redo rolls back your database and then migrates it up. You can define the STEP constant to specify the amount of steps you want to rollback. This task is very useful in development mode when making a modification to the latest migration(s).
db:migrate:reset will drop your database, re create it and migrate it up. Only use this task if you really have to and only in development/test environment.  Use db:reset in production mode since it uses the schema.rb file and won&rsquo;t go through the hundreds of migrations you might have.</p>
<h2 id="changeset">Changeset</h2>
<p><em>2.0.2</em> (December 16th, 2007)</p>
<ul>
<li>
<p>Changed the default database from mysql to sqlite3, so now running &ldquo;rails myapp&rdquo; will have a config/database.yml that&rsquo;s setup for SQLite3 (which in OS X Leopard is installed by default, so is the gem, so everything Just Works with no database configuration at all). To get a Rails application preconfigured for MySQL, just run &ldquo;rails -d mysql myapp&rdquo; [DHH]</p>
</li>
<li>
<p>Turned on ActionView::Base.cache_template_loading by default in config/environments/production.rb to prevent file system stat calls for every template loading to see if it changed (this means that you have to restart the application to see template changes in production mode) [DHH]</p>
</li>
<li>
<p>Introduce <code>rake secret</code> to output a crytographically secure secret key for use with cookie sessions #10363 [revans]</p>
</li>
<li>
<p>Fixed that local database creation should consider 127.0.0.1 local #9026 [parcelbrat]</p>
</li>
<li>
<p>Fixed that functional tests generated for scaffolds should use fixture calls instead of hard-coded IDs #10435 [boone]</p>
</li>
<li>
<p>Added db:migrate:redo and db:migrate:reset for rerunning existing migrations #10431, #10432  [matt]</p>
</li>
<li>
<p>RAILS_GEM_VERSION may be double-quoted also.  #10443 [James Cox]</p>
</li>
<li>
<p>Update rails:freeze:gems to work with RubyGems 0.9.5.  [Jeremy Kemper]</p>
</li>
<li>
<p>Added delete_via_redirect and put_via_redirect to integration testing #10497 [philodespotos]</p>
</li>
<li>
<p>Allow headers[&lsquo;Accept&rsquo;] to be set by hand when calling xml_http_request #10461 [BMorearty]</p>
</li>
<li>
<p>Added OPTIONS to list of default accepted HTTP methods #10449 [holoway]</p>
</li>
<li>
<p>Added option to pass proc to ActionController::Base.asset_host for maximum configurability #10521 [chuyeow]. Example:</p>
</li>
</ul>
<p>ActionController::Base.asset_host = Proc.new { |source|
if source.starts_with?('/images')
&ldquo;<a href="https://images.example.com">https://images.example.com</a>&rdquo;
else
&ldquo;<a href="https://assets.example.com">https://assets.example.com</a>&rdquo;
end
}</p>
<ul>
<li>
<p>Fixed that ActionView#file_exists? would be incorrect if @first_render is set #10569 [dbussink]</p>
</li>
<li>
<p>Added that Array#to_param calls to_param on all it&rsquo;s elements #10473 [brandon]</p>
</li>
<li>
<p>Ensure asset cache directories are automatically created.  #10337 [Josh Peek, Cheah Chu Yeow]</p>
</li>
<li>
<p>render :xml and :json preserve custom content types.  #10388 [jmettraux, Cheah Chu Yeow]</p>
</li>
<li>
<p>Refactor Action View template handlers.  #10437, #10455 [Josh Peek]</p>
</li>
<li>
<p>Fix DoubleRenderError message and leave out mention of returning false from filters.  Closes #10380 [Frederick Cheung]</p>
</li>
<li>
<p>Clean up some cruft around ActionController::Base#head.  Closes #10417 [ssoroka]</p>
</li>
<li>
<p>Ensure optimistic locking handles nil #lock_version values properly.  Closes #10510 [rick]</p>
</li>
<li>
<p>Make the Fixtures Test::Unit enhancements more supporting for double-loaded test cases.  Closes #10379 [brynary]</p>
</li>
<li>
<p>Fix that validates_acceptance_of still works for non-existent tables (useful for bootstrapping new databases).  Closes #10474 [hasmanyjosh]</p>
</li>
<li>
<p>Ensure that the :uniq option for has_many :through associations retains the order.  #10463 [remvee]</p>
</li>
<li>
<p>Base.exists? doesn&rsquo;t rescue exceptions to avoid hiding SQL errors.  #10458 [Michael Klishin]</p>
</li>
<li>
<p>Documentation: Active Record exceptions, destroy_all and delete_all.  #10444, #10447 [Michael Klishin]</p>
</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>googlecharts 0 1 0 released with new site</title>
			<link>https://matt.aimonetti.net/posts/2007-12-googlecharts-0-1-0-released-with-new-site/</link>
			<pubDate>Wed, 12 Dec 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-12-googlecharts-0-1-0-released-with-new-site/</guid>
			<description>I just released Googlecharts 0.1.0 (few bug fixes and enhancements).
  The first thing you want to do is to install the gem
sudo gem install googlecharts
  The second thing you want to do is check the great brand new website for googlecharts
    The third thing you want to do is to recommend me on Working with Rails ;)
  The fourth thing you want to do is to submit patches, suggestions etc&amp;hellip;</description>
			<content type="html"><![CDATA[<p>I just released Googlecharts 0.1.0 (few bug fixes and enhancements).</p>
<ul>
<li>
<p>The first thing you want to do is to install the gem</p>
<p>sudo gem install googlecharts</p>
</li>
<li>
<p>The second thing you want to do is check <a href="https://googlecharts.rubyforge.org/">the great brand new website</a> for <a href="https://googlecharts.rubyforge.org/">googlecharts</a></p>
</li>
</ul>
<p><img src="https://content.screencast.com/media/40c8b83c-06e5-4d07-89d5-8f05ae37e3a9_74569570-772f-4886-b2ea-f305d1ede3aa_static_0_0_00000037.png" alt="website"></p>
<ul>
<li>
<p>The third thing you want to do is to <a href="https://www.workingwithrails.com/recommendation/new/person/6065-matt-aimonetti">recommend me on Working with Rails</a> ;)</p>
</li>
<li>
<p>The fourth thing you want to do is to submit patches, suggestions etc&hellip;</p>
</li>
<li>
<p>The fifth thing you want to do is to develop an awesome website using sexy googlecharts</p>
</li>
</ul>
<p>This gem and its website have been made possible by <a href="https://drnicwilliams.com/">DrNic</a> and his awesome <a href="https://newgem.rubyforge.org/">new gem generator</a> and has been developed following the BDD approach thanks to <a href="https://rspec.rubyforge.org">RSpec</a> :)</p>
]]></content>
		</item>
		
		<item>
			<title>google chart gem</title>
			<link>https://matt.aimonetti.net/posts/2007-12-google-chart-gem/</link>
			<pubDate>Mon, 10 Dec 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-12-google-chart-gem/</guid>
			<description>update Nov 11: the gem is finally available there or simply:  sudo gem install googlecharts  Note that I&amp;rsquo;m working on merging this gem with another Google Charts gem. (see comments for more info about that)
I&amp;rsquo;ve been working on a Google Chart Gem that I have ready for a beta release but unfortunately, getting a new project setup on RubyForge takes forever. (apparently 72 hours)
It&amp;rsquo;s mainly a wrapper for the great GChart API, but instead of using a helper to generate your graphs, you can simply do:</description>
			<content type="html"><![CDATA[<h2 id="update-nov-11-the-gem-is-finally-available-therehttpsrubyforgeorgprojectsgooglecharts-or-simply">update Nov 11: the gem is finally available <a href="https://rubyforge.org/projects/googlecharts/">there</a> or simply:</h2>
<pre><code>  sudo gem install googlecharts
</code></pre>
<p>Note that I&rsquo;m working on merging this gem with another Google Charts gem. (see comments for more info about that)</p>
<p><img src="https://chart.apis.google.com/chart?chtt=Rails+on+the+run&amp;cht=p3&amp;chs=200x90&amp;chd=s:Hellobla&amp;chl=May%7CJun%7CJul%7CAug%7CSep%7COct&amp;chco=0000ff" alt="gchart"></p>
<p>I&rsquo;ve been working on a Google Chart Gem that I have ready for a beta release but unfortunately, getting a new project setup on RubyForge takes forever. (apparently 72 hours)</p>
<p>It&rsquo;s mainly a wrapper for the great GChart API, but instead of using a helper to generate your graphs, you can simply do:</p>
<pre><code>  Gchart.bar(:title =&gt; 'My Mojo', :data =&gt; [1,2,4,67,100,41,234], :max_value =&gt; 300, :bg =&gt; 'c3c3c3')

  Gchart.line(:title =&gt; 'My Mojo',
              :data =&gt; [[1,2,4,67,100,41,234],[41,63,96,17,100,14,423]],
              :bg =&gt; '666666',
              :graph_bg =&gt; 'cccccc',
              :line_colors =&gt; 'ff0000,00ff00',
              :legend =&gt; ['morning','evening'])







  Gchart.pie(:data =&gt; [20,10,15,5,50], :title =&gt; 'SDRuby fu', :size =&gt; '400x200', :labels =&gt; ['matt', 'rob', 'patrick', 'jordan', 'ryan'])
</code></pre>
<p><img src="https://chart.apis.google.com/chart?chs=400x200&amp;chd=s:YMSG9&amp;chtt=SDRuby+fu&amp;chl=matt%7Crob%7Cpatrick%7Cjordan%7Cryan&amp;cht=p" alt="img"></p>
<p>As far as I know this is most complete Ruby wrapper for Google Chart API, but feel free to look around.</p>
]]></content>
		</item>
		
		<item>
			<title>keeping my javascript files organized</title>
			<link>https://matt.aimonetti.net/posts/2007-12-keeping-my-javascript-files-organized/</link>
			<pubDate>Wed, 05 Dec 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-12-keeping-my-javascript-files-organized/</guid>
			<description>I was recently asked by Rubyist friend (Josh Knowles) how I was organizing my Javascript files when using LowPro.
LowPro is the best solution for doing Unobtrusive Javascript using Prototype.
With the help of LowPro, you define behaviors that get triggered by the user. This is great, however, you&amp;rsquo;ll notice that some behaviors are used all over the place (a date chooser for instance) and some complicated behaviors only get used on very specific pages.</description>
			<content type="html"><![CDATA[<p>I was recently asked by Rubyist friend (<a href="https://joshknowles.com/">Josh Knowles</a>) how I was organizing my Javascript files when using <a href="https://lowpro.stikipad.com/home/show/HomePage">LowPro</a>.</p>
<p><a href="https://lowpro.stikipad.com/home/show/HomePage">LowPro</a> is the best solution for doing <a href="https://en.wikipedia.org/wiki/Unobtrusive_JavaScript">Unobtrusive Javascript</a> using <a href="https://www.prototypejs.org/">Prototype</a>.</p>
<p>With the help of <a href="https://lowpro.stikipad.com/home/show/HomePage">LowPro</a>, you define behaviors that get triggered by the user. This is great, however, you&rsquo;ll notice that some behaviors are used all over the place (a date chooser for instance) and some complicated behaviors only get used on very specific pages.</p>
<p>First things first, let&rsquo;s look at the header in my application.html.erb file (located in app/views/layouts).
This is the default layout used by all my views, I rarely use more than 5 layouts per app and always use a default layout.</p>
<p>Please note that I&rsquo;m using Rails 2.0 so some features you&rsquo;ll see in my file won&rsquo;t work in Rails 1.2.x. (if you want to know about all the new Rails sexiness, check on <a href="https://peepcode.com/products/rails2-pdf">this awesome Peepcode PDF</a>.</p>
<p>Here we go:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;




  &lt;%= javascript_include_tag &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;effects&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:cache&lt;/span&gt; =&gt; &lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;%= javascript_include_tag 'lowpro', :cache =&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;%= javascript_include_tag  'application', :cache =&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>The first thing you might notice is that I don&rsquo;t use</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




  &lt;%= javascript_include_tag &lt;span class=&quot;sy&quot;&gt;:defaults&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>The reason? I don&rsquo;t want to load prototype.js, effects.js, controls.js, dragdrop.js, and application.js all at once. I almost never use drag&rsquo;n&rsquo;drop and seldom use Autocompleter and InPlaceEditor so why loading them in each and every single page of my apps? I&rsquo;m not saying they are bad libraries, I&rsquo;m just saying that in more than 80% of my page, I don&rsquo;t use them, so they should not be in my default page load.</p>
<p>The second thing you might notice, I use :cache =&gt; true. Asset caching is a new feature in Rails 2.0 which combines related assets into a single file (works with css and js and only in production mode)
Note that the above code is untested, but everything should be loaded properly, otherwise, make sure proto gets loaded first, then lowpro, then application. (and you can probably create a one-liner)</p>
<p>All the default behaviors are defined in the application.js file, so they get loaded on all page. However to handle action specific behaviors, I use another Rails trick right in the header:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




 &lt;%= &lt;span class=&quot;r&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;sy&quot;&gt;:javascript&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>Why? Very simple, I want to load some custom JS in the header depending on the action that is used. For instance, when a visitor goes to my fancy ajax photo editor, I want to load the content editor javascript right in the header where it belongs.</p>
<p>For that, I simply need to add the following to my view:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;




  &lt;% content_for &lt;span class=&quot;sy&quot;&gt;:javascript&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;%= javascript_include_tag &quot;photos_show&quot; %&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;% &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>If content_for :javascript isn&rsquo;t define, noting is yield in my header and therefore nothing is included but whenever I need, I can access my header directly from the view and insert javascript code in a very clean way.</p>
<p>photos_show.js is the javascript defining all the behaviors related to the photos controller and the show action. I usually only have few actions with a lot of custom behaviors so, these structure works well for me.</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;




  javascripts&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;er&quot;&gt;\&lt;/span&gt;controller_action.js&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;er&quot;&gt;\&lt;/span&gt;controller_another_action.js&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;er&quot;&gt;\&lt;/span&gt;another_controller_action.js&lt;tt&gt;
&lt;/tt&gt;    ...
</code></pre>
<p>However in the case of an app with a lot of custom behaviors, I recommend using the following structure:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;




  javascripts&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;er&quot;&gt;\&lt;/span&gt; controller_name_&lt;tt&gt;
&lt;/tt&gt;            &lt;span class=&quot;er&quot;&gt;\&lt;/span&gt;action_name_.js&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;er&quot;&gt;\&lt;/span&gt;another_controller_name&lt;tt&gt;
&lt;/tt&gt;              &lt;span class=&quot;er&quot;&gt;\&lt;/span&gt;action_name_.js&lt;tt&gt;
&lt;/tt&gt;  ...
</code></pre>
<p>That&rsquo;s it folks, I&rsquo;m not a javascript expert, and if you know better, don&rsquo;t hesitate to leave me a comment. What I know for sure, is that since I started using LowPro and behavior driven with Prototype, I have much more fun. Adding a bit of structure is a simple way for me to keep my code clear and help other people who have to work with me. (more on that later)</p>
]]></content>
		</item>
		
		<item>
			<title>a new useless gem</title>
			<link>https://matt.aimonetti.net/posts/2007-12-a-new-useless-gem/</link>
			<pubDate>Tue, 04 Dec 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-12-a-new-useless-gem/</guid>
			<description>During Thanksgiving break I had fun with a friend of mine working on a Ruby challenge while digesting the traditional turkey.
The challenge was quite simple, create a small library that can generate random words from the English dictionary.
But of course there was a twist. One should be able to choose the total amount of characters, the amount of words and the separator between the words. However we both had a word list.</description>
			<content type="html"><![CDATA[<p>During Thanksgiving break I had fun with a friend of mine working on a Ruby challenge while digesting the traditional turkey.</p>
<p><img src="https://content.screencast.com/media/a088950c-c9d1-4655-9b6e-b917e04dd6ec_74569570-772f-4886-b2ea-f305d1ede3aa_static_0_0_00000026.png" alt="https://content.screencast.com/media/a088950c-c9d1-4655-9b6e-b917e04dd6ec74569570-772f-4886-b2ea-f305d1ede3aastatic00_00000026.png"></p>
<p>The challenge was quite simple, create a small library that can generate random words from the English dictionary.</p>
<p>But of course there was a twist. One should be able to choose the total amount of characters, the amount of words and the separator between the words. However we both had a <a href="https://wordlist.sourceforge.net/">word list</a>.</p>
<p>I personally decided to use <a href="https://www.sqlite.org/">SQlite3</a> to store the words after parsing the text file if the database is empty.</p>
<p>It was a good exercise and it got me to play with SQLite and one of the <a href="https://rubyforge.org/projects/sqlite-ruby/">Ruby adapter library</a>. Once I was done, I decide to play with <a href="https://drnicwilliams.com/">DrNic</a> cool <a href="https://newgem.rubyforge.org/">Gem generator</a>.</p>
<p><img src="https://static.flickr.com/50/130749539_89959dd059_t.jpg" alt="https://static.flickr.com/50/13074953989959dd059t.jpg"></p>
<p>Nic is my favorite Aussie&rsquo;s Rubyist (ok, I don&rsquo;t know many) and I&rsquo;ve been wanting to check on this lib for a very long time. And I have to say he did an awesome job! Writing a Ruby Gem has never that easy! And on top of that the generator creates RSpec examples (or test/unit tests), a basic website for your gem and has a bunch of rake tasks to deploy your newly created gem.</p>
<p>Feel free to check the source code:</p>
<p><a href="https://random-word-gen.rubyforge.org/svn/">https://random-word-gen.rubyforge.org/svn/</a></p>
<p><a href="https://rubyforge.org/projects/random-word-gen/">And the Rubyforge site</a></p>
<p>By the way, I did find an almost useful use for this gem. Activation code generator. You know, the kind of string your receive on by email or SMS to activate a feature or an account. It&rsquo;s always a pain to type a MD5Hash string, while, when using the word generator, the string is made of existing words, making the process way more user friendly.</p>
<p>I also plan on adding some random copyleft text to the sqlite db so the Gem will be able to generate titles, paragraphs and random quotes. I&rsquo;m just tired of reading <a href="https://en.wikipedia.org/wiki/Lorem_ipsum">lorem ipsum</a> and on top of that, I get to it, I might had text in various languages so you check if your app breaks when using another char set, or if your layout can&rsquo;t handle too much text.</p>
<p>Honestly, I don&rsquo;t expect you to use this gem, but I jut wanted to encourage people to start writing their own gem, the process is super easy and rewarding. And actually, feel free to try the challenge and post a link to your implementation in the comments. (That&rsquo;s seriously, the best way to learn)</p>
<p>p.s: I&rsquo;m sorry about my RSS feed constantly being reset, it seems to be a problem with Mephisto, my blog engine and we are trying to figure out what&rsquo;s going on.</p>
]]></content>
		</item>
		
		<item>
			<title>attachment_fu updated</title>
			<link>https://matt.aimonetti.net/posts/2007-11-attachment_fu-updated/</link>
			<pubDate>Wed, 28 Nov 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-11-attachment_fu-updated/</guid>
			<description>I recently bugged Rick Olson so much about attachment_fu that he gave me SVN access to fix few bugs.
Rick being really busy with ActiveReload he didn&amp;rsquo;t spend too much time maintaining attachment_fu.
On my side of things, I&amp;rsquo;ve been using attachment_fu on a lot of projects and I&amp;rsquo;ve been fixing bugs and adding new features.
My first contribution to attachment_fu is a fix for the ImageScience processor.
Attachment_fu is very flexible and let you use your favorite image processor:</description>
			<content type="html"><![CDATA[<p>I recently bugged <a href="https://techno-weenie.net/">Rick Olson</a> so much about <a href="https://svn.techno-weenie.net/projects/plugins/attachment_fu/">attachment_fu</a> that he gave me SVN access to fix few bugs.</p>
<p>Rick being really busy with <a href="https://activereload.net/">ActiveReload</a> he didn&rsquo;t spend too much time maintaining <a href="https://svn.techno-weenie.net/projects/plugins/attachment_fu/">attachment_fu</a>.</p>
<p>On my side of things, I&rsquo;ve been using <a href="https://svn.techno-weenie.net/projects/plugins/attachment_fu/">attachment_fu</a> on a lot of projects and I&rsquo;ve been fixing bugs and adding new features.</p>
<p>My first contribution to <a href="https://svn.techno-weenie.net/projects/plugins/attachment_fu/">attachment_fu</a> is a fix for the <a href="https://seattlerb.rubyforge.org/ImageScience.html">ImageScience</a> processor.</p>
<p>Attachment_fu is very flexible and let you use your favorite image processor:</p>
<ul>
<li>
<p><a href="https://rmagick.rubyforge.org/">RMagick</a> based on <a href="https://www.imagemagick.org/script/mogrify.php">ImageMagick</a> and <a href="https://www.graphicsmagick.org/">GraphicsMagick</a>(known to leak memory and being a pain to setup)</p>
</li>
<li>
<p><a href="https://rubyforge.org/projects/mini-magick/">minimagick</a> based on <a href="https://www.imagemagick.org/script/mogrify.php">ImageMagick</a></p>
</li>
<li>
<p><a href="https://seattlerb.rubyforge.org/ImageScience.html">ImageScience</a> based on <a href="https://sf.net/projects/freeimage">FreeImage</a>.</p>
</li>
</ul>
<p>Like many rubyists, I like <a href="https://seattlerb.rubyforge.org/ImageScience.html">ImageScience</a> for its simplicity and efficiency. However, <a href="https://svn.techno-weenie.net/projects/plugins/attachment_fu/">attachment_fu</a> had few problems when being used with <a href="https://seattlerb.rubyforge.org/ImageScience.html">ImageScience</a>.</p>
<ul>
<li>
<p>File sizes for thumbnails were not saved correctly in the database. Fixed</p>
</li>
<li>
<p>Thumbnails based on a gif files were not processed properly. So, this was the big problem. <a href="https://sf.net/projects/freeimage">FreeImage</a> has issues dealing with resizing gif files because of the gif palette limitation (256 colors). to avoid this problem thumbnails of gif files are converted to png. However the thumbnail content type info in the database was not saved properly. That&rsquo;s now fixed.</p>
</li>
<li>
<p>Because of the gif bug reported above, any thumbnail link was broken since it was trying to link to the thumbnail version with a gif extension instead of a png one. Fixed</p>
</li>
</ul>
<p>I also fixed a small bug related to <a href="https://www.amazon.com/gp/browse.html?node=16427261">S3 storage</a> and the fact that a_fu had issues loading the config file. (Fixed)</p>
<p>I&rsquo;ll also try be able to add some of the S3 features I&rsquo;ve been working on. As well as maybe enhancing the validation process.</p>
<p>In the mean time, you might want to read <a href="https://the.railsi.st/2007/11/27/roll-your-own-attachment_fu-validations">this blog post</a> about better validation with attachment_fu.</p>
<p>If you are heavily using attachment_fu or starting using it and think that a google group would be great idea, please let me know in the comment and I&rsquo;ll try to convince Technoweenie that we need to set that up :)</p>
<p>Ooohh I almost forgot, if you fixed some bugs you found while using a_fu, please contact me so we can get a_fu bug free.</p>
]]></content>
		</item>
		
		<item>
			<title>lowpro 0 5 what s new</title>
			<link>https://matt.aimonetti.net/posts/2007-11-lowpro-0-5-what-s-new/</link>
			<pubDate>Tue, 27 Nov 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-11-lowpro-0-5-what-s-new/</guid>
			<description>If you&amp;rsquo;ve read my post on Ajax pagination you know that I&amp;rsquo;m a big fan of Dan Webb&amp;rsquo;s LowPro unobtrusive javascript library.
Doing Unobtrusive Javascript (UJS) is basically registering event handlers programmatically using CSS selectors to select the elements to register. In other words : keeping things separate and avoiding inline javascript.
If you&amp;rsquo;ve been using LowPro 0.4 and recently tried to upgrade to Prototype 1.6 you probably noticed that things don&amp;rsquo;t work as they used to.</description>
			<content type="html"><![CDATA[<p>If you&rsquo;ve read my <a href="https://railsontherun.com/2007/9/27/ajax-pagination-in-less-than-5-minutes">post on Ajax pagination</a> you know that I&rsquo;m a big fan of <a href="https://www.danwebb.net">Dan Webb</a>&rsquo;s <a href="https://www.danwebb.net/lowpro">LowPro</a> unobtrusive javascript library.</p>
<p>Doing Unobtrusive Javascript (UJS) is basically registering event handlers programmatically using CSS selectors to select the elements to register. In other words : keeping things separate and avoiding inline javascript.</p>
<p>If you&rsquo;ve been using LowPro 0.4 and recently tried to upgrade to <a href="https://www.prototypejs.org/">Prototype 1.6</a> you probably noticed that things don&rsquo;t work as they used to.</p>
<p>The first thing you want to do, is to update to the <a href="https://svn.danwebb.net/external/lowpro/trunk/dist/">latest version of Lowpro</a>.</p>
<h2 id="so-whats-new-in-05-trunk">So what&rsquo;s new in 0.5 trunk?</h2>
<p>First off, you need to know that a lot of lowpro features were moved in Prototype 1.6 core :)</p>
<ul>
<li>
<p>You now get a warning via firebug if you try to use Low Pro with a version of Prototype that its not designed to work with.</p>
</li>
<li>
<p>Alternative event system ripped out: uses core events</p>
</li>
<li>
<p>DOM method mixins ripped out: alternatives all in prototype</p>
</li>
<li>
<p>Event.onReady delegates to the new dom:loaded event.  However this doesn&rsquo;t fire immediately if the dom is already loaded like Event.onReady did. (might be patched to work as before)</p>
</li>
<li>
<p>DOMBuilder is staying but now is a thin shell around the new proto 1.6 Element stuff.</p>
</li>
<li>
<p>You can still return false from event handlers in addEvent and Behaviors to stop the event but now if you use Event.observe raw you don&rsquo;t get this.</p>
</li>
<li>
<p>Behavior.create now works like Class.create in 1.6 so behaviors can have full inheritance:</p>
<p>1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt><strong>5</strong><tt>
</tt>6<tt>
</tt>7<tt>
</tt>8<tt>
</tt>9<tt>
</tt><strong>10</strong><tt>
</tt>11<tt>
</tt>12<tt>
</tt></p>
<p><span class="co">Basic</span> = <span class="co">Behavior</span>.create({<tt>
</tt>   onclick: function() {<tt>
</tt>    alert(<span class="s"><span class="dl">'</span><span class="k">woo</span><span class="dl">'</span></span>);<tt>
</tt>   }<tt>
</tt>  });<tt>
</tt><tt>
</tt>  <span class="co">SuppedUp</span> = <span class="co">Behavior</span>.create({<tt>
</tt>   onclick: function(<span class="gv">$super</span>) {<tt>
</tt>    alert(<span class="s"><span class="dl">'</span><span class="k">wee</span><span class="dl">'</span></span>);<tt>
</tt>    <span class="gv">$super</span>();<tt>
</tt>   }<tt>
</tt>  });</p>
</li>
</ul>
<p>Works really nicely.</p>
<ul>
<li>
<p>core behaviors : Remote and Observed are now moved into the lowpro core (you don&rsquo;t need to include the external files).</p>
</li>
<li>
<p>Event.addBehavior.reassignAfterAjax defaults to false. If you want re assign behaviors after an ajax call, you need to turn this option to true.</p>
</li>
<li>
<p>Event.addBehavior.reload(); added to reload/re assign behaviors. Very useful if you dynamically insert elements you want to observe!</p>
</li>
<li>
<p><a href="https://lowprojs.com">new website</a> has been set up and will contain documentation and tips - Full API docs coming soon.  There&rsquo;s also a dedicated <a href="https://groups.google.co.uk/group/low-pro">google group</a>.</p>
</li>
</ul>
<p>Here is a quick example with real life code. (which could be refactored, I know)</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;




&lt;span class=&quot;c&quot;&gt;// Make sure the behaviors still work even after navigating to another page using the ajax navigation.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;Event.addBehavior.reassignAfterAjax = &lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;// Behaviors&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;Event.addBehavior({&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;// Pagination links  &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;div.pagination a&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; : Remote.&lt;span class=&quot;pt&quot;&gt;Link&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;// Reset the list when a user clicks on cancel.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;a.cancel_button:click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;() {&lt;tt&gt;
&lt;/tt&gt;    $(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;list_of_things&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;).update(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;// carousel navigation prev&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;a#carousel_prev:click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;() {&lt;tt&gt;
&lt;/tt&gt;    moveCarousel(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;prev&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;r&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;false&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;// carousel navigation next&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;a#carousel_next:click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;() {&lt;tt&gt;
&lt;/tt&gt;    moveCarousel(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;); &lt;span class=&quot;r&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;pc&quot;&gt;false&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;div.panel_pic:click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;() {&lt;tt&gt;
&lt;/tt&gt;    removePanelPic(&lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;  },&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;div.photo_from_row img:click&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class=&quot;r&quot;&gt;function&lt;/span&gt;() {&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;// Get the div holding the pic and use it as a target&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;var&lt;/span&gt; target = &lt;span class=&quot;pc&quot;&gt;this&lt;/span&gt;.up();&lt;tt&gt;
&lt;/tt&gt;    addPicToPanel(target);&lt;tt&gt;
&lt;/tt&gt;    new Effect.Highlight(target);&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;});&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;function&lt;/span&gt; addPicToPanel(target){&lt;tt&gt;
&lt;/tt&gt;  new Insertion.Bottom(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;control_panel_photos&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;div id='edit_&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;+ target.id +&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;' class='panel_pic'&gt;&lt;img class='panel_pic' src='&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; +  target.immediateDescendants()[0].src + &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;'/&gt;&lt;/div&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;);&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;// Reload the behaviors so the new inserted pic can be monitored &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;c&quot;&gt;// and the 'div.panel_pic:click' behavior can be triggered&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  Event.addBehavior.&lt;span class=&quot;fu&quot;&gt;reload&lt;/span&gt;();&lt;tt&gt;
&lt;/tt&gt;}&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>LowPro is a great way of keeping your code really clean and your views very accessible.</p>
<p>If you are interested in knowing more about UJS, come to our <a href="https://sdruby.com/">SDruby group meeting</a> on Dec 6 @ 7:30pm (<a href="https://tinyurl.com/2f486e">directions</a>). And if you don&rsquo;t care about UJS, come later to hear about Facebook API. Don&rsquo;t forger to bring your questions for our first <a href="https://groups.google.com/group/sdruby/browse_thread/thread/d488b70d67f84a5f#">Rails roundtable</a>.</p>
]]></content>
		</item>
		
		<item>
			<title>sexy chart the video</title>
			<link>https://matt.aimonetti.net/posts/2007-11-sexy-chart-the-video/</link>
			<pubDate>Tue, 20 Nov 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-11-sexy-chart-the-video/</guid>
			<description>A bit more than a month ago I posted a tutorial on how to use Flash with Rails to create some awesome/sexy graphs.
Since a lot of people seemed interested by the topic, the SDRuby guys asked me to do a intro talk on how to create Sexy Charts with super sexy Rails.
In the mean time, a lot of people were asking for a example app to look at. People knowing me know that I&amp;rsquo;m quite lazy and I don&amp;rsquo;t like repeating tasks.</description>
			<content type="html"><![CDATA[<p>A bit more than a month ago I posted a <a href="https://railsontherun.com/2007/10/4/sexy-charts-in-less-than-5-minutes">tutorial</a> on how to use Flash with Rails to <a href="https://railsontherun.com/2007/10/4/sexy-charts-in-less-than-5-minutes">create some awesome/sexy graphs</a>.</p>
<p><img src="https://content.screencast.com/media/e0605640-1100-43dc-90f9-d8c2083c0f7c_74569570-772f-4886-b2ea-f305d1ede3aa_static_0_0_00000016.png" alt="chart"></p>
<p>Since a lot of people seemed interested by the topic, the <a href="https://sdruby.com/">SDRuby</a> guys asked me to do a intro talk on how to create Sexy Charts with super sexy Rails.</p>
<p>In the mean time, a lot of people were asking for a example app to look at. People knowing me know that I&rsquo;m quite lazy and I don&rsquo;t like repeating tasks. I therefore decided to kill 2 birds with one stone and wrote a demo app that I would use during my <a href="https://podcast.sdruby.com/2007/11/13/episode-037-sexy-charts">presentation</a></p>
<p>As I was writing the demo app, I quickly realized that my talk would be even sexier if I would show some best practices. After all, an introduction talk is meant to help newbies learning the tricks that will change them in ninjas!</p>
<p>Sexy charts are sexy now, but in 15 years they might not look so sexy anymore. However <a href="https://en.wikipedia.org/wiki/Behavior_driven_development">BDD</a> is super hot now and will always be sexy! (even though we&rsquo;ll probably adopt other even hotter approaches).</p>
<p>Based on the circumstances I decided that Sexy charts would become an excuse to show people how to do BDD using <a href="https://rspec.rubyforge.org">RSpec</a> and how to test a XML view  as described in <a href="https://railsontherun.com/2007/10/31/how-to-test-a-xml-builder-view">this previous post</a></p>
<p>During my presentation I totally forgot to show people what what kind of XML we were trying to feed amCharts, so here is the file:</p>
<p><a href="https://pastie.caboo.se/120055">https://pastie.caboo.se/120055</a></p>
<p>The code used in the presentation is also available <a href="https://railsontherun.com/assets/sexy_charts.zip">here</a></p>
<p>Presentation available <a href="https://podcast.sdruby.com/2007/11/13/episode-037-sexy-charts">here</a> (the sound is a bit saturated, sorry about that. Note that we made the video big enough so you can follow with the code if you don&rsquo;t understand my accent :) )</p>
<p>Feel free to watch the other <a href="https://podcast.sdruby.com/">SDRuby podcasts</a> or even better, <a href="https://feeds.feedburner.com/sdrbpodcast">subscribe to our feed</a>.</p>
<h2 id="next-sdruby-meeting-will-be-thursday-december-6--730pm">Next SDRuby meeting will be Thursday, December 6 @ 7:30pm</h2>
<p>Location: <a href="https://tinyurl.com/2f486e">UCSD CS Building</a></p>
<p>We&rsquo;ll be talking about <a href="https://groups.google.com/group/sdruby/browse_thread/thread/d488b70d67f84a5f#">Unobtrusive Javascript</a>, the <a href="https://groups.google.com/group/sdruby/browse_thread/thread/d488b70d67f84a5f#">Facebook API</a>, and hosting our first Rails Roundtable.</p>
<h2 id="newbies-and-experts-welcome">Newbies and experts welcome!</h2>
]]></content>
		</item>
		
		<item>
			<title>rss feed issues</title>
			<link>https://matt.aimonetti.net/posts/2007-11-rss-feed-issues/</link>
			<pubDate>Tue, 06 Nov 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-11-rss-feed-issues/</guid>
			<description>Few of you contacted me to let me know that my RSS feed was always getting reset up to few times a day. (Thanks Josh).
It looks like a Mephisto problem, so if you subscribed to the mephisto feed, please switch to this feed:
https://feeds.feedburner.com/railsontherun
I made sure to clean up the blog header so the old mephisto link won&amp;rsquo;t show up.
Sorry about that and thanks for reading.
-Matt</description>
			<content type="html"><![CDATA[<p>Few of you contacted me to let me know that my RSS feed was always getting reset up to few times a day. (Thanks <a href="https://blog.hasmanythrough.com/">Josh</a>).</p>
<p>It looks like a <a href="https://mephistoblog.com/">Mephisto</a> problem, so if you subscribed to the mephisto feed, please switch to <a href="https://feeds.feedburner.com/railsontherun">this</a> feed:</p>
<p><a href="https://feeds.feedburner.com/railsontherun">https://feeds.feedburner.com/railsontherun</a></p>
<p>I made sure to clean up the blog header so the old mephisto link won&rsquo;t show up.</p>
<p>Sorry about that and thanks for reading.</p>
<p>-Matt</p>
]]></content>
		</item>
		
		<item>
			<title>how to test a xml builder view</title>
			<link>https://matt.aimonetti.net/posts/2007-10-how-to-test-a-xml-builder-view/</link>
			<pubDate>Wed, 31 Oct 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-10-how-to-test-a-xml-builder-view/</guid>
			<description>As a good Rubyist, I do TDD and even BDD.
Since I&amp;rsquo;ve started using RSpec I&amp;rsquo;ve started writing tests against my views. RSpec makes things really easy and I&amp;rsquo;ve been enjoying testing my views.
I&amp;rsquo;m not the only one having fun, check this great post from Mr Planet Argon aka Robby Russel
Recently I was working on implementing some Sexy Charts and I was using a XML builder to create an XML view of for a controller.</description>
			<content type="html"><![CDATA[<p>As a good Rubyist, I do <a href="https://en.wikipedia.org/wiki/Test-driven_development">TDD</a> and even <a href="https://en.wikipedia.org/wiki/Behavior_driven_development">BDD</a>.</p>
<p>Since I&rsquo;ve started using <a href="https://rspec.rubyforge.org/">RSpec</a> I&rsquo;ve started writing tests against my views. RSpec makes things really easy and I&rsquo;ve been enjoying testing my views.</p>
<p>I&rsquo;m not the only one having fun, check <a href="https://www.robbyonrails.com/articles/2007/08/02/spec-your-views">this great post</a> from Mr <a href="https://www.planetargon.com/">Planet Argon</a> aka <a href="https://www.robbyonrails.com">Robby Russel</a></p>
<p>Recently I was working on implementing some <a href="https://railsontherun.com/2007/10/4/sexy-charts-in-less-than-5-minutes">Sexy Charts</a> and I was using a XML builder to create an XML view of for a controller. Since I wanted to be a good Rails Ninja and obey the BDD rules, I figured I needed to test my XML view. Making sure that the nodes and the attributes were properly created. Turned out that is wasn&rsquo;t too hard, there was many options but none were very well documented so I decided to write this quick tutorial.</p>
<h2 id="update-31-oct-2007-after-a-comment-from-josh-knowleshttpsjoshknowlescom-i-updated-the-tests-to-test-with-have_tags-built-in-rspec-and-hpricot">UPDATE 31 Oct 2007: After a comment from <a href="https://joshknowles.com">Josh Knowles</a>, I updated the tests to test with have_tags (built in RSpec) and hpricot.</h2>
<h2 id="hpricot">Hpricot</h2>
<p><a href="https://code.whytheluckystiff.net/hpricot/">hpricot</a> is a awesome HTML parser perfect for <a href="https://en.wikipedia.org/wiki/Screen_scraping">screen scraping</a>. But wait, there&rsquo;s more to this awesome library, <a href="https://code.whytheluckystiff.net/hpricot/wiki/HpricotXML">hpricot can also parse XML</a>.</p>
<p>If you watched the excellent <a href="https://peepcode.com/products">RSpec peepcasts</a> you probably noticed that <a href="https://topfunky.com/">topfunky</a> aka <a href="https://geoffreygrosenbach.com/">Geoffrey Grosenbach</a> uses hpricot to test a remote API.</p>
<p>In our case, we&rsquo;ll use hpricot to test that our generated XML follows our expectations.</p>
<h2 id="xml-builder--rspec">XML Builder + RSpec</h2>
<p>Let&rsquo;s write a quick test to make sure our controller uses a XML builder view:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;




  describe &lt;span class=&quot;co&quot;&gt;AveragesController&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;handling GET /averages.xml&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    before &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;co&quot;&gt;Average&lt;/span&gt;.stub!(&lt;span class=&quot;sy&quot;&gt;:find&lt;/span&gt;).and_return(&lt;span class=&quot;iv&quot;&gt;@average&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;do_get&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@request&lt;/span&gt;.env[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;HTTP_ACCEPT&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;] = &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;application/xml&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      get &lt;span class=&quot;sy&quot;&gt;:index&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;    it &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;should render the action using the XML builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      do_get&lt;tt&gt;
&lt;/tt&gt;      response.should render_template(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>To make this example pass, we need to modify our rspec generated controller.</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;




  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;index&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;iv&quot;&gt;@averages&lt;/span&gt; = &lt;span class=&quot;co&quot;&gt;Average&lt;/span&gt;.find(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;    respond_to &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |format|&lt;tt&gt;
&lt;/tt&gt;      format.html &lt;span class=&quot;c&quot;&gt;# index.html.erb&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      format.xml  { render &lt;span class=&quot;sy&quot;&gt;:action&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:layout&lt;/span&gt; =&gt; &lt;span class=&quot;pc&quot;&gt;false&lt;/span&gt; }&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>(Please note that I&rsquo;m using Rails 2.0 and that&rsquo;s why I&rsquo;m not using a .rxml view)</p>
<p>Here is what our XML file should end up looking like:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;




  &lt;&lt;span class=&quot;i&quot;&gt;?x&lt;/span&gt;ml version=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; encoding=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;UTF-8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;?&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;chart&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;series&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;co&quot;&gt;January&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&quot;1&quot;&gt;February&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;co&quot;&gt;March&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&quot;3&quot;&gt;April&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;co&quot;&gt;May&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&quot;5&quot;&gt;June&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;co&quot;&gt;July&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&quot;7&quot;&gt;August&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;co&quot;&gt;September&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&quot;9&quot;&gt;October&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;co&quot;&gt;November&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;value xid=&quot;11&quot;&gt;December&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;series&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;graphs&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;graph fill_alpha=&quot;50&quot; color=&quot;#FF0000&quot; fill_color=&quot;#CC0000&quot; title=&quot;high&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;0&quot;&gt;65.1&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;65.7&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;2&quot;&gt;64.9&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;66.7&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;4&quot;&gt;67.1&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;69.3&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;6&quot;&gt;73.0&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;74.8&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;8&quot;&gt;75.4&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;73.4&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;10&quot;&gt;68.9&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;65.3&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;graph&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;graph fill_alpha=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; color=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#0000CC&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; fill_color=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#0000CC&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; title=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;low&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;48.9&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;1&quot;&gt;50.7&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;52.9&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;3&quot;&gt;55.6&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;59.2&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;5&quot;&gt;61.9&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;65.7&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;7&quot;&gt;67.3&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;65.7&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;9&quot;&gt;61.0&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&gt;&lt;span class=&quot;fl&quot;&gt;54.0&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;value xid=&quot;11&quot;&gt;48.7&lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;value&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;graph&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt;graphs&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chart&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>Let&rsquo;s write some tests to make sure our view is ok:</p>
<p>index.xml.builder_spec.rb</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;35&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;45&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;54&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;55&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;56&lt;tt&gt;
&lt;/tt&gt;57&lt;tt&gt;
&lt;/tt&gt;58&lt;tt&gt;
&lt;/tt&gt;59&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;60&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;61&lt;tt&gt;
&lt;/tt&gt;62&lt;tt&gt;
&lt;/tt&gt;63&lt;tt&gt;
&lt;/tt&gt;64&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;65&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;66&lt;tt&gt;
&lt;/tt&gt;67&lt;tt&gt;
&lt;/tt&gt;68&lt;tt&gt;
&lt;/tt&gt;69&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;70&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;71&lt;tt&gt;
&lt;/tt&gt;72&lt;tt&gt;
&lt;/tt&gt;73&lt;tt&gt;
&lt;/tt&gt;74&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;75&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;76&lt;tt&gt;
&lt;/tt&gt;77&lt;tt&gt;
&lt;/tt&gt;78&lt;tt&gt;
&lt;/tt&gt;79&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;80&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;81&lt;tt&gt;
&lt;/tt&gt;




require &lt;span class=&quot;co&quot;&gt;File&lt;/span&gt;.dirname(&lt;span class=&quot;pc&quot;&gt;__FILE__&lt;/span&gt;) + &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/../../spec_helper&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;hpricot&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;describe &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  include &lt;span class=&quot;co&quot;&gt;AveragesHelper&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  before &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    average_1 = mock_model(&lt;span class=&quot;co&quot;&gt;Average&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    average_1.stub!(&lt;span class=&quot;sy&quot;&gt;:month&lt;/span&gt;).and_return(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;January&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    average_1.stub!(&lt;span class=&quot;sy&quot;&gt;:high&lt;/span&gt;).and_return(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;74.5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    average_1.stub!(&lt;span class=&quot;sy&quot;&gt;:low&lt;/span&gt;).and_return(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;61.5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    average_2 = mock_model(&lt;span class=&quot;co&quot;&gt;Average&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    average_2.stub!(&lt;span class=&quot;sy&quot;&gt;:month&lt;/span&gt;).and_return(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;February&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    average_2.stub!(&lt;span class=&quot;sy&quot;&gt;:high&lt;/span&gt;).and_return(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;82.5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    average_2.stub!(&lt;span class=&quot;sy&quot;&gt;:low&lt;/span&gt;).and_return(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;71.5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    assigns[&lt;span class=&quot;sy&quot;&gt;:averages&lt;/span&gt;] = [average_1, average_2]&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  it &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;should render the months in the series&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    render &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;January&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;February&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# Same thing but with Hpricot&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    doc = &lt;span class=&quot;co&quot;&gt;Hpricot&lt;/span&gt;.XML(response.body.to_s)&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:value&lt;/span&gt;).first.inner_html.should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;January&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:value&lt;/span&gt;)[&lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;].inner_html.should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;February&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  it &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;should set the xid attributes for the series&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    render &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value[xid=0]:first-child&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;value[xid=1]:last-child&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# Same thing but with Hpricot&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    doc = &lt;span class=&quot;co&quot;&gt;Hpricot&lt;/span&gt;.XML(response.body.to_s)&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:value&lt;/span&gt;).first[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;xid&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;].should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:value&lt;/span&gt;).last[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;xid&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;].should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  it &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;should have 2 graphs and they should have a title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    render &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;graph[title=high]:first-child&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;graph[title=low]:last-child&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# Same thing but with Hpricot&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    doc = &lt;span class=&quot;co&quot;&gt;Hpricot&lt;/span&gt;.XML(response.body.to_s)&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;).size.should == &lt;span class=&quot;i&quot;&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;).first[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;].should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;high&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;).last[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;].should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;low&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  it &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;should have a color set by graph&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    render &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;graph[color]:first-child&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;graph[color]:last-child&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;graph[fill_color]:last-child&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;graph[fill_alpha]:last-child&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# Same thing but with Hpricot&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    doc = &lt;span class=&quot;co&quot;&gt;Hpricot&lt;/span&gt;.XML(response.body.to_s)&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;).first[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;].should_not be_nil&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;).last[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;].should_not be_nil&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;).last[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fill_color&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;].should_not be_nil&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;).last[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fill_alpha&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;].should_not be_nil&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  it &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;should have an xid for each graph value&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    render &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;graph &gt; value[xid=0]:first-child&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# Same thing but with Hpricot&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    doc = &lt;span class=&quot;co&quot;&gt;Hpricot&lt;/span&gt;.XML(response.body.to_s)&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;/&lt;span class=&quot;sy&quot;&gt;:value&lt;/span&gt;).first[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;xid&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;].should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  it &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;should have the high average as values of the first graph&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    render &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    response.should have_tag(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;graph &gt; value:first-child&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;74.5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# Same thing but with Hpricot&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    doc = &lt;span class=&quot;co&quot;&gt;Hpricot&lt;/span&gt;.XML(response.body.to_s)&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;/&lt;span class=&quot;sy&quot;&gt;:value&lt;/span&gt;).first.inner_html.should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;74.5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>The first thing you must do (after installing the hpricot gem) is to require hpricot in your test:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




  require &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;hpricot&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>Now that hpricot is created we can use it to parse the response and check against our expectations.</p>
<p>(we create mock objects to pass to the view so we know exactly what to expect and we separate Model/Controller/Views tests)</p>
<p>To check against our response we have to use hpricot parser syntax. It might look at bit funny at first, but believe me it&rsquo;s really easy once you get it.</p>
<p>But first, let&rsquo;s parse the view:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;




&lt;span class=&quot;c&quot;&gt;# Render the mocked up data using the xml view&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;render &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;c&quot;&gt;# Load and parse the view response body:&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;doc = &lt;span class=&quot;co&quot;&gt;Hpricot&lt;/span&gt;.XML(response.body.to_s)
</code></pre>
<p>Let&rsquo;s look at the first test:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;




  it &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;should render the months in the series&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    render &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    doc = &lt;span class=&quot;co&quot;&gt;Hpricot&lt;/span&gt;.XML(response.body.to_s)&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:value&lt;/span&gt;).first.inner_html.should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;January&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:value&lt;/span&gt;)[&lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;].inner_html.should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;February&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>(doc/:value) returns all the value nodes, we take the first one and extract its content. We expect that it would match the name of the month for the first average.</p>
<p>Let&rsquo;s now look at another test:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;




  it &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;should have 2 graphs and they should have a title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    render &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    doc = &lt;span class=&quot;co&quot;&gt;Hpricot&lt;/span&gt;.XML(response.body.to_s)&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;).size.should == &lt;span class=&quot;i&quot;&gt;2&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;).first[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;].should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;high&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;).last[&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;].should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;low&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>The thing to look at here is the fact that we are checking on the node&rsquo;s attribute &ldquo;title&rdquo;. Really simple syntax and clean test, isn&rsquo;t it?</p>
<p>Finally let&rsquo;s look at the last example:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;




  it &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;should have the high average as values of the first graph&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    render &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/averages/index.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    doc = &lt;span class=&quot;co&quot;&gt;Hpricot&lt;/span&gt;.XML(response.body.to_s)&lt;tt&gt;
&lt;/tt&gt;    (doc/&lt;span class=&quot;sy&quot;&gt;:graph&lt;/span&gt;/&lt;span class=&quot;sy&quot;&gt;:value&lt;/span&gt;).first.inner_html.should == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;74.5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>We are checking that the content of the first value node nested inside a graph node is equal to 74.5 which is the high average for the first month.</p>
<p>In practice, you probably won&rsquo;t write all these tests at once, but anyway, let&rsquo;s look at our XML builder which will make all these tests pass:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;




xml.instruct! &lt;span class=&quot;sy&quot;&gt;:xml&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:version&lt;/span&gt;=&gt;&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:encoding&lt;/span&gt;=&gt;&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;UTF-8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;xml.chart &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  xml.series &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;iv&quot;&gt;@averages&lt;/span&gt;.each_with_index &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |average, index|&lt;tt&gt;
&lt;/tt&gt;      xml.value average.month, &lt;span class=&quot;sy&quot;&gt;:xid&lt;/span&gt; =&gt; index&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  xml.graphs &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    xml.graph &lt;span class=&quot;sy&quot;&gt;:title&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;high&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:color&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#FF0000&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:fill_alpha&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:fill_color&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#CC0000&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@averages&lt;/span&gt;.each_with_index &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |average, index|&lt;tt&gt;
&lt;/tt&gt;        xml.value average.high, &lt;span class=&quot;sy&quot;&gt;:xid&lt;/span&gt; =&gt; index&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;    xml.graph &lt;span class=&quot;sy&quot;&gt;:title&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;low&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:color&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#0000CC&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:fill_alpha&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:fill_color&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#0000CC&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@averages&lt;/span&gt;.each_with_index &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |average, index|&lt;tt&gt;
&lt;/tt&gt;        xml.value average.low, &lt;span class=&quot;sy&quot;&gt;:xid&lt;/span&gt; =&gt; index&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>Hpricot is a <em>really</em> nice tool which can make your BDD life much easier. And even if you don&rsquo;t do BDD/TDD yet, it&rsquo;s a great way to verify that any XML data you receive/generate is valid.</p>
<h2 id="happy-testing">Happy testing</h2>
]]></content>
		</item>
		
		<item>
			<title>freelancing</title>
			<link>https://matt.aimonetti.net/posts/2007-10-freelancing/</link>
			<pubDate>Mon, 15 Oct 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-10-freelancing/</guid>
			<description>I&amp;rsquo;ve been a freelancer/consultant/contractor/mercenary for many years now. However, until now, I used to do that on the side. Few months ago, after thinking a lot about it, I finally decided that freelancing was what I wanted to do. I left my job and started my own adventure.
The first reason for this switch was a desire to be more involved with my clients&#39; projects and accept bigger projects. Then there was the obvious flexibility brought by this new position (I can now work wherever I want, usually on my deck).</description>
			<content type="html"><![CDATA[<p>I&rsquo;ve been a freelancer/consultant/contractor/mercenary for many years now. However, until now, I used to do that on the side. Few months ago, after thinking a lot about it, I finally decided that freelancing was what I wanted to do. I left my job and started my own adventure.</p>
<p>The first reason for this switch was a desire to be <em>more involved</em> with my clients' projects and accept bigger projects. Then there was the obvious <em>flexibility</em> brought by this new position (I can now work wherever I want, usually on my deck). Finally I have to admit that <em>financially</em> things are better now.</p>
<p>This post won&rsquo;t be about helping you deciding if you should freelance or not. I&rsquo;m just curious to know how you work, how do you deal with your clients, deadlines, payments etc&hellip;
So instead of simply asking, I&rsquo;ll explain <em>how I do it</em> and I hope that <em>you will share your ways of doing it</em>.</p>
<h1 id="how-do-i-do-it">How do I do it?</h1>
<h2 id="choose-a-client">Choose a client</h2>
<p>Clients are the heart of your business. At first, you might be worried not to find enough work and you will take any project. <em>WRONG!</em> this is the worst thing you could do. You would not take any job just because they are willing to give you a salary, would you?</p>
<p><img src="https://farm2.static.flickr.com/1112/1465525142_0f9256d5d3_m.jpg" alt="https://flickr.com/photos/14304964@N05/1465525142/"></p>
<h2 id="i-find-a-match">I. find a match</h2>
<p>Personally, I believe in <a href="https://en.wikipedia.org/wiki/Agile_software_development">Agile methodologies</a>, regular code release, iteration planning, daily stand-ups, test driven development, continuous integration&hellip; This is what I call my <em>&lsquo;work values&rsquo;</em>.
If I see that a potential client&rsquo;s <em>&lsquo;work values&rsquo;</em> are opposite to mine. For instance, he might like the <a href="https://en.wikipedia.org/wiki/Waterfall_model">waterfall</a> approach, writing a lot of documentation before we start coding, doesn&rsquo;t see the essential need for a good test suite, then I know we would not be a good match.</p>
<p>It doesn&rsquo;t mean that I&rsquo;m right and she/he&rsquo;s wrong. It simply means we don&rsquo;t work the same way and that a work experience together might be frustrating for both of us.</p>
<p>A lot of clients don&rsquo;t know how to approach software development and they might not have strong &lsquo;values&rsquo; yet. In this case, I explain how I work and I try to read their reaction. Sometimes, you can agree on a &lsquo;trial period&rsquo;. Being freelance, you are more than likely free to quite whenever you want. However, you&rsquo;ll find out that is not a good experience for neither of you.</p>
<h2 id="ii-check-on-the-project">II. Check on the project</h2>
<p><img src="https://farm1.static.flickr.com/32/51227603_aa2e2da9e8_m.jpg" alt="https://flickr.com/photos/scutter/51227603/"></p>
<p>My first rule when it comes to choosing a project: <em>if it doesn&rsquo;t interest me, I don&rsquo;t take it</em>.</p>
<p>It&rsquo;s very simple: to do a good job, I need to be passionate. If the project is boring or simply doesn&rsquo;t attract me, I know I won&rsquo;t be able to serve my client the best I could.</p>
<p>Second rule: <em>Code review</em></p>
<p>Often, you might be contacted by people who already started a project but for some reason need you to take the project over. That happens often when a client tries to save money by taking the cheapest guys around (often overseas) and realize it doesn&rsquo;t work for them. Or maybe, your client&rsquo;s main developer had to leave and they need your help. Finally you have the case of a project growing and they simply need more people to work on it.</p>
<p>I always ask for a code review before I accept a job. Why? Simply because a CEO can tell how much he believes in Agile software development, that he has a portrait of <a href="https://www.loudthinking.com/">David Heinemeier Hansson</a> above his bed and that he knows <a href="https://gettingreal.37signals.com/">getting real</a> by heart, a quick look at the code will reveal the truth. It will also tell you a lot about the other guys who worked on the project.</p>
<ul>
<li>
<p><em>testing suite</em>: do they have any? Rspec? Unit test? Selenium? What&rsquo;s the test coverage? Do the tests pass?</p>
</li>
<li>
<p><em>test readability</em>: Did the developers try to be clever and the code is very obscure?</p>
</li>
<li>
<p><em>best practices</em>: Did the team follow most of the best practices? Why not?</p>
</li>
<li>
<p><em>reinventing the wheel</em>: Did they make a proper usage of plugins/gems.</p>
</li>
<li>
<p><em>living on the Edge</em>: Are they running on Rails Edge? Would it help?</p>
</li>
</ul>
<p>I usually don&rsquo;t worry much about how they deploy, since that can be changed easily.</p>
<p>Looking at your code review I try to evaluate few things:</p>
<ul>
<li>
<p>what&rsquo;s the team&rsquo;s tech level?</p>
</li>
<li>
<p>what kind of pressure the administrative people put on the tech team?</p>
</li>
<li>
<p>what do the teach value?</p>
</li>
<li>
<p>do I need to rewrite a lot of code?</p>
</li>
<li>
<p>do I seriously need to improve the test coverage?</p>
</li>
<li>
<p>is it a real mess and I&rsquo;d better give up before starting?</p>
</li>
</ul>
<p>A few months ago, <a href="https://iamruinous.com">Jade Meskill</a> recommended I read <a href="https://www.amazon.com/Dip-Little-Book-Teaches-Stick/dp/1591841666/">&ldquo;the dip&rdquo;</a> from <a href="https://sethgodin.typepad.com/">Seth Godin</a>. If you haven&rsquo;t read it yet, get a copy. It&rsquo;s a very simple and obvious book but it explains very well why and when you should give up and when you keep on struggling. And that&rsquo;s exactly what we are trying to do. We want to evaluate the effort needed to succeed (if it&rsquo;s doable).</p>
<h2 id="iii-build-a-relationship">III. Build a relationship</h2>
<p><img src="https://farm2.static.flickr.com/1218/1412917482_45b1a1ceaf_m.jpg" alt="https://flickr.com/photos/senor_codo/1412917482/"></p>
<p>Business is all about relationship. Both your client and you have needs. By creating a relationship you will try to fulfill most of your needs. Let&rsquo;s look at an evaluation of my professional needs:</p>
<ul>
<li>
<p>I need to be challenged</p>
</li>
<li>
<p>I need communication</p>
</li>
<li>
<p>I need guidance</p>
</li>
<li>
<p>I need deadlines</p>
</li>
<li>
<p>I need results</p>
</li>
<li>
<p>I need to be valued</p>
</li>
</ul>
<p>And here is what I cam up with when I tried to estimate my client needs:</p>
<ul>
<li>
<p>he needs business value</p>
</li>
<li>
<p>he needs to feel special</p>
</li>
<li>
<p>he needs to be reassured</p>
</li>
<li>
<p>he needs to keep control over the finance</p>
</li>
<li>
<p>he needs to make sure he doesn&rsquo;t waste money/time with me</p>
</li>
<li>
<p>he needs to plan the future</p>
</li>
</ul>
<p>There we go, we have the base of our relationship. As long as most of our needs are fulfilled, the relationship should be strong.</p>
<p>As you can see by looking at the list above, the client needs to be convinced that I am the perfect fit they were looking for. On my side, I want them to realize that we are lucky to work together and I want them to value me.</p>
<p>Money makes the world go round, especially in a business relationship and especially in the Western world.
Your rates are a simple way to say, this is what I&rsquo;m worth. If you are willing to pay my rates, you are valuing me. Obviously rates can be negotiated but be careful, somehow they will always represent your value.</p>
<p>So how do I build this relationship?</p>
<ul>
<li>be frank, open and transparent.</li>
</ul>
<p>I don&rsquo;t want my clients to feel that I&rsquo;m hiding things from them. For instance, I&rsquo;m always running two projects at the same time and I make that really clear at the beginning before I start working on a contract. My client A knows that I will work 17-20 hours a week on his project and 17-20 hours on a different project. If I have to miss one of our stand-up, I usually explain why.</p>
<p><em>Trust is very important when you are an outsider and even more when you work remotely.</em></p>
<ul>
<li>Provide visible business value on a weekly basis.</li>
</ul>
<p>At least once a week, I have a <em>quick demo</em> with my clients and if possible their co-workers. This demo is really important for a client since he can then <em>visualize</em> the business value added to his product. He will feel <em>in control</em>, <em>reassured</em> and will be able to <em>evaluate the situation</em> and <em>plan the future</em> of the product. Usually clients who worked with other developers/methodologies also <em>feel special</em> since they would usually only see business value at the end of the project. By the way, the demo is usually done on the production application so we are talking about real business value.</p>
<ul>
<li>Make the client the center of the decision making process</li>
</ul>
<p>In my usual process, we have a special meeting every monday. During this meeting, we plan the work for the coming week/iteration. I simply help the client breaking down his tasks in small chunks that we could handle in a week. During this meeting we also agree on this iteration priorities. In general we already created a queue/backlogs of tasks that need to be executed. I simply let the client make his choice to what is <em>really</em> important. In general a client wants everything done right away exactly how he has it mind. Well&hellip; the reality is <em>really</em> different. A client doesn&rsquo;t have to understand the concept of polymorphic association to make decisions. Actually, he doesn&rsquo;t care how you do it as long as it&rsquo;s well done. However, your client should know how to prioritize things, he probably already does that all day long.
Converting the technical details into simple concepts that make sense to both you and the client will seriously help the project. I don&rsquo;t have to worry about delays, I don&rsquo;t make these decisions, my client does that for me and he likes having control over budget/time line.</p>
<p><em>To sum-up, I believe that by choosing a client that matches my view of software development, a project that sounds interesting to me and building a strong relationship, we will have a good end result and a win-win situation.</em></p>
<h2 id="what-about-you-how-do-you-manage-your-projects-clients-do-you-agree-with-me-or-do-you-think-im-idealist-and-in-the-real-world-things-dont-happen-like-that">What about you? How do you manage your projects, clients? Do you agree with me, or do you think I&rsquo;m idealist and in the real world things don&rsquo;t happen like that?</h2>
]]></content>
		</item>
		
		<item>
			<title>sexy charts in less than 5 minutes</title>
			<link>https://matt.aimonetti.net/posts/2007-10-sexy-charts-in-less-than-5-minutes/</link>
			<pubDate>Thu, 04 Oct 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-10-sexy-charts-in-less-than-5-minutes/</guid>
			<description>date = &amp;ldquo;NOV&amp;rdquo; slug = &amp;ldquo;NOV/sexy-charts-in-less-than-5-minutes&amp;rdquo;
Last time, in our &amp;lsquo;do it in less than 5 minutes&amp;rsquo; series, we saw how to add quickly and simply add Ajax pagination.
This time we&amp;rsquo;ll see how to add some sexy/fancy charts to your rails app.
The goal is to end up with something like:
Various options You might have heard or even tried solution such as Gruff or JFreeChart.
While these solutions are great, they are certainly a pain in the butt.</description>
			<content type="html"><![CDATA[<p>date = &ldquo;NOV&rdquo;
slug = &ldquo;NOV/sexy-charts-in-less-than-5-minutes&rdquo;</p>
<p><a href="https://railsontherun.com/2007/9/27/ajax-pagination-in-less-than-5-minutes">Last time</a>, in our <em>&lsquo;do it in less than 5 minutes&rsquo;</em> series, we saw how to add <a href="https://railsontherun.com/2007/9/27/ajax-pagination-in-less-than-5-minutes">quickly and simply add Ajax pagination</a>.</p>
<p>This time we&rsquo;ll see how to add some sexy/fancy charts to your rails app.</p>
<p>The goal is to end up with something like:</p>
<p><img src="https://farm2.static.flickr.com/1322/1480241002_e67637a659_o.png" alt="chart"></p>
<p><img src="https://farm2.static.flickr.com/1414/1479377969_805d23a55d_o.png" alt="charts2"></p>
<h2 id="various-options">Various options</h2>
<p>You might have heard or even tried solution such as <a href="https://nubyonrails.com/pages/gruff">Gruff</a> or <a href="https://www.jfree.org/jfreechart/">JFreeChart</a>.</p>
<p>While these solutions are great, they are certainly a pain in the butt. Gruff requires RMagick (avoid RMagick as much as can) and creates static files (a real pain when your graphs change all the time) JFreeChart on the other hand requires Java, Java skills and I hate <a href="https://wiki.rubyonrails.org/rails/pages/HowtoGenerateJFreeCharts">the way</a> you create graphs:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;




  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;CreateChart&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;         pipe = &lt;span class=&quot;co&quot;&gt;IO&lt;/span&gt;.popen &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;java -cp C:&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;InstantRails&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;rails_apps&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;jfree&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;src;C:&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;InstantRails&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;rails_apps&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;jfree&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;jcommon-1.0.0-rc1.jar;C:&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;InstantRails&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;rails_apps&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;project&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;jfree&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;ch&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;jfreechart-1.0.0-rc1.jar; CreateChart&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;         pipe.close&lt;tt&gt;
&lt;/tt&gt;         redirect_to &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/graph/report&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>Anyway, none of these solutions would let us create our charts in less than 5 minutes so let&rsquo;s cut the story short. The best solution IMHO is to use Flash. But <em>wait</em>, you don&rsquo;t need to know ActionScript or to own a license of Flash or Flex, we have libraries available for us to use without any Flash knowledge :)</p>
<p><a href="https://www.maani.us/xml_charts/index.php?menu=Gallery">XML/SWF</a> is cool Flash library which should fulfill our needs, you can even find a <a href="https://ziya.liquidrail.com/">rails plugin</a> to make things easier.</p>
<h2 id="amcharts">amCharts</h2>
<p>But, to be honest I&rsquo;d like to have something a bit &ldquo;cleaner/sexy/fancy&rdquo; and easier to setup.  So we&rsquo;re going to use <a href="https://www.amcharts.com/">amCharts</a>  Don&rsquo;t get me wrong, XML/SWF is a great library and you can make your graphs look nice (but you have to pay for support).
Since we are running out of time let&rsquo;s see how to implement a nice graph using <em>my</em> favorite library.</p>
<p><img src="https://www.amcharts.com/images/logo.gif" alt="amcharts"></p>
<p>[DISCLAIMER: amCharts is <em>NOT open source</em> and <em>NOT free</em>. But, it&rsquo;s <em>cheap</em> (85 euros per site) especially when you think of how much time you will save. AND there is a <em>FREE version</em>. The Free version is the same as the full version but with a link back to amcharts.com]</p>
<h2 id="setup">Setup</h2>
<p>Let&rsquo;s go ahead and download one of the package: <a href="https://www.amcharts.com/column/download/">https://www.amcharts.com/column/download/</a> for instance.</p>
<p>Unpack the files and put them in their own folder in your public folder.
Make sure you have the .swf file (amcolumn.swf for instance), a XML settings file and the fonts folder.
(You might want to also create an empty amcharts_key.txt in the same folder since the plugin tries to load the key and you don&rsquo;t want to pollute your logs.)</p>
<h2 id="usage">Usage</h2>
<p>Now you need to understand how amCharts works.</p>
<p>After being loaded, amCharts expects a datastream. The datastream is then parsed and displayed as a chart.
You can modify the aspect of any chart by changing its settings.
Settings are set at runtime and/or in a setting file.</p>
<p>Great! I won&rsquo;t cover the settings file. It&rsquo;s a well documented XML file you just copied in your public folder. (or check the documentation)</p>
<p>What we want to focus on, is the <em>datastream</em>. Basically we just need to create a XML file that can be parsed by amCharts.</p>
<p>Let&rsquo;s imagine that we have a reports_controller.rb file  We want to display the population of the cities in California.</p>
<p>let&rsquo;s add a new action to render our XML file:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;




  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;population&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;iv&quot;&gt;@cities&lt;/span&gt; = &lt;span class=&quot;co&quot;&gt;City&lt;/span&gt;.find(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;iv&quot;&gt;@population_data_link&lt;/span&gt; = formatted_population_reports_url(&lt;span class=&quot;sy&quot;&gt;:xml&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;    respond_to &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |format|&lt;tt&gt;
&lt;/tt&gt;      format.html&lt;tt&gt;
&lt;/tt&gt;      format.xml  { render &lt;span class=&quot;sy&quot;&gt;:action&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;population.xml.builder&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:layout&lt;/span&gt; =&gt; &lt;span class=&quot;pc&quot;&gt;false&lt;/span&gt; }&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>(notice that I&rsquo;m using rails 2.0 and that&rsquo;s why my XML template is not RXML)</p>
<p>As you can see, we have 2 values: @cities and @population_data_link</p>
<p>@cities contains all the City records, including their population etc..</p>
<p>@population_data_link contains the url to retrieve the datastream.</p>
<p>If you wonder how I got this url? I&rsquo;m simply using a named route defined in my routes.rb:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




  map.resources &lt;span class=&quot;sy&quot;&gt;:reports&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:collection&lt;/span&gt; =&gt; {&lt;span class=&quot;sy&quot;&gt;:population&lt;/span&gt; =&gt; &lt;span class=&quot;sy&quot;&gt;:get&lt;/span&gt;}
</code></pre>
<p>(note that you don&rsquo;t need to create a restful route for that, a simple named route would have worked too)</p>
<h2 id="flash-detection">Flash detection</h2>
<p>Since we are going to use Flash, we want to make sure that people have the Flash plugin installed on their browser. For that we will use <a href="https://blog.deconcept.com/swfobject/">swfobject</a>. Simply make sure to add swfobject.js (available in any amChart package) to your public/javascript folder. Then make sure you linked the javascript in your header:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




  &lt;%= javascript_include_tag &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;swfobject&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>We now need to create our 2 views: <em>population.html.erb</em> and <em>population.xml.builder</em></p>
<h2 id="populationhtmlerb">population.html.erb</h2>
<p>Basically, this view only loads amCharts and provides it with the details of the datastream:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;




  &lt;div id=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;population_chart&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chart&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;strong&gt;&lt;span class=&quot;co&quot;&gt;Text&lt;/span&gt; displayed &lt;span class=&quot;r&quot;&gt;when&lt;/span&gt; the user doesn&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;t have Flash. You might want to display a simple table with the population, search engines and visitor without flash would love that.&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;p&gt; To see this page properly, you need to upgrade your Flash Player, please visit the Adobe web site&lt;/p&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;/div&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;script type=&quot;text/javascript&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;    // &lt;![CDATA[    &lt;tt&gt;
&lt;/tt&gt;    var so = new SWFObject(&quot;/amcolumn/amcolumn.swf&quot;, &quot;population_chart&quot;, &quot;800&quot;, &quot;380&quot;, &quot;8&quot;, &quot;#000000&quot;);&lt;tt&gt;
&lt;/tt&gt;    so.addVariable(&quot;path&quot;, &quot;/amcolumn/&quot;);&lt;tt&gt;
&lt;/tt&gt;    so.addVariable(&quot;settings_file&quot;, escape(&quot;/amcolumn/column_settings.xml&quot;));&lt;tt&gt;
&lt;/tt&gt;    so.addVariable(&quot;data_file&quot;, escape(&quot;&lt;%= @population_data_link %&gt;&quot;));&lt;tt&gt;
&lt;/tt&gt;    so.addVariable(&quot;additional_chart_settings&quot;, &quot;&lt;settings&gt;&lt;labels&gt;&lt;label&gt;&lt;x&gt;250&lt;/x&gt;&lt;y&gt;25&lt;/y&gt;&lt;text_size&gt;18&lt;/text_size&gt;&lt;text&gt;&lt;![CDATA[&lt;b&gt;California Population as of &lt;%= Time.now.to_s(:db) %&gt;&lt;/b&gt;]]&gt;&lt;/text&gt;&lt;/label&gt;&lt;/labels&gt;&lt;/settings&gt;&quot;);&lt;tt&gt;
&lt;/tt&gt;    so.addVariable(&quot;preloader_color&quot;, &quot;#000000&quot;);&lt;tt&gt;
&lt;/tt&gt;    so.write(&quot;population_chart&quot;);&lt;tt&gt;
&lt;/tt&gt;    // ]]&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;/script&gt;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>As you can see, we have a div called population_chart. This div is replaced at load time by the Flash object if the visitor has Flash setup locally. Think about providing some data in case the user doesn&rsquo;t have Flash.</p>
<p>The rest is simple Javascript. I unpacked the amchart column lib in mypublic/amcolumn folder and that&rsquo;s why I setup the path as &ldquo;amcolumn&rdquo;</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




  so.addVariable(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/amcolumn/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;);
</code></pre>
<p>My settings file is called column_settings.xml :</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




  so.addVariable(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;settings_file&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, escape(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;/amcolumn/column_settings.xml&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;));
</code></pre>
<p>and the most important part:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




  so.addVariable(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;data_file&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, escape(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;%= @population_data_link %&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;));
</code></pre>
<p>Finally, I added some dynamic settings just to show you how easy it is:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;




  so.addVariable(&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;additional_chart_settings&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;,&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;settings&gt;&lt;labels&gt;&lt;label&gt;&lt;x&gt;250&lt;/x&gt;&lt;y&gt;25&lt;/y&gt;&lt;text_size&gt;18&lt;/text_size&gt;&lt;text&gt;&lt;![CDATA[&lt;b&gt;California Population as of &lt;%= Time.now.to_s(:db) %&gt;&lt;/b&gt;]]&gt;&lt;/text&gt;&lt;/label&gt;&lt;/labels&gt;&lt;/settings&gt;&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;);
</code></pre>
<p>Ok, let&rsquo;s now create our XML view:</p>
<h2 id="populationxmlbuilder">population.xml.builder</h2>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;15&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;25&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;




  xml.instruct! &lt;span class=&quot;sy&quot;&gt;:xml&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:version&lt;/span&gt;=&gt;&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:encoding&lt;/span&gt;=&gt;&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;UTF-8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  xml.chart &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;c&quot;&gt;# xml.message &quot;You can broadcast any message to chart from data XML file&quot;, :bg_color =&gt; &quot;#FFFFFF&quot;, :text_color =&gt; &quot;#000000&quot;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    xml.series &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;    &lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@cities&lt;/span&gt;.each_with_index &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |city, index|&lt;tt&gt;
&lt;/tt&gt;        xml.value city.name, &lt;span class=&quot;sy&quot;&gt;:xid&lt;/span&gt; =&gt; index&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    xml.graphs &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;     &lt;span class=&quot;c&quot;&gt;#the gid is used in the settings file to set different settings just for this graph&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      xml.graph &lt;span class=&quot;sy&quot;&gt;:gid&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;population&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;iv&quot;&gt;@cities&lt;/span&gt;.each_with_index &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |city, index|&lt;tt&gt;
&lt;/tt&gt;          population = city.population&lt;tt&gt;
&lt;/tt&gt;          &lt;span class=&quot;r&quot;&gt;case&lt;/span&gt; population&lt;tt&gt;
&lt;/tt&gt;            &lt;span class=&quot;c&quot;&gt;# When the population is &gt; 1 million, show the bar in red/pink&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;            &lt;span class=&quot;r&quot;&gt;when&lt;/span&gt; &gt; &lt;span class=&quot;i&quot;&gt;100000&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;              xml.value value, &lt;span class=&quot;sy&quot;&gt;:xid&lt;/span&gt; =&gt; index, &lt;span class=&quot;sy&quot;&gt;:color&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#ff43a8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:gradient_fill_colors&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#960040,#ff43a8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:description&lt;/span&gt; =&gt; level&lt;tt&gt;
&lt;/tt&gt;            &lt;span class=&quot;r&quot;&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;              xml.value value, &lt;span class=&quot;sy&quot;&gt;:xid&lt;/span&gt; =&gt; index, &lt;span class=&quot;sy&quot;&gt;:color&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#00C3C6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:gradient_fill_colors&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#009c9d,#00C3C6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:description&lt;/span&gt; =&gt; level&lt;tt&gt;
&lt;/tt&gt;            &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>Nothing fancy, we first created a series with all the city names:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;




  xml.series &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;    &lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;iv&quot;&gt;@cities&lt;/span&gt;.each_with_index &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |city, index|&lt;tt&gt;
&lt;/tt&gt;      xml.value city.name, &lt;span class=&quot;sy&quot;&gt;:xid&lt;/span&gt; =&gt; index&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>Then we created another node with the values for each city.
Since it would be cool to display some bars in a different color, we used a case-switch statement:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;




    xml.graph &lt;span class=&quot;sy&quot;&gt;:gid&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;population&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;iv&quot;&gt;@cities&lt;/span&gt;.each_with_index &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |city, index|&lt;tt&gt;
&lt;/tt&gt;        population = city.population&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;r&quot;&gt;case&lt;/span&gt; population&lt;tt&gt;
&lt;/tt&gt;          &lt;span class=&quot;c&quot;&gt;# When the population is &gt; 1 million, show the bar in red/pink&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;          &lt;span class=&quot;r&quot;&gt;when&lt;/span&gt; &gt; &lt;span class=&quot;i&quot;&gt;100000&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;            xml.value value, &lt;span class=&quot;sy&quot;&gt;:xid&lt;/span&gt; =&gt; index, &lt;span class=&quot;sy&quot;&gt;:color&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#ff43a8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:gradient_fill_colors&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#960040,#ff43a8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:description&lt;/span&gt; =&gt; level&lt;tt&gt;
&lt;/tt&gt;          &lt;span class=&quot;r&quot;&gt;else&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;            xml.value value, &lt;span class=&quot;sy&quot;&gt;:xid&lt;/span&gt; =&gt; index, &lt;span class=&quot;sy&quot;&gt;:color&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#00C3C6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:gradient_fill_colors&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;#009c9d,#00C3C6&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:description&lt;/span&gt; =&gt; level&lt;tt&gt;
&lt;/tt&gt;          &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>Depending on what you want to display, you might need to have different colors or a different tooltip text, or load an animation or image&hellip;  and as you can see, it&rsquo;s <em>REALLY</em> easy.</p>
<p>Got to <a href="https://yoursite.com/reports/population">https://yoursite.com/reports/population</a> to enjoy your new fancy graph.</p>
<h2 id="thats-it-you-are-done">That&rsquo;s it, you are done!</h2>
<p>Time to tweak your settings file to make your graph look <em>awesome</em>.
Since you now have a lot of free time, you can start re-factoring your code and make sure you have a good test coverage.</p>
<p>Good luck!</p>
]]></content>
		</item>
		
		<item>
			<title>ajax pagination in less than 5 minutes</title>
			<link>https://matt.aimonetti.net/posts/2007-09-ajax-pagination-in-less-than-5-minutes/</link>
			<pubDate>Thu, 27 Sep 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-09-ajax-pagination-in-less-than-5-minutes/</guid>
			<description>updated Nov 26 to reflect the recent low pro changes. (please use low pro 0.5 and Prototype 1.6) Recently one of my client asked me to add &amp;lsquo;ajax&amp;rsquo; pagination to his application. His site already had a very nice pagination using the excellent will_paginate from Mislav and the guys(PJ &amp;amp; Chris) from err the blog but since my client had a special need where he had to have Ajax.
It took me virtually no time to convert the standard pagination into an Ajax navigation while still degrading gracefully.</description>
			<content type="html"><![CDATA[<h2 id="updated-nov-26-to-reflect-the-recent-low-pro-changes-please-use-low-pro-05-and-prototype-16">updated Nov 26 to reflect the recent low pro changes. (please use low pro 0.5 and Prototype 1.6)</h2>
<p>Recently one of my client asked me to add &lsquo;ajax&rsquo; pagination to his application. His site already had a very nice pagination using the excellent <a href="https://plugins.require.errtheblog.com/browser/will_paginate">will_paginate</a> from <a href="https://www.workingwithrails.com/person/2764-mislav-marohni">Mislav</a> and the guys(PJ &amp; Chris) from <a href="https://errtheblog.com/">err the blog</a> but since my client had a special need where he had to have Ajax.</p>
<p>It took me <strong>virtually no time to convert the standard pagination into an Ajax navigation</strong> while still degrading gracefully.(it works even without Javascript)</p>
<p>I really enjoy using will_paginate, it&rsquo;s very well written and the authors keep up with the <a href="https://err.lighthouseapp.com/projects/466-plugins/tickets?q=tagged%3Awill_paginate">bugs</a> and <a href="https://err.lighthouseapp.com/projects/466-plugins/tickets?q=tagged%3Awill_paginate">new features</a>.</p>
<h2 id="start-by-installing-will_paginate">Start by installing will_paginate:</h2>
<pre><code>&lt;code&gt;ruby script/plugin install svn://errtheblog.com/svn/plugins/will_paginate
&lt;/code&gt;
</code></pre>
<h2 id="then-go-watch-the-railcast-screencasthttpsrailscastscomepisodes51-about-will-paginate">Then go watch the <a href="https://railscasts.com/episodes/51">Railcast screencast</a> about will paginate.</h2>
<p>Once you have your pagination working, we will do some &lsquo;<a href="https://en.wikipedia.org/wiki/Progressive_enhancement">progressive enhancement</a>&rsquo;.</p>
<p>What we want is to <strong>add a behavior to the pagination link</strong>. The behavior would make the same call than the normal link but via an ajax(Javascript) call.</p>
<h2 id="add-lowpro">Add lowpro</h2>
<p>To do that, you simply need to add the excellent <a href="https://www.danwebb.net/lowpro">&lsquo;lowpro&rsquo;</a> Prototype extension from <a href="https://www.danwebb.net">Dan Webb</a></p>
<p>You can get the files directly from the <a href="https://svn.danwebb.net/external/lowpro/trunk/dist/lowpro.js">lowpro&rsquo;s repository</a>.</p>
<p>Add <a href="https://svn.danwebb.net/external/lowpro/trunk/dist/lowpro.js">lowpro.js</a> to your public/javascript folder.</p>
<p>Don&rsquo;t forget to include the javascript in your page. (</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  &lt;%= javascript_include_tag &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;lowpro&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;%&gt;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<h2 id="create-a-behavior">Create a behavior</h2>
<p>Now open your application.js file (or whichever Javascript file you&rsquo;re using) and add the following:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;Event&lt;/span&gt;.addBehavior.reassignAfterAjax = &lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt;;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;co&quot;&gt;Event&lt;/span&gt;.addBehavior({&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;div.pagination a&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt; : &lt;span class=&quot;co&quot;&gt;Remote&lt;/span&gt;.&lt;span class=&quot;co&quot;&gt;Link&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  })&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>Refresh your cache, reload your page, and test the link. It will probably look like it doesn&rsquo;t do anything but if you are using <a href="https://www.getfirebug.com/">firebug</a> or if you are checking your logs, you&rsquo;ll notice something happened. The problem is that we didn&rsquo;t tell our action to send an Ajax response so we get the html full page all over again.</p>
<h2 id="setup-a-response-for-javascript-requests">Setup a response for javascript requests</h2>
<p>Got to your action handling the pagination and let&rsquo;s setup a response for Javascript:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;




&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;index&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;iv&quot;&gt;@photos&lt;/span&gt; = &lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.paginate(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:conditions&lt;/span&gt; =&gt; [&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;photos.user_id = ?&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, current_user.id], &lt;span class=&quot;sy&quot;&gt;:page&lt;/span&gt; =&gt; params[&lt;span class=&quot;sy&quot;&gt;:page&lt;/span&gt;])&lt;tt&gt;
&lt;/tt&gt;    respond_to &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |format|&lt;tt&gt;
&lt;/tt&gt;      format.html &lt;span class=&quot;c&quot;&gt;# index.html.erb&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      format.js &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        render &lt;span class=&quot;sy&quot;&gt;:update&lt;/span&gt; &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |page|&lt;tt&gt;
&lt;/tt&gt;          page.replace_html &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;photos&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:partial&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;photos&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;
</code></pre>
<p>Perfect! Now when a visitor clicks on my pagination links, only the photos are paginated, the rest of the page stays the same. Note that my navigation bar is inside the partial so it gets &lsquo;updated&rsquo; after a visitor clicks on any pagination link.</p>
<h2 id="read-more-and-convert-to-ujs-unobtrusive-javascript">Read more and convert to UJS (unobtrusive javascript)</h2>
<p>Read more about <a href="https://jlaine.net/2007/8/3/from-rails-ajax-helpers-to-low-pro-part-i">UJS</a> and think about replacing all your nasty inline javascript snippets by pretty behaviors :) (Think about stopping using the obtrusive rails helpers)</p>
]]></content>
		</item>
		
		<item>
			<title>my rails contribution mentioned in dhh keynote</title>
			<link>https://matt.aimonetti.net/posts/2007-09-my-rails-contribution-mentioned-in-dhh-keynote/</link>
			<pubDate>Wed, 19 Sep 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-09-my-rails-contribution-mentioned-in-dhh-keynote/</guid>
			<description>That&amp;rsquo;s kind of cool, I was reading a post about DHH Keynote at RailsConf Europe when I realized that DHH mentioned one of my contribution to Rails Edge.
&amp;ldquo;small, but to me significant improvement has also found its way to Rails 2.0: You can now create the needed databases with a rake command. By running this command, all referenced databases in your database.yml will be created&amp;rdquo;
&amp;lt;tt&amp;gt; &amp;lt;/tt&amp;gt; rake db&amp;lt;span class=&amp;quot;sy&amp;quot;&amp;gt;:create&amp;lt;/span&amp;gt;&amp;lt;span class=&amp;quot;sy&amp;quot;&amp;gt;:all&amp;lt;/span&amp;gt;  I&amp;rsquo;m glad to see that my contribution is appreciated, as a reminder you also have the following options:</description>
			<content type="html"><![CDATA[<p>That&rsquo;s kind of cool, I was reading a <a href="https://casperfabricius.com/blog/2007/09/18/railsconf2007-dhh/">post</a> about DHH Keynote at RailsConf Europe when I realized that DHH mentioned one of my contribution to Rails Edge.</p>
<p>&ldquo;small, but to me significant improvement has also found its way to Rails 2.0: You can now create the needed databases with a rake command. By running this command, all referenced databases in your database.yml will be created&rdquo;</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




rake db&lt;span class=&quot;sy&quot;&gt;:create&lt;/span&gt;&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;
</code></pre>
<p>I&rsquo;m glad to see that my contribution is appreciated, as a reminder you also have the following options:</p>
<p>Only create your current environment database (can be useful to bootstrap your application):</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




rake db&lt;span class=&quot;sy&quot;&gt;:create&lt;/span&gt;
</code></pre>
<p>Another command I use often in development is:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




rake db&lt;span class=&quot;sy&quot;&gt;:reset&lt;/span&gt;
</code></pre>
<p>It simply drops your current environment database, re create it and migrate it :)
(btw, your new database will be utf-8 by default)</p>
<p>Here is a list of the new rake tasks:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;




rake db&lt;span class=&quot;sy&quot;&gt;:create&lt;/span&gt;                       &lt;span class=&quot;c&quot;&gt;# Create the local database defined in config/database.yml for the current RAILS_ENV&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;rake db&lt;span class=&quot;sy&quot;&gt;:create&lt;/span&gt;&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;                   &lt;span class=&quot;c&quot;&gt;# Create all the local databases defined in config/database.yml&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;rake db&lt;span class=&quot;sy&quot;&gt;:drop&lt;/span&gt;                         &lt;span class=&quot;c&quot;&gt;# Drops the database for the current environment&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;rake db&lt;span class=&quot;sy&quot;&gt;:reset&lt;/span&gt;                         &lt;span class=&quot;c&quot;&gt;# Drops, creates and then migrates the database for the current environment. Target specific version with VERSION=x&lt;/span&gt;
</code></pre>
<p>Read DHH Keynote summary <a href="https://casperfabricius.com/blog/2007/09/18/railsconf2007-dhh/">there</a></p>
]]></content>
		</item>
		
		<item>
			<title>ambition why should you care</title>
			<link>https://matt.aimonetti.net/posts/2007-09-ambition-why-should-you-care/</link>
			<pubDate>Sun, 16 Sep 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-09-ambition-why-should-you-care/</guid>
			<description>By now, you should have heard about ambition if not read the latest post from the author.
Ambition has a simple goal: making you stop writing SQL in your queries and only stick to Ruby. (who cares if you use ActiveRecord, Sequel, DataMapper or another ORM)
I&amp;rsquo;m so used to the ActiveRecord way of querying the database that I was not fully convinced that Ambition would help me in my daily tasks.</description>
			<content type="html"><![CDATA[<p><img src="https://errtheblog.com/static/images/ambition-tower.png" alt="ambition"></p>
<p>By now, you should have heard about <a href="https://errtheblog.com/post/10722">ambition</a> if not <a href="https://errtheblog.com/post/11998">read the latest post from the author</a>.</p>
<p><strong>Ambition has a simple goal: making you stop writing SQL in your queries and only stick to Ruby. (who cares if you use ActiveRecord, Sequel, DataMapper or another ORM)</strong></p>
<p>I&rsquo;m so used to the ActiveRecord way of querying the database that I was not fully convinced that Ambition would help me in my daily tasks. I still gave it a try:</p>
<h2 id="testing-ambition">Testing Ambition</h2>
<pre><code>&lt;code&gt;$ sudo gem install ambition -y
&lt;/code&gt;
</code></pre>
<p>Started my console</p>
<pre><code>&lt;code&gt;$ script/console
&lt;/code&gt;
</code></pre>
<p>and required Ambition</p>
<pre><code>&lt;code&gt;require 'ambition'
&lt;/code&gt;
</code></pre>
<p>I started by doing a query the AR way:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;




 &lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.find(&lt;span class=&quot;sy&quot;&gt;:all&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:conditions&lt;/span&gt; =&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;photos.title IS NULL AND photos.width &gt; 250 &lt;tt&gt;
&lt;/tt&gt;AND photos.height &gt; 200 AND users.name = 'test'&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:include&lt;/span&gt; =&gt; &lt;span class=&quot;sy&quot;&gt;:user&lt;/span&gt;)
</code></pre>
<p>And I converted it into an Ambition call:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




&lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.select {|p| p.title == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; &amp;&amp; p.width &gt; &lt;span class=&quot;i&quot;&gt;250&lt;/span&gt; &amp;&amp; p.height &gt; &lt;span class=&quot;i&quot;&gt;200&lt;/span&gt;  &amp;&amp; p.user.name == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}.entries
</code></pre>
<p>145 vs 102 keystrokes. 30% less typing with Ambition! I don&rsquo;t know about you, but I REALLY prefer the Ruby only query, much cleaner and much &ldquo;DRYer&rdquo;. However, that&rsquo;s not always true:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




&lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.find_by_title(&lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt;)
</code></pre>
<p>(24chars)</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




&lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.detect{|p| p.title == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt;}
</code></pre>
<p>(32 chars)</p>
<p>But what&rsquo;s going on behind the scene? Do we have the exact same SQL query sent to our DB?</p>
<p>Well, Ambition doesn&rsquo;t generate any SQL, it uses AR to do so. You want to make sure Ambition is not messing with you, try that:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;




 &gt;&gt; &lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.select {|p| p.title == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; &amp;&amp; p.width &gt; &lt;span class=&quot;i&quot;&gt;250&lt;/span&gt; &amp;&amp; p.height &gt; &lt;span class=&quot;i&quot;&gt;200&lt;/span&gt;  &amp;&amp; p.user.name == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}.to_hash&lt;tt&gt;
&lt;/tt&gt; =&gt; {&lt;span class=&quot;sy&quot;&gt;:conditions&lt;/span&gt;=&gt;&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;(photos.`title` IS NULL AND (photos.`width` &gt; 250 AND (photos.`height` &gt; 200 AND users.name = 'test')))&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:include&lt;/span&gt;=&gt;[&lt;span class=&quot;sy&quot;&gt;:user&lt;/span&gt;]}
</code></pre>
<p>That&rsquo;s pretty hot. Especially when you have to use eager loading!</p>
<p>Obviously you can still do stuff like that:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;




&lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.select {|p| p.title == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; &amp;&amp; p.width &gt; &lt;span class=&quot;i&quot;&gt;250&lt;/span&gt; &amp;&amp; p.height &gt; &lt;span class=&quot;i&quot;&gt;200&lt;/span&gt;  &amp;&amp; p.user.name == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}.each &lt;span class=&quot;r&quot;&gt;do&lt;/span&gt; |photo|&lt;tt&gt;
&lt;/tt&gt; puts photo.filename&lt;tt&gt;
&lt;/tt&gt;&lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;
</code></pre>
<p>(note the query will only be made once)</p>
<p>Another cool thing, is to do simple sorting:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




&gt;&gt; &lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.select {|p| p.title == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; &amp;&amp; p.user.name == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}.sort_by { |p| [p.created_at, -p.size] }
</code></pre>
<p>creates the following:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




=&gt; {&lt;span class=&quot;sy&quot;&gt;:order&lt;/span&gt;=&gt;&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;photos.created_at, photos.size DESC&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:conditions&lt;/span&gt;=&gt;&lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;(photos.`title` IS NULL AND users.name = 'test')&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class=&quot;sy&quot;&gt;:include&lt;/span&gt;=&gt;[&lt;span class=&quot;sy&quot;&gt;:user&lt;/span&gt;]}
</code></pre>
<p>or</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




=&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT * FROM photos JOIN user WHERE (photos.`title` IS NULL AND users.name = 'test') ORDER BY photos.created_at, photos.size DESC&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>That&rsquo;s cool, and you can still sort on relationships:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;




&gt;&gt; &lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.select {|p| p.title == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; }.sort_by { |p| p.user.name }&lt;tt&gt;
&lt;/tt&gt;=&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT * FROM photos JOIN user WHERE photos.`title` IS NULL ORDER BY users.name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;&lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;macro:code &gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;Or directly on the model:&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;macro:code lang=&quot;ruby&quot;&gt;&gt;&gt; Photo.sort_by(&amp;:title)&lt;tt&gt;
&lt;/tt&gt;=&gt; &quot;SELECT * FROM photos ORDER BY photos.title&quot;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>To finish, another detail which makes Ambition a great library</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;




&gt;&gt; &lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.any? {|p| p.title =~ &lt;span class=&quot;rx&quot;&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;ambition&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;/&lt;/span&gt;&lt;/span&gt; }&lt;tt&gt;
&lt;/tt&gt;=&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT count(*) AS count_all FROM photos WHERE (photos.`title` REGEXP 'ambition')&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;tt&gt;
&lt;/tt&gt;=&gt; &lt;span class=&quot;pc&quot;&gt;true&lt;/span&gt;
</code></pre>
<p>And if you were worried that it wouldn&rsquo;t work with utf8, check this out:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;




&gt;&gt; &lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.any? {|p| p.title == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;Ã©cole&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}&lt;tt&gt;
&lt;/tt&gt;=&gt; &lt;span class=&quot;co&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;NAMES&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;utf8&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;=&gt; &lt;span class=&quot;co&quot;&gt;SET&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;SQL_AUTO_IS_NULL&lt;/span&gt;=&lt;span class=&quot;i&quot;&gt;0&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;=&gt; &lt;span class=&quot;co&quot;&gt;SHOW&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;FIELDS&lt;/span&gt; &lt;span class=&quot;co&quot;&gt;FROM&lt;/span&gt; photos&lt;tt&gt;
&lt;/tt&gt;=&gt; &lt;span class=&quot;co&quot;&gt;SELECT&lt;/span&gt; count(*) &lt;span class=&quot;co&quot;&gt;AS&lt;/span&gt; count_all &lt;span class=&quot;co&quot;&gt;FROM&lt;/span&gt; photos &lt;span class=&quot;co&quot;&gt;WHERE&lt;/span&gt; (photos.`title&lt;span class=&quot;sh&quot;&gt;&lt;span class=&quot;dl&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;k&quot;&gt; = 'Ã©cole') &lt;tt&gt;
&lt;/tt&gt;=&gt; false&lt;/span&gt;&lt;/span&gt;
</code></pre>
<h2 id="limitations">Limitations</h2>
<p>The only limitation I found in Ambition is that Ruby code won&rsquo;t work in the block, for instance:</p>
<pre><code>&lt;tt&gt;
&lt;/tt&gt;




&gt;&gt; &lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.select {|p| p.title == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; &amp;&amp; p.created_at &lt; &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;.week.ago &amp;&amp; p.user.name == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}.entries
</code></pre>
<p>won&rsquo;t work at the moment. To inspect what&rsquo;s going simply try:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;




&gt;&gt; &lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.select {|p| p.title == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; &amp;&amp; p.created_at &lt; &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;.week.ago &amp;&amp; p.user.name == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}.to_sql&lt;tt&gt;
&lt;/tt&gt;=&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT * FROM photos JOIN user WHERE (photos.`title` IS NULL AND (photos.`created_at` &lt; 1.`week`.`ago` AND users.name = 'test'))&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>You can see that <strong>photos.<code>created_at</code> &lt; 1.<code>week</code>.<code>ago</code></strong>  is the problem.</p>
<p>The recommended way to achieve the same result is to use variables:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;




&gt;&gt; date = &lt;span class=&quot;i&quot;&gt;1&lt;/span&gt;.week.ago&lt;tt&gt;
&lt;/tt&gt;&gt;&gt; &lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.select {|p| p.title == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; &amp;&amp; p.created_at &lt; date &amp;&amp; p.user.name == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}.to_sql&lt;tt&gt;
&lt;/tt&gt;=&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT * FROM photos JOIN user WHERE (photos.`title` IS NULL AND (photos.`created_at` &lt; '2007-09-08 19:38:48' AND users.name = 'test'))&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<p>However, note that method calls will work just fine:</p>
<pre><code>1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;5&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;




&gt;&gt; &lt;span class=&quot;r&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;fu&quot;&gt;time_now_please&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&gt;&gt; &lt;span class=&quot;co&quot;&gt;Time&lt;/span&gt;.now&lt;tt&gt;
&lt;/tt&gt;&gt;&gt; &lt;span class=&quot;r&quot;&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;tt&gt;
&lt;/tt&gt;&gt;&gt; &lt;span class=&quot;co&quot;&gt;Photo&lt;/span&gt;.select {|p| p.title == &lt;span class=&quot;pc&quot;&gt;nil&lt;/span&gt; &amp;&amp; p.created_at &lt; time_now_please &amp;&amp; p.user.name == &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;/span&gt;}.to_sql&lt;tt&gt;
&lt;/tt&gt;=&gt; &lt;span class=&quot;s&quot;&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;SELECT * FROM photos JOIN user WHERE (photos.`title` IS NULL AND (photos.`created_at` &lt; '2007-09-15 19:41:37' AND users.name = 'test'))&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
</code></pre>
<h2 id="conclusion">Conclusion</h2>
<p>For now, Ambition is still just wrapping ActiveRecord::Base#find but the plan is to actually generate SQL. Hopefully we&rsquo;ll also be able to use Ruby code from within an Ambition block. Kickers methods are very interesting and could become a really nice way of speeding up your app and keep your code clean.</p>
<p>Ambition is a great query library, I think I&rsquo;ll start using it whenever I have &ldquo;find&rdquo; calls with multiple conditions especially if my conditions are related to another model. However I still didn&rsquo;t figure out how to use an inner join with Ambition.</p>
]]></content>
		</item>
		
		<item>
			<title>globalite major update</title>
			<link>https://matt.aimonetti.net/posts/2007-09-globalite-major-update/</link>
			<pubDate>Sun, 02 Sep 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-09-globalite-major-update/</guid>
			<description>I&amp;rsquo;m glad to announce a major update of Globalite. First off I&amp;rsquo;d like to thank all the translators who helped with this release.
  Globalite now support its first Asian language: Chinese! Ivan Chang did an awesome job creating a localization file in Chinese for Taiwan, Hong Kong and Main Land China. I&amp;rsquo;m really glad thinking that Globalite will make the Rails experience much nicer for a lot of Chinese people.</description>
			<content type="html"><![CDATA[<h2 id="_im-glad-to-announce-a-major-update-of-globalite_"><em>I&rsquo;m glad to announce a major update of Globalite.</em></h2>
<p>First off I&rsquo;d like to thank all the translators who helped with this release.</p>
<ul>
<li>
<p>Globalite now support its <strong>first Asian language: Chinese!</strong>
Ivan Chang did an awesome job creating a localization file in Chinese for Taiwan, Hong Kong and Main Land China. I&rsquo;m really glad thinking that Globalite will make the Rails experience much nicer for a lot of Chinese people.</p>
</li>
<li>
<p>Ivan also pushed me to add a new feature that people had asked about: a <strong>better ActiveRecord error message support</strong>.</p>
</li>
</ul>
<p>You know how Rails has a nice way of displaying your Model errors:</p>
<p><img src="https://farm2.static.flickr.com/1052/1306879608_e60431d214_o.png" alt="AR_error"></p>
<p>Well, now that&rsquo;s automatically translated in your locale. (as long as the new localization files are up to date. Feel free to contact me if you want to improve the locale file in your own language)</p>
<ul>
<li>I also added support for pluralization directly in the translation file. (pluralization doesn&rsquo;t always make sense in some languages) I&rsquo;m planning on adding a better Inflector support later on.</li>
</ul>
<p>for now, in your translation file simply use:</p>
<p><code>horse_count: we have pluralize curly_brace curly_brace count curly_brace, horse curly_brace in the
ranch</code></p>
<p>In your view use the localization with arguments to pass the count:</p>
<code>
<%= :horse_count.l_with_args({:count => @horse.count}) %>
</code>
<p>See <a href="https://code.google.com/p/globalite/wiki/PluralizationSupport">the wiki</a> for more information about pluralization.</p>
<ul>
<li>Finally the <a href="https://globalite.googlecode.com/svn/sample/ui/">demo app</a> has been updated with an example of how to grab the acceptable locale from the header. (thanks to Emmanuel Bouton)</li>
</ul>
]]></content>
		</item>
		
		<item>
			<title>new version of globalite is coming up</title>
			<link>https://matt.aimonetti.net/posts/2007-08-new-version-of-globalite-is-coming-up/</link>
			<pubDate>Wed, 29 Aug 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-08-new-version-of-globalite-is-coming-up/</guid>
			<description>I&amp;rsquo;m almost ready to update Globalite with 2 major changes:
  Support for Chinese (Taiwan, Hong Kong and main land China) thanks to Ivan Chang
  Better support for Active Record error messages in forms (based on contribution from Ivan)
  I&amp;rsquo;m writing more tests and updating the sample app before releasing the updated version. It should be out in the next few days.
[Globalite page @ Google Code](https://code.</description>
			<content type="html"><![CDATA[<p>I&rsquo;m almost ready to update Globalite with 2 major changes:</p>
<ul>
<li>
<p>Support for Chinese (Taiwan, Hong Kong and main land China) thanks to Ivan Chang</p>
</li>
<li>
<p>Better support for Active Record error messages in forms (based on contribution from Ivan)</p>
</li>
</ul>
<p>I&rsquo;m writing more tests and updating the sample app before releasing the updated version. It should be out in the next few days.</p>
<p>[Globalite page @ Google Code](<a href="https://code.google.com/p/globalite/">https://code.google.com/p/globalite/</a></p>
]]></content>
		</item>
		
		<item>
			<title>differently way of working</title>
			<link>https://matt.aimonetti.net/posts/2007-08-differently-way-of-working/</link>
			<pubDate>Sat, 25 Aug 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-08-differently-way-of-working/</guid>
			<description>Josh Knowles shared with me a great video about working methodologies, client relationship and project management.
Check it out, it&amp;rsquo;s really worth it.</description>
			<content type="html"><![CDATA[<p><a href="https://joshknowles.com">Josh Knowles</a> shared with me a great video about working methodologies, client relationship and project management.</p>
<p>Check it out, it&rsquo;s really worth it.</p>
<p><a href="https://unspace.ca/innovation/speak"><img src="https://farm2.static.flickr.com/1216/1228290366_271e6a2509_o.png" alt="video"></a></p>
]]></content>
		</item>
		
		<item>
			<title>tired of excessively dry code and smart coding</title>
			<link>https://matt.aimonetti.net/posts/2007-08-tired-of-excessively-dry-code-and-smart-coding/</link>
			<pubDate>Wed, 22 Aug 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-08-tired-of-excessively-dry-code-and-smart-coding/</guid>
			<description>Recently, I got really annoyed at some code I had to work on.
The main reason was that the developer I was working with likes making everything super DRY. While I hate repetitions I like being able to understand the code I&amp;rsquo;m reading and I want to be able to quickly refactor it.
Anyway, I got over it but during my journey I found some inspiration:
Check out this Keynote of Marcel Molina, Jr at the Ruby Hoedown about code beauty and the rules of Proportion, Integrity and Clarity.</description>
			<content type="html"><![CDATA[<p>Recently, I got really annoyed at some code I had to work on.</p>
<p>The main reason was that the developer I was working with likes making everything super DRY. While I hate repetitions I like being able to understand the code I&rsquo;m reading and I want to be able to quickly refactor it.</p>
<p>Anyway, I got over it but during my journey I found some inspiration:</p>
<p>Check out <a href="https://rubyhoedown2007.confreaks.com/session09.html">this Keynote of Marcel Molina, Jr</a> at the Ruby Hoedown about code beauty and the rules of Proportion, Integrity and Clarity.</p>
<p>We were discussing the issue in the SD ruby Brigade mailing list and <a href="https://www.jordanfowler.com">Jordan Fowler</a> posted the following:</p>
<p>I couldn&rsquo;t help but quote the Towelie episode from South park:</p>
<pre><code>&lt;code&gt;General: Don't you see what genetically enhanced smart towels like these are capable of?
You get out of the shower and dry yourself off. But even after you're dry, the towel makes you more dry.
It keeps getting you drier and drier.
Can you imagine it? What it would feel like to be way, way too dry?
I'll tell you something, you don't want to know and I don't know.

Kyle: And we don't care!
&lt;/code&gt;
</code></pre>
]]></content>
		</item>
		
		<item>
			<title>the seattle rb guys did it again</title>
			<link>https://matt.aimonetti.net/posts/2007-08-the-seattle-rb-guys-did-it-again/</link>
			<pubDate>Tue, 14 Aug 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-08-the-seattle-rb-guys-did-it-again/</guid>
			<description>The Seattle.rb guys did it again! 
After releasing the excellent Zentest suite, imageScience, Heckle and much more, Ryan Davis and his crew came back with great news.
From Saturday, August 4th to Tuesday, August 7th, the Ruby Hit Squad was in full effect. After almost 4 days working almost none stop, they released Vlad the Deployer
What&amp;rsquo;s Vlad? Some sort of simple and efficient version of Capistrano with simple goals:</description>
			<content type="html"><![CDATA[<p>The <a href="https://seattlerb.rubyforge.org/">Seattle.rb guys</a> did it again! <a href="https://seattlerb.rubyforge.org/"><img src="https://www.zenspider.com/image/seattle/Seattle.rb.small.png" alt="seattle.rb"></a></p>
<p>After releasing the excellent <a href="https://www.zenspider.com/ZSS/Products/ZenTest/index.html">Zentest suite</a>, <a href="https://seattlerb.rubyforge.org/ImageScience.html">imageScience</a>, <a href="https://rubyforge.org/projects/seattlerb/">Heckle</a> and <a href="https://rubyforge.org/projects/seattlerb/">much more</a>, Ryan Davis and his crew came back with great news.</p>
<p>From Saturday, August 4th to Tuesday, August 7th, the Ruby Hit Squad was in full effect. After almost 4 days working almost none stop, they released <a href="https://rubyhitsquad.com/Ruby_Hit_Squad.html">Vlad the Deployer</a></p>
<h2 id="whats-vlad">What&rsquo;s Vlad?</h2>
<p>Some sort of simple and efficient version of Capistrano with simple goals:</p>
<ul>
<li>
<p>Do the simplest thing that could possibly work.</p>
</li>
<li>
<p>Nothing to 1.0 in four(ish) days.</p>
</li>
<li>
<p>Targets the 80% use case.</p>
</li>
<li>
<p>Uses Rake, as god intended.</p>
</li>
<li>
<p>Use the right tool for the job (ssh, rsync, etc).</p>
</li>
<li>
<p>Fold in the Rails Machine recipes.</p>
</li>
<li>
<p>Clever is bad. Period.</p>
</li>
</ul>
<p>If you are like me, you love Capistrano and couldn&rsquo;t imagine working without it, but you also wonder Jamis decided not to extend Rake instead of creating something similar but not really. You would also really appreciate the last objective:</p>
<ul>
<li>Clever is bad. Period.</li>
</ul>
<p>I didn&rsquo;t have the opportunity to test it yet, but I have to say that I&rsquo;m excited to see alternative solutions in the Rails world. I like conventions, but I like having the choice of which conventions I want to follow ;)</p>
]]></content>
		</item>
		
		<item>
			<title>why you should seriously consider using lighthouse</title>
			<link>https://matt.aimonetti.net/posts/2007-07-why-you-should-seriously-consider-using-lighthouse/</link>
			<pubDate>Sat, 28 Jul 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-07-why-you-should-seriously-consider-using-lighthouse/</guid>
			<description>is one of my favorite web application of the moment. It got publicly released last April (2007) by the activereload ninjas.
Since then, they also released 
but I&amp;rsquo;ll keep that for another post.
I&amp;rsquo;ve been using Lighthouse for a little while and I have to admit that I was a bit confused at first. I&amp;rsquo;d like to share with you why I&amp;rsquo;m really pleased with Lighthouse and why I think you should consider using it too.</description>
			<content type="html"><![CDATA[<p><a href="https://www.lighthouseapp.com/"><img src="https://farm2.static.flickr.com/1290/931895653_92ab9b4282_o.jpg" alt="lighthouse logo"></a> is one of my favorite web application of the moment. It got publicly released last April (2007) by the <a href="https://activereload.net/">activereload</a> ninjas.</p>
<p>Since then, they also released <a href="https://warehouseapp.com/"><img src="https://farm2.static.flickr.com/1338/932922548_576ef7fb11_m.jpg" alt="warehouse"></a></p>
<p>but I&rsquo;ll keep that for another post.</p>
<p>I&rsquo;ve been using Lighthouse for a little while and I have to admit that I was a bit confused at first. I&rsquo;d like to share with you <strong>why I&rsquo;m really pleased with <a href="https://www.lighthouseapp.com/">Lighthouse</a></strong> and <strong>why I think you should consider using it too</strong>.</p>
<p>You have probably figured out, I&rsquo;m a little biased. So let me give you my conclusions right away.</p>
<ul>
<li>
<p><a href="https://www.lighthouseapp.com/">Lighthouse</a> is <strong>simple</strong> and <strong>efficient</strong>.</p>
</li>
<li>
<p><a href="https://www.lighthouseapp.com/">Lighthouse</a> is <strong>more than a bug tracker</strong>, it&rsquo;s also a <strong>project management application</strong>.</p>
</li>
<li>
<p><a href="https://www.lighthouseapp.com/">Lighthouse</a> helps you <strong>communicating better</strong> with you clients.</p>
</li>
<li>
<p><a href="https://www.lighthouseapp.com/">Lighthouse</a> <strong>doesn&rsquo;t lack any features</strong> I used in <a href="https://trac.edgewall.org">trac</a>.</p>
</li>
<li>
<p><a href="https://www.lighthouseapp.com/">Lighthouse</a> helps you <strong>keeping it simple</strong>.</p>
</li>
<li>
<p><a href="https://www.lighthouseapp.com/">Lighthouse</a> has a <strong>nice UI</strong>.</p>
</li>
<li>
<p><a href="https://www.lighthouseapp.com/">Lighthouse</a> is really cheap (it&rsquo;s not free but almost).</p>
</li>
</ul>
<p>The 2 things that threw me off when I switched from <a href="https://trac.edgewall.org">trac</a> to <a href="https://www.lighthouseapp.com/">Lighthouse</a> were:</p>
<ul>
<li>
<p>the lack of <strong>integration with Subversion</strong></p>
</li>
<li>
<p>the weird way of <strong>organizing tickets</strong></p>
</li>
</ul>
<p><strong>SVN integration:</strong></p>
<p>So, no <a href="https://www.lighthouseapp.com/">Lighthouse</a> doesn&rsquo;t have a repository browser, you would need to use <a href="https://warehouseapp.com/">warehouse</a>, <a href="https://trac.edgewall.org">trac</a>, <a href="https://retrospectiva.org/blog">retrospectiva</a> or another tool. I personally don&rsquo;t think there&rsquo;s a real need for such a tool, but others might disagree.  However, Lighthouse has a subversion beacon(Beacons are services that can be used to interact with Lighthouse). You can really easily install the beacon on your subversion server and committing code will leave a comment in your ticket, add a tag, change the status etc.. check <a href="https://lighthouseapp.com/tour/source-control-integration">this video</a> to see how it works. That&rsquo;s something I never did with Trac and I spent a lot of time editing tickets to mention the changesets related to issue related in the ticket.</p>
<p><strong>SVN integration conclusion: better than expected</strong></p>
<p><strong>Organizing tickets:</strong></p>
<p>I like having my tickets well organized. When i switched to Lighhouse and I only had tags to organize my tickets, I felt a bit lost. Actually Lighthouse doesn&rsquo;t only have tags, it also has milestones. My milestones are usually really simple: iteration 1, iteration 2, iteration 3, investor demo 1, iteration 4, beta etc&hellip; Milestones aren&rsquo;t used to classify tickets but to give them a deadline. So I was still facing an issue since I wanted to organize and prioritize all my user story tickets, bug reports, feature requests etc&hellip; using tag is &lsquo;ok&rsquo; but finding your tickets later on is a pain. I decided to do something I&rsquo;ve been doing with trac for a while: adding a keyword in the topic line. For instance I would create a new ticket like that <strong>[bug] a user can&rsquo;t use utf-8 characters in his name</strong>. It worked ok but I was still missing something. What I didn&rsquo;t know was that Rick and Justin already thought about that and came up with a simple/cool solution: <a href="https://lighthouseapp.com/tour/ticket-bins">ticket bins</a>. Basically, a ticket is just a pool of tickets sharing the same criteria. Creating a ticket bin is dead simple, search for tickets, save the search criteria. That&rsquo;s it.</p>
<p><img src="https://farm2.static.flickr.com/1280/933132130_839046bcd3_o.jpg" alt="ticket bins"></p>
<p>I could now start using my critical, essential, nonessential tags and create bins for them. What I love with bins is that they are not <em>folders</em>. A ticket can be inside many bins. For instance, my critical UI open bug will be in my current bugs bin, critical bugs bin and in my UI bin. (I don&rsquo;t actually have a current bugs bin, but you see my point.)</p>
<p>User stories/bug reports/new features can all be entered via the same interface and you don&rsquo;t have to worry since they can be easily sorted using your ticket bins.</p>
<p><strong>Organizing tickets conclusion: awesome</strong></p>
<hr>
<p><strong>What about <a href="https://basecamphq.com/">Basecamp</a>?</strong></p>
<p><a href="https://basecamphq.com/">Basecamp</a> is great but even DHH says it is not meant for managing development projects. Itâ€™s really meant for marketers and managers, in other words: my clients. But you still need a good way of tracking your code, <a href="https://www.lighthouseapp.com/">Lighthouse</a> isn&rsquo;t perfect and I wish it had a better support of user stories but it&rsquo;s by far the best tool I found so far. Regarding the lack of user stories/criteria support, maybe I&rsquo;ll just write my own application and use their beacon interface to integrate both apps together&hellip;</p>
]]></content>
		</item>
		
		<item>
			<title>new plugin to manage your backups</title>
			<link>https://matt.aimonetti.net/posts/2007-07-new-plugin-to-manage-your-backups/</link>
			<pubDate>Tue, 24 Jul 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-07-new-plugin-to-manage-your-backups/</guid>
			<description>I just released a simple plugin that I use to backup and restore databases instead of using a mysql dump.
check out the plugin page
File structure will look like that:
I use this plugin to backup my apps running in production. When I need to debug an application, I just need to restore the db locally and debug. The fact that it uses fixtures helps me finding data quickly and I can easily decide to only restore few tables.</description>
			<content type="html"><![CDATA[<p>I just released a simple plugin that I use to backup and restore databases instead of using a mysql dump.</p>
<p><a href="https://code.google.com/p/ar-backup/">check out the plugin page</a></p>
<p>File structure will look like that:</p>
<p><img src="https://farm2.static.flickr.com/1054/882951034_343db15424_o.jpg" alt="ar-backup"></p>
<p>I use this plugin to backup my apps running in production. When I need to debug an application, I just need to restore the db locally and debug. The fact that it uses fixtures helps me finding data quickly and I can easily decide to only restore few tables.</p>
<p>I also have a Capistrano recipe to create backups before each deployment.</p>
<p>oohh and the plugin is <a href="https://errtheblog.com/post/6069">Sake</a> compatible, give it a try :)</p>
<p>Enjoy</p>
]]></content>
		</item>
		
		<item>
			<title>attachment_fu s3 railroad tip</title>
			<link>https://matt.aimonetti.net/posts/2007-07-attachment_fu-s3-railroad-tip/</link>
			<pubDate>Mon, 23 Jul 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-07-attachment_fu-s3-railroad-tip/</guid>
			<description>Here is another type for attachment_fu users.
This evening I wanted to try Railroad to generate one of my app diagram. I alreay wrote my own script generating a .dot file that I usually import in omnigraffle before exporting a pretty version for my clients. The thing is, my script is quite simple and only covers models while railroad also deals with controllers.
Wanting to check on railroad, after installing the gem I typed</description>
			<content type="html"><![CDATA[<p>Here is another type for attachment_fu users.</p>
<p>This evening I wanted to try <a href="https://railroad.rubyforge.org/">Railroad</a> to generate one of my app diagram. I alreay wrote my own script generating a .dot file that I usually import in <a href="https://www.omnigroup.com/applications/omnigraffle/">omnigraffle</a> before exporting a pretty version for my clients. The thing is, my script is quite simple and only covers models while <a href="https://railroad.rubyforge.org/">railroad</a> also deals with controllers.</p>
<p>Wanting to check on railroad, after installing the gem I typed</p>
<pre><code>&lt;code&gt; railroad -o models.dot -M
&lt;/code&gt;
</code></pre>
<p>and here is the <em>&lsquo;pretty&rsquo;</em> error message I got.</p>
<p><img src="https://farm2.static.flickr.com/1209/874252844_25e869205e_o.jpg" alt="railroad error msg"></p>
<p>No worries, Technoweenie didn&rsquo;t mess up, it&rsquo;s just that I use s3 for storage and his great plugin checks on the environment to load the proper credentials. Since railroad doesn&rsquo;t care about the environment, RAILS_ENV isn&rsquo;t set and my model diagram isn&rsquo;t generated.</p>
<p>To fix this issue, simply type:</p>
<pre><code>&lt;code&gt;$ railroad -o models.dot -M RAILS_ENV='development'
&lt;/code&gt;
</code></pre>
]]></content>
		</item>
		
		<item>
			<title>attachment_fu flash and to_xml tips</title>
			<link>https://matt.aimonetti.net/posts/2007-07-attachment_fu-flash-and-to_xml-tips/</link>
			<pubDate>Sat, 21 Jul 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-07-attachment_fu-flash-and-to_xml-tips/</guid>
			<description>I recently had to deal with an interesting challenge. I had to write a simple interface between a rails app and a Flash application. Nothing hard and if you browse the archives, you&amp;rsquo;ll find examples and tutorials on how to create a REST interface to communicate between Rails and Flash.
The thing was that this time I had to interface with a model using attachment_fu. I&amp;rsquo;m a great fan of a_fu and it&amp;rsquo;s definitely the best way of dealing with uploads.</description>
			<content type="html"><![CDATA[<p>I recently had to deal with an interesting challenge. I had to write a simple interface between a rails app and a Flash application. Nothing hard and if you browse the archives, you&rsquo;ll find examples and tutorials on how to create a REST interface to communicate between Rails and Flash.</p>
<p>The thing was that this time I had to interface with a model using <a href="https://svn.techno-weenie.net/projects/plugins/attachment_fu/">attachment_fu</a>. I&rsquo;m a great fan of a_fu and it&rsquo;s definitely the best way of dealing with uploads.</p>
<p>My model looked more or less like that:</p>
<pre><code>&lt;code&gt;class Photo &lt; ActiveRecord::Base

belongs_to :user

  has_attachment(
    :content_type =&gt; :image,
    :storage =&gt; :file_system,
    :max_size =&gt; 10.megabytes,
    :resize_to =&gt; '640x480&gt;',
    :thumbnails =&gt; { :thumb =&gt; '100x100&gt;',
                              :preview =&gt; '300x200&gt;',
                     }
  )
  validates_as_attachment
  # read more about validates_existence_of https://blog.hasmanythrough.com/2007/7/14/validate-your-existence
  validates_existence_of :user
end
&lt;/code&gt;
</code></pre>
<p>My show action in my photo controller could have looked a bit like that:</p>
<pre><code>&lt;code&gt;respond_to do |format|
  format.html # show.html.erb
  format.xml  { render :xml =&gt; @photo }
end
&lt;/code&gt;
</code></pre>
<p>That&rsquo;s great, the problem is that we are displaying a lot of information that our Flash client doesn&rsquo;t need to see, actually we are exposing a lot of information nobody should ever see and we are not displaying what we should. On top of being a waste of bandwidth and giving too much work to the client, we are not actually providing the user with the details of the thumbnail.</p>
<p>The first thing to do would be not to display some of the object attributes, the to_xml method lets you do that.</p>
<p>Note that in Edge, Rails will automatically try to convert your object using to_xml, you don&rsquo;t even need to mention it. However in our case, we want to use some <em>advanced</em> features offered by to_xml, and here is how our code should look like:</p>
<pre><code>&lt;code&gt;format.xml do
  render :xml =&gt; @photo.to_xml( :except =&gt; [ :id, :filename, :updated_at, :user_id, :height, :width], :skip_types =&gt; true )
end
&lt;/code&gt;
</code></pre>
<p>What I just did is very simple, we rendered our object as an xml object but we didn&rsquo;t convert few attributes, :id, :filename, :updated_at, :user_id, :height, :width. By default Rails also adds the object type, we don&rsquo;t really need that right now, so let&rsquo;s skip them.</p>
<p>(The reason why I don&rsquo;t want to convert the filename is that I want to provide our Flash client with the photo thumbnail instead of the original picture.)</p>
<p>As far as I know, to_xml doesn&rsquo;t let you create new attributes. (if I have some time, I&rsquo;ll submit a patch to get that added).</p>
<p>What we are trying to do is to display the avatar of a user. We found the photo record using @user.photo but that&rsquo;s the original photo and we want to provide Flash with the avatar info, not the original.</p>
<p>What we need to do is to simply add a new attribute called avatar:</p>
<pre><code>&lt;code&gt;format.xml do
  @photo[:avatar] = @photo.public_filename(:thumb)
  render :xml =&gt; @photo.to_xml( :except =&gt; [ :id, :filename, :updated_at, :user_id, :height, :width], :skip_types =&gt; true )
end
&lt;/code&gt;
</code></pre>
<p>Simple enough, but it took me a little while to figure it out ;)</p>
<p>Voila, we now have a clean, trimmed and safe XML returned object that you can be consumed by our Flash client. Ohh, and we added a new attribute that the original object didn&rsquo;t have :)</p>
]]></content>
		</item>
		
		<item>
			<title>irb tricks</title>
			<link>https://matt.aimonetti.net/posts/2007-07-irb-tricks/</link>
			<pubDate>Sun, 15 Jul 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-07-irb-tricks/</guid>
			<description>I recently had a discussion with someone(not really familiar with Ruby and its frameworks) and this person didn’t realize the power of IRB and the Rails console.
Not, this irb, the Ruby IRB. According to wikipedia IRB is a shell for programming in the object-oriented scripting language Ruby. IRB is run from the command line and allows the programmer to experiment with code in real time. It allows you to enter Ruby commands at the prompt and have the interpreter respond immediately.</description>
			<content type="html"><![CDATA[<p>I recently had a discussion with someone(not really familiar with Ruby and its frameworks)  and this person didn’t realize the power of IRB and the Rails console.</p>
<p><img src="https://myskitch.com/matt_a/irb-20070714-223658.jpg" alt="irb"></p>
<p>Not, this irb, the Ruby IRB. According to <a href="https://en.wikipedia.org/wiki/Interactive_Ruby_Shell">wikipedia</a> IRB is a shell for programming in the object-oriented scripting language Ruby. IRB is run from the command line and allows the programmer to experiment with code in real time. It allows you to enter Ruby commands at the prompt and have the interpreter respond immediately. It features command history, line editing capabilities, and job control, and is able to communicate directly as a shell script over the Internet and interact with a live server. It was developed by Keiju Ishitsuka.</p>
<p>IRB is awesome and the Rails developers knew it and extended it by creating the Rails console. (come on, you know: $ ruby script/console )</p>
<p>The only issue I have with the Rails console is that it doesn’t have a history. Not really a big deal but don’t worry the console can be extended.</p>
<p><a href="https://wiki.rubygarden.org/Ruby/page/show/Irb/TipsAndTricks">IRB tips and tricks</a></p>
<p>You can also decide to install <a href="https://pablotron.org/software/wirble/">wirble</a> a gem compiling most of the tricks from rubygarden.org</p>
<p>Simply do:</p>
<pre><code>&lt;code&gt;sudo gem install wirble
&lt;/code&gt;
</code></pre>
<p>then edit your ~/.irbrc file and add the following:</p>
<pre><code>&lt;code&gt;# load libraries
require 'rubygems'
require 'wirble'
Wirble.init
&lt;/code&gt;
</code></pre>
<p>or if you want the fancy colors (I personally don’t like using them), your ~/.irbrc file should look like:</p>
<pre><code>&lt;code&gt;# load libraries
require 'rubygems'
require 'wirble'

# start wirble (with color)
Wirble.init
Wirble.colorize
&lt;/code&gt;
</code></pre>
<p>Start your console and you can now use the history by pressing up.</p>
<p><a href="https://pablotron.org/software/wirble/README">read more about wirble</a></p>
<h1 id="tricks-i-use-on-a-regular-basis">Tricks I use on a regular basis:</h1>
<p>Start a console in a different environment:</p>
<pre><code>&lt;code&gt;$ ruby script/console production
&lt;/code&gt;
</code></pre>
<p>Reload the console after you modified a class</p>
<pre><code>&lt;code&gt;&gt;&gt; reload!
&lt;/code&gt;
</code></pre>
<p>Rollback changes on exit:</p>
<pre><code>&lt;code&gt;$ script/console --sandbox
&lt;/code&gt;
</code></pre>
<p>or</p>
<pre><code>&lt;code&gt;$ script/console -s
&lt;/code&gt;
</code></pre>
<p>and if feel like a ninja, try the combo which will load the production environment in sanbbox :</p>
<pre><code>&lt;code&gt;$ script/console production -s
&lt;/code&gt;
</code></pre>
<p><img src="https://myskitch.com/matt_a/console-ninja-combo-20070714-231517.jpg" alt="ninja combo"></p>
<p>Most Rails developers are really familiar with everything I explained in this post but I realized that too many new comers ignore the great tools provided to them for free. Hopefully this post will help few newbies ;)</p>
]]></content>
		</item>
		
		<item>
			<title>restful_authentication and rspec tip</title>
			<link>https://matt.aimonetti.net/posts/2007-07-restful_authentication-and-rspec-tip/</link>
			<pubDate>Fri, 13 Jul 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-07-restful_authentication-and-rspec-tip/</guid>
			<description>resftul_authentication is a great plugin, but not always resftful… especially if like me you dropped unit test for RSpec.
I have a set of RSpec examples I use all the time on all my projects requiring restful_authentication, obviously I always end up tweaking them because each application has its specific needs.
However, I was recently asked what’s the way of dealing with controllers specs when a controller has a limited access ?</description>
			<content type="html"><![CDATA[<p><a href="https://svn.techno-weenie.net/projects/plugins/restful_authentication/">resftul_authentication</a> is a great plugin, but not always resftful… especially if like me you dropped unit test for RSpec.</p>
<p><img src="https://myskitch.com/matt_a/p-restful_24x40.jpg__jpeg_image__2224x1475_pixels__-_scaled__43__-20070712-224940.jpg" alt=""></p>
<p>I have a set of RSpec examples I use all the time on all my projects requiring restful_authentication, obviously I always end up tweaking them because each application has its specific needs.</p>
<p>However, I was recently asked <em>what’s the way of dealing with controllers specs when a controller has a limited access ?</em></p>
<p>Let’s look at the following controller for instance:</p>
<pre><code>&lt;code&gt;class AssetController &lt; ApplicationController
 before_filter :login_required, :except =&gt; [ :index, :show ]
&lt;/code&gt;
</code></pre>
<p>my assets_controller_spec.rb file will have the following code:</p>
<pre><code>&lt;code&gt;describe AssetController, &quot;handling GET /assets/new&quot; do

  before do
    @asset = mock_model(Asset)
    Asset.stub!(:new).and_return(@asset)
  end

  def do_get
    get :new
  end

  it &quot;should be successful&quot; do
    do_get
    response.should be_success
  end

end
&lt;/code&gt;
</code></pre>
<p>and guess what… it will fail! Why? simply because we are trying to access an action requiring login. Right, so what’s the best way of dealing with this issue and get our test to pass?</p>
<p>The best solution I found was to use a simple helper that I put in my spec_helper.rb file</p>
<pre><code>&lt;code&gt;def login_as(user)
  case user
    when :admin
      @current_user = mock_model(User)
      User.should_receive(:find_by_id).any_number_of_times.and_return(@current_user)
      request.session[:user] = @current_user
    else
      request.session[:user] = nil
  end
end
&lt;/code&gt;
</code></pre>
<p>You might wonder why I use when :user, well, in a lot of the application I’m working on, I have different levels of access and I want to tests different accounts so I the case conditional loop.</p>
<p>Anyway, let’s implement our helper in our previous RSpec example:</p>
<pre><code>&lt;code&gt;describe AssetController, &quot;handling GET /assets/new&quot; do

  before do
    login_as :admin
    @asset = mock_model(Asset)
    Asset.stub!(:new).and_return(@asset)
  end

  def do_get
    get :new
  end

  it &quot;should be successful&quot; do
    do_get
    response.should be_success
  end

end
&lt;/code&gt;
</code></pre>
<p>and there you go, now your example passes properly ;)</p>
<p>Have fun</p>
]]></content>
		</item>
		
		<item>
			<title>feeedom</title>
			<link>https://matt.aimonetti.net/posts/2007-07-feeedom/</link>
			<pubDate>Wed, 11 Jul 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-07-feeedom/</guid>
			<description>For many Americans, the 4th of July reminds them of their freedom.
Since I didn&amp;rsquo;t grow up in the US, for the 4th of July was a great occasion for a BBQ with friends and enjoying fireworks.
However, things changed this year when I decided to leave my full time job as Rails developer to become a consultant and work with my own clients.
Just after July the 4th, I started working full time as a contractor and I really like it.</description>
			<content type="html"><![CDATA[<p>For many Americans, the 4th of July reminds them of their freedom.</p>
<p>Since I didn&rsquo;t grow up in the US, for the 4th of July was a great occasion for a BBQ with friends and enjoying  fireworks.</p>
<p>However, things changed this year when I decided to leave my full time job as Rails developer to become a consultant and work with my own clients.</p>
<p><img src="https://farm1.static.flickr.com/151/364297547_70050418cd_m.jpg" alt="freedom"></p>
<p>Just after July the 4th, I started working full time as a contractor and I really like it. I&rsquo;ve been working on some projects as a consultant in the past but I found myself often frustrated by the fact that I couldn&rsquo;t spend enough time on a project a once.</p>
<p>I seriously enjoy working with different people, different needs, different approaches. Learning from all these people is very valuable to me.</p>
<p>Working from home comes at a price though, I need to deal with taxes, health coverage and the rest of the paperwork&hellip;.  but come on, being able to work from your deck and have flexible hours is priceless ;)</p>
]]></content>
		</item>
		
		<item>
			<title>globalite usage example</title>
			<link>https://matt.aimonetti.net/posts/2007-07-globalite-usage-example/</link>
			<pubDate>Tue, 03 Jul 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-07-globalite-usage-example/</guid>
			<description>If you haven&amp;rsquo;t check out the Globalite sample app yet, here are some screenshots.
Here is the French yml file used for the UI translation/localization:
Here is the code to display a select box so the user can choose the publication date:
So you know,
&amp;lt;code&amp;gt;&amp;lt;%= :published_date.l %&amp;gt; &amp;lt;/code&amp;gt;  is the same as
&amp;lt;code&amp;gt;&amp;lt;%= :published_date.localize %&amp;gt; &amp;lt;/code&amp;gt;  Globalite will try to load the translation of the :published_date key using the locale you set.</description>
			<content type="html"><![CDATA[<p>If you haven&rsquo;t check out the <a href="https://globalite.googlecode.com/svn/sample/ui/">Globalite sample app</a> yet, here are some screenshots.</p>
<p>Here is the French yml file used for the UI translation/localization:</p>
<p><img src="https://myskitch.com/matt_a/fr.yml__ui-20070702-200052.jpg" alt="create a yml file with the translation"></p>
<p>Here is the code to display a select box so the user can choose the publication date:</p>
<p><img src="https://myskitch.com/matt_a/date_select-code-20070702-195558.jpg" alt="write some code to let the user choose a published date "></p>
<p>So you know,</p>
<pre><code>&lt;code&gt;&lt;%= :published_date.l %&gt;
&lt;/code&gt;
</code></pre>
<p>is the same as</p>
<pre><code>&lt;code&gt;&lt;%= :published_date.localize %&gt;
&lt;/code&gt;
</code></pre>
<p>Globalite will try to load the translation of the :published_date key using the locale you set. (if you didn&rsquo;t set a locale, it will try in English. If there was no English translation available, a warning message would be displayed instead of the translation. We could have also done the following:</p>
<pre><code>&lt;code&gt;&lt;%= :published_date.l('Published Date') %&gt;
&lt;/code&gt;
</code></pre>
<p>If you pass a string to the localization function, Globalite will display it in the case where it doesn&rsquo;t find a translation.</p>
<p>Here is the default view in English:</p>
<p><img src="https://myskitch.com/matt_a/date_select_en-20070702-192452.jpg" alt="let&rsquo;s look at the view in English (default locale)"></p>
<p>Change the locale to French  ( Locale.code = &lsquo;fr-*&rsquo;  or use the select box in the demo app).
Let&rsquo;s display the same page:</p>
<p><img src="https://myskitch.com/matt_a/date_select_fr-20070702-192257.jpg" alt="same date select box in French"></p>
<p>Note that in French, the date is different, on top of having translated month names, the order is different. American English format is year/month/day while the French format is day/month/year.</p>
<p>You get all of that for free and even more.</p>
<p>Just for the fun, here is another example of localization: currency. you might know it, but each country, on top of having a different currency display numbers differently.</p>
<p>In the England, it would look like that:</p>
<p><img src="https://myskitch.com/matt_a/nbr_to_currency-uk-20070702-203822.jpg" alt="uk"></p>
<p>Note that the currency is before the amount and that there&rsquo;s a separator for the thousands and a delimiter for the pence.</p>
<p>In France, it would look like that:</p>
<p><img src="https://myskitch.com/matt_a/nbr_to_currency-fr-20070702-202242.jpg" alt="fr"></p>
<p>The currency is after the amount and the French separator is actually the British delimiter and vice versa!</p>
<p>Spain also uses the Euro as currency but they don&rsquo;t display the same amount in the same way:</p>
<p><img src="https://myskitch.com/matt_a/nbr_to_currency-es-20070702-203736.jpg" alt="es"></p>
<p>The code to display the amount for each locale is the following:</p>
<pre><code>&lt;code&gt;&lt;%= number_to_currency(9999.99) %&gt;
&lt;/code&gt;
</code></pre>
<p>Pretty cool and simple, isn&rsquo;t it? Check out the <a href="https://globalite.googlecode.com/svn/sample/ui/">sample app</a> for more advance used.</p>
<p><em>Enjoy</em></p>
<p>p.s: thanks <a href="https://joshknowles.com">josh knowles</a> for the <a href="https://plasq.com/skitch/">skitch</a> invite, it&rsquo;s awesome!</p>
]]></content>
		</item>
		
		<item>
			<title>globalite update</title>
			<link>https://matt.aimonetti.net/posts/2007-06-globalite-update/</link>
			<pubDate>Wed, 27 Jun 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-06-globalite-update/</guid>
			<description>Today I updated Globalite, refactoring the code and fixing some issues.
I added a bunch of aliases since I was tired of typing:
&amp;lt;code&amp;gt;Globalite.current_language = :fr &amp;lt;/code&amp;gt;  I shortened it to
&amp;lt;code&amp;gt;Globalite.language = :fr &amp;lt;/code&amp;gt;  But the old method is still available so it won’t break your code ;)
The major change with this update is a better support for locales. Let’s say that in our application we setup the language to :fr (French) but we didn’t specify a country.</description>
			<content type="html"><![CDATA[<p>Today I updated Globalite, refactoring the code and fixing some issues.</p>
<p>I added a bunch of aliases since I was tired of typing:</p>
<pre><code>&lt;code&gt;Globalite.current_language = :fr
&lt;/code&gt;
</code></pre>
<p>I shortened it to</p>
<pre><code>&lt;code&gt;Globalite.language = :fr
&lt;/code&gt;
</code></pre>
<p>But the old method is still available so it won’t break your code ;)</p>
<p>The major change with this update is a better support for locales. Let’s say that in our application we setup the language to :fr (French) but we didn’t specify a country. Remember that Globalite lets you have specific translations/localizations per country so you can display dates, prices properly.</p>
<p>Previously, if my locale was set to :fr-* then Globalite would try to load the fr.yml files and not fr-FR.yml.</p>
<p>If you decided to use a fr.yml file for your UI localization, you might have noticed that all the Rails core messages weren’t translated(now you know why). This update deals with this issue and if a translation isn’t found in your locale, it will look for translations in your language but from a different country and pick a random one.</p>
<p>I’m expecting Rails core translations in Japanese, Korean and Chinese. Feel free to email me your own file and let me know on what project you used Globalite.</p>
]]></content>
		</item>
		
		<item>
			<title>rails hackfest status update</title>
			<link>https://matt.aimonetti.net/posts/2007-06-rails-hackfest-status-update/</link>
			<pubDate>Tue, 26 Jun 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-06-rails-hackfest-status-update/</guid>
			<description>The Rails hackfest is a chance for people to be rewarded for contributing source code to Ruby On Rails. The value of their contributions are accumulated and the results charted.
I’m honored to be listed as contributor number 4 few days before the end of the month. I know I got lucky with some of my patches getting merged in and that I might not be able to stay in the top 10, but I’m still glad I was able to help.</description>
			<content type="html"><![CDATA[<p><img src="https://www.railsontherun.com/assets/2007/6/26/hackfest-4.png" alt="Hackfest status 4 days before the end of the month"></p>
<p>The <a href="https://www.workingwithrails.com/hackfest/12-monthly-june-2-7">Rails hackfest</a> is a chance for people to be rewarded for contributing source code to Ruby On Rails. The value of their contributions are accumulated and the results charted.</p>
<p>I’m honored to be listed as contributor number 4 few days before the end of the month.
I know I got lucky with some of my patches getting merged in and that I might not be able to stay in the top 10, but I’m still glad I was able to help.</p>
]]></content>
		</item>
		
		<item>
			<title>vocac2aa fala portuguac2aas</title>
			<link>https://matt.aimonetti.net/posts/2007-06-vocac2aa-fala-portuguac2aas/</link>
			<pubDate>Tue, 26 Jun 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-06-vocac2aa-fala-portuguac2aas/</guid>
			<description>Globalite contributor: Marcus Derencius just submitted a Portuguese translation for Rails.
Your application can now speak Portuguese thanks to Globalite and Marcus :)</description>
			<content type="html"><![CDATA[<p>Globalite contributor: <a href="https://www.taoweb.com.br/">Marcus Derencius</a> just submitted a Portuguese translation for Rails.</p>
<p>Your application can now speak Portuguese thanks to Globalite and Marcus :)</p>
]]></content>
		</item>
		
		<item>
			<title>voce fala portugues</title>
			<link>https://matt.aimonetti.net/posts/2007-06-voce-fala-portugues/</link>
			<pubDate>Tue, 26 Jun 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-06-voce-fala-portugues/</guid>
			<description>Globalite contributor: Marcus Derencius just submitted a Portuguese translation for Rails.
Your application can now speak Portuguese thanks to Globalite and Marcus :)</description>
			<content type="html"><![CDATA[<p>Globalite contributor: <a href="https://www.taoweb.com.br/">Marcus Derencius</a> just submitted a Portuguese translation for Rails.</p>
<p>Your application can now speak Portuguese thanks to Globalite and Marcus :)</p>
]]></content>
		</item>
		
		<item>
			<title>mimetype_fu update</title>
			<link>https://matt.aimonetti.net/posts/2007-06-mimetype_fu-update/</link>
			<pubDate>Fri, 22 Jun 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-06-mimetype_fu-update/</guid>
			<description>Quick note to let you know that I updated mimetype_fu to actually get the mime type of a file using the file command on mac and linux. I still didn&amp;rsquo;t post an example since I&amp;rsquo;m planning on writing a patch for attachment_fu.</description>
			<content type="html"><![CDATA[<p>Quick note to let you know that I updated mimetype_fu to actually get the mime type of a file using the file command on mac and linux. I still didn&rsquo;t post an example since I&rsquo;m planning on writing a patch for attachment_fu.</p>
]]></content>
		</item>
		
		<item>
			<title>new rails plugin mimetype_fu</title>
			<link>https://matt.aimonetti.net/posts/2007-06-new-rails-plugin-mimetype_fu/</link>
			<pubDate>Thu, 14 Jun 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-06-new-rails-plugin-mimetype_fu/</guid>
			<description>mimetype_fu/ is a new plugin I just wrote. It&amp;rsquo;s simple and it can be really useful if you need to get the mime type of a file already on your server.
During one of my project, I add to migrate old assets from a legacy system to a new Rails app. The new app uses attachment fu and even though techno weenie did an amazing job, attachment_fu validation is based on the content type.</description>
			<content type="html"><![CDATA[<p><a href="https://code.google.com/p/mimetype-fu/">mimetype_fu/</a> is a new plugin I just wrote. It&rsquo;s simple and it can be really useful if you need to get the mime type of a file already on your server.</p>
<p>During one of my project, I add to migrate old assets from a legacy system to a new Rails app. The new app uses <a href="https://svn.techno-weenie.net/projects/plugins/attachment_fu/">attachment fu</a> and even though techno weenie did an amazing job, attachment_fu validation is based on the content type. A_fu gets the content type coming from the CGI query.</p>
<p>Unit test has a helper faking this process but in real life, if you use a Flash uploader (Flash doesn&rsquo;t give you the proper mime type/content type) or if you want to migrate files, the attachment_fu validation won&rsquo;t work for you.</p>
<p>The solution is simple: <a href="https://code.google.com/p/mimetype-fu/">mimetype_fu/</a></p>
<p><a href="https://code.google.com/p/mimetype-fu/">mimetype_fu/</a> extends the File class and is really easy to use:</p>
<pre><code>&lt;code&gt;File.mime_type?(@file)
&lt;/code&gt;
</code></pre>
<p>Check it out <a href="https://code.google.com/p/mimetype-fu/">https://code.google.com/p/mimetype-fu/</a></p>
<p>Expect a post showing how a ninja would use the mimetype_fu / attachment_fu combo :)</p>
]]></content>
		</item>
		
		<item>
			<title>create a rails edge rspec project</title>
			<link>https://matt.aimonetti.net/posts/2007-06-create-a-rails-edge-rspec-project/</link>
			<pubDate>Wed, 06 Jun 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-06-create-a-rails-edge-rspec-project/</guid>
			<description>Recently I helped few people moving to Rails Edge and start using RSpec. I realized that I learned few tricks and even if for me everything seemed quite simple, things are not that simple when you recently started with Rails.
This would work on Mac and Linux, sorry Windows users, you&amp;rsquo;ll have to slightly change the code below.
Live on the Edge This is actually a bit tricky but it was very well covered by John Nunemaker in this post</description>
			<content type="html"><![CDATA[<p>Recently I helped few people moving to <a href="https://dev.rubyonrails.org/">Rails Edge</a> and start using <a href="https://rspec.rubyforge.org">RSpec</a>. I realized that I learned few tricks and even if for me everything seemed quite simple, things are not that simple when you recently started with Rails.</p>
<p>This would work on Mac and Linux, sorry Windows users, you&rsquo;ll have to slightly change the code below.</p>
<h1 id="live-on-the-edge">Live on the Edge</h1>
<p>This is actually a bit tricky but it was very well covered by <a href="https://addictedtonew.com/about/">John Nunemaker</a> in <a href="https://railstips.org/2007/5/31/even-edgier-than-edge-rails">this post</a></p>
<p>To sum John&rsquo;s post:</p>
<p>Create a normal rails project:</p>
<pre><code>&lt;code&gt;$ rails my_project
$ cd my_project

$ rake rails:freeze:edge
&lt;/code&gt;
</code></pre>
<p>(or use checkout edge in the vendor folder)</p>
<pre><code>&lt;code&gt;$ cd ..
$ ruby my_project/vendor/rails/railties/bin/rails my_edgie_project
&lt;/code&gt;
</code></pre>
<p>You now have have a real Edge project called my_edgie_project. You can delete the my_project folder since we only used it to create our real edge project.</p>
<p>Now, we are not really done since we need to add the Edge files into our vendor folder so we don&rsquo;t use our local rails gem.</p>
<p>I would refer to another post from John, that you can find <a href="https://railstips.org/2007/3/5/my-local-rails-setup">there</a></p>
<pre><code>&lt;code&gt;$ mkdir ~/rails
$ cd ~/rails
$ svn co https://dev.rubyonrails.com/svn/rails/trunk .
&lt;/code&gt;
</code></pre>
<p>We just created a rails folder called rails in our home folder and we checked out edge/trunk in it.
Now let&rsquo;s go in our Rails app and setup a symlink to the trunk folder we just created.</p>
<pre><code>&lt;code&gt;$ cd ~/rails_projects/my_edgie_project
$ ln -s ~/rails/trunk vendor/rails
&lt;/code&gt;
</code></pre>
<p>If you are using subversion, you can ignore the symlink so it doesnâ€™t try to version it:</p>
<pre><code>&lt;code&gt;$ svn propset svn:ignore &quot;rails&quot; vendor/
$ svn commit -m &quot;using new sweet rails setup as recommended by John Nunemaker&quot;
$ svn up
&lt;/code&gt;
</code></pre>
<p><a href="https://railstips.org/2007/3/5/my-local-rails-setup">Read more</a> for advanced settings etc&hellip;</p>
<h1 id="install-rspec">Install RSpec</h1>
<p>Very straight forward, you just need to follow <a href="https://rspec.rubyforge.org/documentation/rails/install.html">the documentation</a></p>
<pre><code>&lt;code&gt;$ cd ~/rails_projects/my_edgie_project
$ ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec
$ ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec_on_rails
&lt;/code&gt;
</code></pre>
<p>If you have TextMate, you might want to download the <a href="https://rubyforge.org/frs/?group_id=797">latest RSpec-X.Y.Z.tmbundle.tgz Bundle</a></p>
<p>Next thing you want to do is to install <a href="https://www.zenspider.com/ZSS/Products/ZenTest/">ZenTest</a></p>
<pre><code>&lt;code&gt;$ sudo gem install ZenTest
&lt;/code&gt;
</code></pre>
<p>Make sure you install all the required packages.</p>
<p>If you are using <a href="https://growl.info/">Growl</a> create a new file called .autotest in your home directory:</p>
<pre><code>&lt;code&gt;$mate ~./autotest
&lt;/code&gt;
</code></pre>
<p>and add the following 2 lines to be warned when your specs/examples fail/pass</p>
<pre><code>&lt;code&gt;require 'autotest/redgreen'
require 'autotest/growl'
&lt;/code&gt;
</code></pre>
<p>Now, lets go back to our project and create a model using the rspec scaffold (it uses scaffold_resource generator and create all the specs for you)</p>
<pre><code>&lt;code&gt;$ cd ~/rails_projects/my_edgie_project
$ ruby script/generate rspec_scaffold User first_name:string last_name:string :age:integer
&lt;/code&gt;
</code></pre>
<p>Now, let&rsquo;s start autotest (from zentest) so out code is tested in the background</p>
<pre><code>&lt;code&gt;$ autotest
&lt;/code&gt;
</code></pre>
<p>There you go, really to modify your RSpec examples, make them fail, fix your code, examples should pass, refactor your code and start again :)</p>
]]></content>
		</item>
		
		<item>
			<title>railsresources org is live almost</title>
			<link>https://matt.aimonetti.net/posts/2007-06-railsresources-org-is-live-almost/</link>
			<pubDate>Sat, 02 Jun 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-06-railsresources-org-is-live-almost/</guid>
			<description>The guys at integrum launched their resources site as promised.
— CHECK IT OUT —
There’s not much there yet but I would recommend to subscribe to their feed!</description>
			<content type="html"><![CDATA[<p>The guys at <a href="https://integrumtech.com">integrum</a> launched <a href="https://railsresources.org/">their resources site</a> as promised.</p>
<p>— <a href="https://railsresources.org/">CHECK IT OUT</a> —</p>
<p>There’s not much there yet but I would recommend to subscribe to their feed!</p>
]]></content>
		</item>
		
		<item>
			<title>first rails merged in</title>
			<link>https://matt.aimonetti.net/posts/2007-05-first-rails-merged-in/</link>
			<pubDate>Sat, 26 May 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-05-first-rails-merged-in/</guid>
			<description>I&amp;rsquo;m quite glad to let you know that my first patch made it to Rails Edge. UPDATE: Ryan Daigle covered the new added features in his blog How cool is that?
That&amp;rsquo;s a great achievement that I owe to josh Knowles and Josh Susser
Josh Knowles and Matt Heidemann from Integrum started working on rake_tasks a little while ago. I helped them hacking this cool plugin. After a while, we realized that the plugin was getting too big and we decided to split it in two:</description>
			<content type="html"><![CDATA[<h2 id="im-quite-glad-to-let-you-know-that-my-first-patch-made-it-to-rails-edge">I&rsquo;m quite glad to let you know that my first patch made it to Rails Edge.</h2>
<p>UPDATE: Ryan Daigle covered the new added features in <a href="https://ryandaigle.com/articles/2007/5/29/what-s-new-in-edge-rails-new-database-rake-tasks">his blog</a>
How cool is that?</p>
<p>That&rsquo;s a great achievement that I owe to <a href="https://joshknowles.com">josh Knowles</a> and <a href="https://hasmanythrough.com">Josh Susser</a></p>
<p><a href="https://joshknowles">Josh Knowles</a> and Matt Heidemann from <a href="https://integrumtech.com">Integrum</a> started working on <a href="https://svn.integrumtech.com/public/plugins/rake_tasks/">rake_tasks</a> a little while ago. I helped them hacking this cool plugin. After a while, we realized that the plugin was getting too big and we decided to split it in two:</p>
<ul>
<li>
<p>db_tasks</p>
</li>
<li>
<p>svn_tasks</p>
</li>
</ul>
<p>Without telling the other guys (sorry!), I started <a href="https://groups.google.com/group/rubyonrails-core/browse_thread/thread/194c845ae5678266">discussing</a> merging some of the rake_tasks plugin in Rails core.</p>
<p>I then submitted my patch following <a href="https://hasmanythrough.com/layingtracks">Josh Susser</a> recommendations.</p>
<p>Today, Josh congratulated me on the merge. I&rsquo;m quite glad/proud that our work made it to Edge.</p>
<h2 id="whats-that-patch-anyway">What&rsquo;s that patch anyway?</h2>
<p>Here are the 2 features my patch added to the future Rails 2.0:</p>
<ul>
<li>
<p>MySQL: create_database takes :charset and :collation options. Charset defaults to utf8.</p>
</li>
<li>
<p>Add db:create, drop, reset, charset, and collation tasks</p>
</li>
</ul>
<p>That means that you cna now do that:</p>
<pre><code>&lt;code&gt;$rails my_app
$rake db:create
$ruby script/server
&lt;/code&gt;
</code></pre>
<p>That&rsquo;s it, you have a working Rails app!! Well, almost, there&rsquo;s nothing it in yet but at least your databases are created. Ohh, and your database is unicode, that also means that all your new tables will be utf8.</p>
<p>Enjoy :)</p>
]]></content>
		</item>
		
		<item>
			<title>dbtasks intro</title>
			<link>https://matt.aimonetti.net/posts/2007-05-dbtasks-intro/</link>
			<pubDate>Tue, 22 May 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-05-dbtasks-intro/</guid>
			<description>Josh knowles and Matt Heidemann from Integrum and I released few weeks a go a cool plugin called rake_tasks
The thing is that the plugin was getting too big when I started hacking the MySQL adapter and adding utf-8 support we figured out it was smarter to split the plugin and create db_tasks and svn_tasks
I temporarily hosted db_tasks there:
https://svn.aimonetti.net/public/plugins/db_tasks/
&amp;lt;code&amp;gt;ruby script/plugin install https://svn.aimonetti.net/public/plugins/db_tasks/ &amp;lt;/code&amp;gt;  check your Rake tasks:</description>
			<content type="html"><![CDATA[<p><a href="https://joshknowles.com">Josh knowles</a> and Matt Heidemann from <a href="https://integrumtech.com">Integrum</a> and I released few weeks a go a cool plugin called <a href="https://svn.integrumtech.com/public/plugins/rake_tasks/">rake_tasks</a></p>
<p>The thing is that the plugin was getting too big when I started hacking the MySQL adapter and adding utf-8 support we figured out it was smarter to split the plugin and create <a href="https://svn.aimonetti.net/public/plugins/db_tasks/">db_tasks</a> and svn_tasks</p>
<p>I temporarily hosted db_tasks there:</p>
<p><a href="https://svn.aimonetti.net/public/plugins/db_tasks/">https://svn.aimonetti.net/public/plugins/db_tasks/</a></p>
<pre><code>&lt;code&gt;ruby script/plugin install https://svn.aimonetti.net/public/plugins/db_tasks/
&lt;/code&gt;
</code></pre>
<p>check your Rake tasks:</p>
<ul>
<li>
<p><em>rake db:create</em>      Creates the databases defined in your config/database.yml (unless they already exist) You can also specify the charset and collation you want your dbs to use: rake db:create CHARSET=&lsquo;latin1&rsquo; COLLATION=&lsquo;latin1_bin&rsquo;)</p>
</li>
<li>
<p><em>rake db:drop</em>       Drops the database for your currenet RAILS_ENV as defined in config/database.yml</p>
</li>
<li>
<p><em>rake db:reset</em>       Drops, creates and then migrates the database for your current RAILS_ENV</p>
</li>
<li>
<p><em>rake db:shell</em>       Launches the database shell using the values defined in config/database.yml</p>
</li>
<li>
<p><em>rake db:charset</em>    Returns the charset of your current RAILS_ENV database</p>
</li>
<li>
<p><em>rake db:collation</em>   Returns the collation of your current RAILS_ENV database</p>
</li>
<li>
<p><em>rake db:update_connection_settings</em>  add the encoding format to each environment in the database.yml file</p>
</li>
</ul>
<p>By default, your new databases will be utf8, you can automatically create your databases by typing:</p>
<p>rake db:create</p>
<p>or reset your databases (drop, create, migrate)</p>
<p>rake db:reset</p>
<h2 id="another-simple-plugin-for-lazy-developers">Another simple plugin for lazy developers.</h2>
]]></content>
		</item>
		
		<item>
			<title>globalite i18n i10n solution</title>
			<link>https://matt.aimonetti.net/posts/2007-05-globalite-i18n-i10n-solution/</link>
			<pubDate>Tue, 15 May 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-05-globalite-i18n-i10n-solution/</guid>
			<description>I&amp;rsquo;ve been recently slightly annoyed by the lack of simple yet powerful internationalization/localization plugin for Rails. It seems like the only real solution out there is Globalize
However, it&amp;rsquo;s a heavy, bloated, hard to setup plugin. I might seem to complain, but I&amp;rsquo;m actually glad that someone came up with a decent solution. Globalize is quite powerful but I would like to see something simpler, lighter and easier to use.</description>
			<content type="html"><![CDATA[<p>I&rsquo;ve been recently slightly annoyed by the lack of simple yet powerful internationalization/localization plugin for Rails.
It seems like the only real solution out there is <a href="https://www.globalize-rails.org">Globalize</a></p>
<p>However, it&rsquo;s a heavy, bloated, hard to setup plugin. I might seem to complain, but I&rsquo;m actually glad that someone came up with a decent solution. Globalize is quite powerful but I would like to see something simpler, lighter and easier to use.</p>
<p>While I was looking for alternate solutions, <a href="https://errtheblog.com/">Err</a> released <a href="https://errtheblog.com/post/4396">Gibberish</a> a simple and nice localization plugin.</p>
<p>Looking at Chris' code, I found a clean and nice solution but unfortunately too simple. The major problem I had with Giberrish was the lack of support for locales. That means that one cannot create an application supporting British English and American English. I lived in  both America and the UK and believe me, I can never spell some words properly. How should I spell the following words: colours or colors, behaviour or behavior, aluminium or aluminum? On top of that, your UI might be slightly different based on the region your visitor is coming from. Localization is more than translation.</p>
<p>Anyway, I decided to come up with my own solution, a breed of the best features from my favorite i18n/l10n projects. This hybrid solution should, hopefully be useful for people not needing all the resources of Globalize. I called my new project <em>Globa_lite</em>_</p>
<h2 id="whats-cool-with-globalite">What&rsquo;s cool with Globalite?</h2>
<ul>
<li>
<p>Simple UI localization</p>
<ul>
<li>
<p>support different locales</p>
</li>
<li>
<p>yml file based</p>
</li>
<li>
<p>simple syntax</p>
</li>
<li>
<p>no setup needed</p>
</li>
<li>
<p>enough for most projects needing localization</p>
</li>
<li>
<p>pass variables to the localization and let the translator deal with it</p>
</li>
</ul>
</li>
<li>
<p>Simple Rails Localization</p>
<ul>
<li>
<p>support different locales</p>
</li>
<li>
<p>nothing to do, rails comes in your own language (including currency conversion and other helpers)</p>
</li>
<li>
<p>yml file based localization for easy update</p>
</li>
<li>
<p>support for Rails 1.2x</p>
</li>
<li>
<p>simple to maintain</p>
</li>
<li>
<p>simple to add/edit a new locale</p>
</li>
</ul>
</li>
<li>
<p>Simple content i18n/l10n (coming soon)</p>
</li>
</ul>
<h2 id="ui-localization">UI localization:</h2>
<ul>
<li>
<p>Create a lang/ui folder at the root of the folder.</p>
</li>
<li>
<p>create 2 localization files: fr.yml and en-US.yml</p>
</li>
<li>
<p>add localization keys in the files:</p>
</li>
</ul>
<p>fr.yml:</p>
<pre><code>&lt;code&gt;hello: bonjour

welcome: bienvenue
&lt;/code&gt;
</code></pre>
<p>en-US.yml</p>
<pre><code>&lt;code&gt;hello: howdy

welcome: welcome
&lt;/code&gt;
</code></pre>
<ul>
<li>
<p>Declare the current locale or language</p>
<p><code>Globalite.current_language :fr
</code></p>
</li>
<li>
<p>In your view (or anywhere else) localize a key</p>
<p><code>:hello.l
</code></p>
</li>
</ul>
<p>or</p>
<pre><code>&lt;code&gt;:hello.localize
&lt;/code&gt;
</code></pre>
<p>you can also do</p>
<pre><code>&lt;code&gt;:unknown_key.l(&quot;this is the default text to display if the localization isn't found&quot;)
&lt;/code&gt;
</code></pre>
<p>Also you can pass one or many variables to the localization(check the documentation)</p>
<h2 id="rails-localization">Rails Localization</h2>
<p>Rails is automatically localized for you (meaning most helpers, including the currency converter are localized for the locale you declared).
You really easily add a new supported rails language/settings by adding a yml file or editing an existing one. (for now, I only create an English and a French localization file, but I&rsquo;ll add plenty more very soon)</p>
<p>Globalite also saves the locale in the session allowing many users to see a site at the same time in different languages :)</p>
<p>I believe Globalite is/will be a good solution for most of my international projects. It still lacks the content i18n and l10n as well as support for pluralization but it should be added soon.</p>
<p>Give it a try and let me know what you think:</p>
<p><a href="https://rubyforge.org/projects/globalite">RubyForge page</a></p>
<p>svn repository: svn checkout svn://rubyforge.org/var/svn/globalite/trunk globalite</p>
<p><a href="https://viewvc.rubyforge.mmmultiworks.com/cgi/viewvc.cgi/?root=globalite">view repository content</a></p>
<p>ps: The project is still in beta and will change during the next few weeks, feel free to submit patches, ideas, suggestions&hellip;</p>
]]></content>
		</item>
		
		<item>
			<title>note to myself</title>
			<link>https://matt.aimonetti.net/posts/2007-05-note-to-myself/</link>
			<pubDate>Fri, 11 May 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-05-note-to-myself/</guid>
			<description>This morning I couldn&amp;rsquo;t remember how to get an array with only the unique properties of a Model attribute. For instance, I have a User model, and I want to retrieve the list of all my users&#39; cities. I also don&amp;rsquo;t want to retrieve all the attributes and only the unique rows.
in my model:
&amp;lt;code&amp;gt;def self.cities User.find(:all, :select =&amp;gt; &amp;quot;DISTINCT city&amp;quot;).map(&amp;amp;:city) end &amp;lt;/code&amp;gt;  Clean and simple, but for some reason I know I&amp;rsquo;ll forget and loose 5 minutes trying different things.</description>
			<content type="html"><![CDATA[<p>This morning I couldn&rsquo;t remember how to get an array with only the unique properties of a Model attribute. For instance, I have a User model, and I want to retrieve the list of all my users' cities. I also don&rsquo;t want to retrieve all the attributes and only the unique rows.</p>
<p>in my model:</p>
<pre><code>&lt;code&gt;def self.cities
    User.find(:all, :select =&gt; &quot;DISTINCT city&quot;).map(&amp;:city)
end
&lt;/code&gt;
</code></pre>
<p>Clean and simple, but for some reason I know I&rsquo;ll forget and loose 5 minutes trying different things.</p>
]]></content>
		</item>
		
		<item>
			<title>installing postgresql on mac</title>
			<link>https://matt.aimonetti.net/posts/2007-05-installing-postgresql-on-mac/</link>
			<pubDate>Wed, 09 May 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-05-installing-postgresql-on-mac/</guid>
			<description>I&amp;rsquo;m working on a Rails project and I need to make sure that our code is compatible with PostgreSQL. I never installed/used before and since I&amp;rsquo;m lazy and rely on other people knowledge, I decided to install Postgresql using MacPort.
It was actually simpler than I expected. I simply followed this post and almost everything went ok.
&amp;lt;code&amp;gt;sudo port install postgresql81 +server &amp;lt;/code&amp;gt;  will install postgresql
&amp;lt;code&amp;gt;sudo gem install postgres -- --with-pgsql-include-dir=/opt/local/include/postgresql81 --with-pgsql-lib-dir=/opt/local/lib/postgresql81 &amp;lt;/code&amp;gt;  Will do a gem install</description>
			<content type="html"><![CDATA[<p>I&rsquo;m working on a Rails project and I need to make sure that our code is compatible with PostgreSQL. I never installed/used before and since I&rsquo;m lazy and rely on other people knowledge, I decided to install Postgresql using <a href="https://blog.duncandavidson.com/2006/04/sandboxing_rail.html">MacPort</a>.</p>
<p>It was actually simpler than I expected. I simply followed <a href="https://blog.evanweaver.com/articles/2006/06/26/building-ruby-rails-lighttpd-mysql-and-postgres-on-os-x-tiger">this post</a> and almost everything went ok.</p>
<pre><code>&lt;code&gt;sudo port install postgresql81 +server
&lt;/code&gt;
</code></pre>
<p>will install postgresql</p>
<pre><code>&lt;code&gt;sudo gem install postgres -- --with-pgsql-include-dir=/opt/local/include/postgresql81 --with-pgsql-lib-dir=/opt/local/lib/postgresql81
&lt;/code&gt;
</code></pre>
<p>Will do a gem install</p>
<p>Start your server automatically by doing:</p>
<pre><code>&lt;code&gt;sudo launchctl load -w /Library/LaunchDaemons/org.macports.postgresql81-server.plist
sudo launchctl start org.macports.postgresql81-server
&lt;/code&gt;
</code></pre>
<p>Create a folder for your dbs
mkdir /opt/local/var/db/pgsql/data</p>
<p>Add pgsql to your path (I use textmate)</p>
<pre><code>&lt;code&gt;mate ~/.profile
&lt;/code&gt;
</code></pre>
<p>My path looks like that:</p>
<pre><code>&lt;code&gt;export PATH=/opt/local/bin:/opt/local/sbin:/opt/local/apache2/bin:/opt/local/lib/postgresql81/bin/:$PATH

export PGDATA=&quot;/opt/local/var/db/pgsql/data&quot;
&lt;/code&gt;
</code></pre>
<p>restart your shell (or open a new tab) and type
initdb -D /opt/local/var/db/pgsql/data</p>
<p>Success. You can now start the database server using:</p>
<pre><code>&lt;code&gt;postmaster -D /opt/local/var/db/pgsql/data
&lt;/code&gt;
</code></pre>
<p>or
pg_ctl -D /opt/local/var/db/pgsql/data -l logfile start</p>
<p>Now, create your db: $ createdb test -E utf8    or drop your newly created db: $ dropdb test</p>
<p>That&rsquo;s it, it was easy.</p>
<p><a href="https://developer.apple.com/internet/opensource/postgres.html">more info from apple</a></p>
]]></content>
		</item>
		
		<item>
			<title>myconfplan com</title>
			<link>https://matt.aimonetti.net/posts/2007-04-myconfplan-com/</link>
			<pubDate>Thu, 26 Apr 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-04-myconfplan-com/</guid>
			<description>DrNic the most famous Australian Rails developer surprisingly doesn’t spend most of his time working on Rails read interview That’s maybe why he recently became so active in the Rails community ( see Magic Multi-Connections, Magic Models, map_by_methods, Gem Generator etc..)
Today he released something very helpful for the Rails Community, not another Gem or another cool plugin to extend Rails but a web application to help you planning your conferences.</description>
			<content type="html"><![CDATA[<p><a href="https://drnicwilliams.com/">DrNic</a> the most famous Australian Rails developer surprisingly doesn’t spend most of his time working on Rails  <a href="https://www.akitaonrails.com/pages/drnic">read interview</a>
That’s maybe why he recently became so active in the Rails community ( see <a href="https://www.loudthinking.com/arc/000610.html">Magic Multi-Connections</a>, Magic Models, map_by_methods, Gem Generator etc..)</p>
<p>Today he released something very helpful for the Rails Community, not another Gem or another cool plugin to extend Rails but a <a href="https://myconfplan.com">web application</a> to help you planning your conferences. We already had other tools such as <a href="https://railsconf2007.conferencemeetup.com/p/276-matt-aimonetti">conference meetup</a> but it’s the first time that we get a product helping you to plan a conference by scheduling the sessions you want to attend.</p>
<p><img src="https://farm1.static.flickr.com/169/473390616_12c7596617.jpg?v=0" alt="screenshot"></p>
<p><a href="https://flickr.com/photos/railsontherun/473389852/in/photostream/">screenshot of the entire schedule</a></p>
<p>I had a quick chat with DrNic about his latest creation and here is what he said:</p>
<p>“its been fun building just how I thought session selection might look + feel
web2.0 = permissive voyeurism I think!”</p>
<p>I share the same vision than Nic on session selection and I really enjoyed booking my Rails sessions and seeing what other people selected. (I guess that’s my voyeur side, don’t you like web2.0?)</p>
<p>If you wanna see what I planned on attending, checkout my schedule: <a href="https://myconfplan.com/conferences/RailsConf2007/users/matt">my schedule</a></p>
<p>Thanks Nic for the good work and too bad you are not presenting anything at the RailsConf (move your bum to come up with a <em>better</em> submission next year!)</p>
]]></content>
		</item>
		
		<item>
			<title>rspec bundle for textmate</title>
			<link>https://matt.aimonetti.net/posts/2007-04-rspec-bundle-for-textmate/</link>
			<pubDate>Wed, 18 Apr 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-04-rspec-bundle-for-textmate/</guid>
			<description>I recently realized that a lot of people using RSpec didn’t use the great TextMate bundle designed for them.
You might not think you need an extra bundle, or maybe you never used a bundle ever and don’t know why you would try one. I’ll try to change your mind, let’s look at some screenshots first:
This is what you will want to see before checking in your code:
This is what you will see before you write your code:</description>
			<content type="html"><![CDATA[<p>I recently realized that a lot of people using <a href="https://rspec.rubyforge.org">RSpec</a> didn’t use the great <a href="https://macromates.com/">TextMate</a> bundle designed for them.</p>
<p>You might not think you need an extra bundle, or maybe you never used a bundle ever and don’t know why you would try one. I’ll try to change your mind, let’s look at some screenshots first:</p>
<p>This is what you will want to see before checking in your code:</p>
<p><img src="https://farm1.static.flickr.com/209/463687467_87e92fb79e.jpg?v=0" alt="Specs passing"></p>
<p>This is what you will see before you write your code:</p>
<p><img src="https://farm1.static.flickr.com/212/463687455_a6cc15a8bf.jpg?v=0" alt="Specs failing"></p>
<p>This is how you will run your specs:</p>
<p><img src="https://farm1.static.flickr.com/216/463687471_431a3a2939.jpg?v=0" alt="Specs commands"></p>
<p>This is all you get for free to save you some precious minutes every day:</p>
<p><img src="https://farm1.static.flickr.com/167/463687473_0f27cedac4.jpg?v=0" alt="Snippets"></p>
<p><strong>How to install?</strong></p>
<p>Easy, checkout the file from RSpec repository:</p>
<pre><code>&lt;code&gt;svn co svn://rubyforge.org/var/svn/rspec/trunk/RSpec.tmbundle
&lt;/code&gt;
</code></pre>
<p>Double click on the file and that’s it! You are ready to go. (you would obviously need RSpec plugin or gem).</p>
<p>Thank you to all the RSpec team for creating such a great tool.</p>
]]></content>
		</item>
		
		<item>
			<title>rails and flash</title>
			<link>https://matt.aimonetti.net/posts/2007-04-rails-and-flash/</link>
			<pubDate>Mon, 09 Apr 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-04-rails-and-flash/</guid>
			<description>With the recent Buzz around Adobe Apollo I figured out that since I recently switched to Mac and that I didn’t try the latest Flex upgrade, I should try Flex 2.01 for Mac.
I really like what Adobe did with Flex, Unit testing, better accessibility, etc… but one thing I regret, it’s getting closer and closer to Java and AS3 syntax is a pain to use when you got used to Ruby.</description>
			<content type="html"><![CDATA[<p>With the recent Buzz around <a href="https://labs.adobe.com/wiki/index.php/Apollo">Adobe Apollo</a> I figured out that since I recently switched to Mac and that I didn’t try the latest Flex upgrade, I should try <a href="https://www.adobe.com/products/flex/">Flex 2.01</a> for Mac.</p>
<p>I really like what Adobe did with Flex, Unit testing, better accessibility, etc… but one thing I regret, it’s getting closer and closer to Java and <a href="https://flexblog.faratasystems.com/?p=115">AS3 syntax</a> is a pain to use when you got used to Ruby.</p>
<p>Anyway, what I really wanted to do was to have Flash quickly access my Restful Rails app. The adobe guys came up with a <a href="https://code.google.com/p/rubyonrails-ria-sdk-by-adobe/">RoR Ria SDK</a> but well….   it only covers Flex and requires FlashPlayer 9.
I also found some great <a href="https://blog.vixiom.com/2006/08/23/flash-remoting-for-rails-tutorial/">tutorials</a> on how to use the efficient  <a href="https://osflash.org/documentation/amf">AMF messaging protocol</a> with Rails using the <a href="https://www.themidnightcoders.com/weborb/rubyonrails/index.htm">WebOrb for Rails plugins</a></p>
<p>All that was really nice and I had fun, but it was an overkill for what I wanted to do. Let me show you how in less than 5 minutes how you can access you Rails Model from Flash and add some new item directly from Flash.</p>
<p>Create your new Rails app and use the script/generate scaffold_resource command to generate your Event Model.</p>
<pre><code>&lt;code&gt;script/generate scaffold_resource Event
&lt;/code&gt;
</code></pre>
<p>It should create all that for you:</p>
<pre><code>&lt;code&gt;exists  app/models/
  exists  app/controllers/
  exists  app/helpers/
  create  app/views/events
  exists  test/functional/
  exists  test/unit/
  create  app/views/events/index.rhtml
  create  app/views/events/show.rhtml
  create  app/views/events/new.rhtml
  create  app/views/events/edit.rhtml
  create  app/views/layouts/events.rhtml
  identical  public/stylesheets/scaffold.css
  create  app/models/event.rb
  create  app/controllers/events_controller.rb
  create  test/functional/events_controller_test.rb
  create  app/helpers/events_helper.rb
  create  test/unit/event_test.rb
  create  test/fixtures/events.yml
  exists  db/migrate
  create  db/migrate/001_create_events.rb
  route  map.resources :events
&lt;/code&gt;
</code></pre>
<p>let’s edit the migration file:
db/migrate/001_create_events.rb</p>
<pre><code>&lt;code&gt;class CreateEvents &lt; ActiveRecord::Migration
  def self.up
    create_table :events do |t|
      t.column :title, :string
      t.column :description, :string
      t.column :location, :string
        t.column :starts_at, :datetime
        t.column :ends_at, :datetime
    end
  end

  def self.down
    drop_table :events
  end
end
&lt;/code&gt;
</code></pre>
<p>And let&rsquo;s add some fixtures:
test/fixtures/events.yml</p>
<pre><code>&lt;code&gt;meeting:
  id: 1
</code></pre>
<p>title = &ldquo;rails and flash&rdquo;
description = Boring meeting with the whole staff
location: conference room
starts_at: 2007-11-02 09:00:00
ends_at: 2007-11-02 10:30:00
Joe_bday:
id: 2
title = &ldquo;rails and flash&rdquo;
description = Come and celebrate Joe&rsquo;s Birthday
location: Lapin Agile Pub
starts_at: 2007-09-07 20:00:00
ends_at: 2007-09-07 23:30:00
</code></p>
<p>Ok, now simply migrate your database,load the fixtures and start the webrick:</p>
<pre><code>&lt;code&gt;rake db:migrate
rake db:fixtures:load
script/server
&lt;/code&gt;
</code></pre>
<p>Great, we are done with Rails.</p>
<p>Let&rsquo;s launch Flash</p>
<p>Create a new Flash document and create a new .As fie in TextMate (or your favorite editor). We&rsquo;ll write a quick ActionScript class to access Rails.</p>
<pre><code>&lt;code&gt;class Restfulflash{
    public var gateway:String;

    function Resftfulflash(gateway:String){
        this.set_gateway(gateway);
    }
    public function set_gateway(gateway:String){
        this.gateway = gateway;
        trace(&quot;gateway set to:&quot;+gateway);
    }

    public function get(model, callback){
        var railsReply:XML = new XML();
        railsReply.ignoreWhite = true;
        railsReply.onLoad = function(success:Boolean){
            if (success) {
                    trace ('Rails responded: '+railsReply);
                    callback.text = railsReply;
            } else {
                    trace ('Error while waiting for Rails to reply');
               callback.text = 'error';
            }
        }
        var railsRequest:XML = new XML();
        railsRequest.contentType=&quot;application/xml&quot;;
        railsRequest.sendAndLoad(this.gateway+model, railsReply);
        delete railsRequest;
    }

    public function create(model, newItem){
        railsRequest.onLoad = function(success){
                trace(&quot;Item creation success: &quot; + success);
                trace(this);
        };
        var railsRequest:XML = new XML();
        railsRequest.parseXML(newItem);
        railsRequest.contentType=&quot;application/xml&quot;;
        railsRequest.sendAndLoad(this.gateway+model+'/create/', railsRequest,'POST');
        delete railsRequest;
    }
}
&lt;/code&gt;
</code></pre>
<p>Save this file in the same directory as your .fla file</p>
<p>In your fla file add:</p>
<pre><code>&lt;code&gt;// Create a XML object to hold the events from our Rails app
rails_events = new XML();

// Prepare the connection to Rails (it would be nicer to do that in 1 step, but to make things clearer i decided to do it in 2)
var rails:Restfulflash = new Restfulflash();
rails.set_gateway(&quot;https://localhost:3000/&quot;);

// Get the events from rails and load the result in the rails_event XML object.
rails.get('events', rails_events);
trace(rails_events);

// Let's create a new event
newEvent = new XML('&lt;event&gt;&lt;description&gt;Spend some time with Grandma before its too late&lt;/description&gt;&lt;ends-at type=&quot;datetime&quot;&gt;2007-11-02T18:30:00-07:00&lt;/ends-at&gt;&lt;id type=&quot;integer&quot;&gt;1&lt;/id&gt;&lt;location&gt;Paris, France&lt;/location&gt;&lt;starts-at type=&quot;datetime&quot;&gt;2007-11-02T16:00:00-07:00&lt;/starts-at&gt;&lt;title&gt;Visit Grandma&lt;/title&gt;&lt;/event&gt;&amp;#8217;)
rails.create(&amp;#8216;events&amp;#8217;, newEvent);

// Verify  that the event was added
rails.get(&amp;#8216;events&amp;#8217;, rails_events);
trace(rails_events);
&lt;/code&gt;
</code></pre>
<p>There you go, you have all the events provided to you by Rails nicely prepared in an easy to parse XML object. You can bind the results to a Datagrid or display the info the way you want it. Ohh and by the way, we just added a new Event to the database… easy, isn’t it?  The code is a bit dirty but it’s still a good example why you need to use REST and how easy it is to get Flash to talk with Rails. (I strongly encourage that you also look at the very good WebOrb plugin for Rails)</p>
]]></content>
		</item>
		
		<item>
			<title>migrating legacy app part 2</title>
			<link>https://matt.aimonetti.net/posts/2007-04-migrating-legacy-app-part-2/</link>
			<pubDate>Mon, 02 Apr 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-04-migrating-legacy-app-part-2/</guid>
			<description></description>
			<content type="html"><![CDATA[]]></content>
		</item>
		
		<item>
			<title>migrating legacy app part 1</title>
			<link>https://matt.aimonetti.net/posts/2007-03-migrating-legacy-app-part-1/</link>
			<pubDate>Fri, 30 Mar 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-03-migrating-legacy-app-part-1/</guid>
			<description>I recently started working on migrating an old PHP based application to a new sexy Rails app. The old model was kind of messy, the usual case of bloated, feature creep app written by many people without any standard conventions.
Anyway, I have to migrate users and content from many sites using the legacy app.
Data Structure Instead of having 1 code base and 1 database per site, we now only have 1 code base and 1 database for all sites on a server.</description>
			<content type="html"><![CDATA[<p>I recently started working on migrating an old PHP based application to a new <em>sexy</em> Rails app. The old model was kind of messy, the usual case of bloated, <a href="https://en.wikipedia.org/wiki/Feature_creep">feature creep</a> app written by many people without any standard conventions.</p>
<p>Anyway, I have to migrate users and content from many sites using the legacy app.</p>
<h1 id="data-structure">Data Structure</h1>
<p>Instead of having 1 code base and 1 database per site, we now only have 1 code base and 1 database for all sites on a server.</p>
<p>The legacy application had a minimum of 3 databases:
1. installer database (keeps track of site version, manage upgrades, list sites on a server)
2. central server database (keeps all the sites details such as billing address, location, contacts, licenses… )
3. site database (contains users, content, settings)</p>
<p>Our new application, on the other hand, is as mentioned earlier, very <em>sexy</em> and has a nice Model. It is also developed following the <a href="https://behaviour-driven.org/">Behaviour-Driven Development</a> principles using <a href="https://rspec.rubyforge.org/">RSpec</a>. The best way for me to migrate the legacy data is probably to develop a Rails Plugin with a set of <a href="https://www.martinfowler.com/articles/rake.html#RakeTasks">Rake Tasks</a> that I could use to migrate my sites automatically.</p>
<p>I therefore decided to start working on my migration plugin… using BDD, with RSpec edge….</p>
<p>The first think I started thinking was: what should I test/spec? how am I access the pile of not organized content from the legacy sites? How am I connect nicely to each of the legacy sites?</p>
<h1 id="model-connection">Model Connection</h1>
<p>First question by order of priority: how could I leverage the legacy Model by using ActiveRecord?</p>
<p>I could create a Legacy Model for each table and connect each of them directly to the legacy database. Sounds ok but that means a lot of connections, and every time I would need to access another site, I would have to reconnect all my legacy classes… I was sure there was a better solution… and I was right. After googling for a solution, I noticed that <a href="https://pragdave.pragprog.com">Dave Thomas</a> had already found a <a href="https://pragdave.pragprog.com/pragdave/2006/01/sharing_externa.html">solution</a> few months earlier:</p>
<pre><code>&lt;code&gt;class LegacyBase &lt; ActiveRecord::Base
    establish_connection ...
  end

  class LegacyUser &lt; LegacyBase
     ...
  end

  class LegacyContent&lt; LegacyBase
    ...
  end
&lt;/code&gt;
</code></pre>
<p>And as Dave explains in his post:</p>
<blockquote>
</blockquote>
<blockquote>
<p>“It turns out that Rails does just about everything lazily. That includes connecting to databases and reflecting on tables to extract the schema (needed to build the internals of the models). This improves performance, but it also makes this hack possible. In general, youâ€™d expect the LegacyBase class to map to a database table called legacy_base. It would, if we ever tried to use it to access data. But because we donâ€™t, and because Rails only reflects on the table the first time a data access occurs, we can safely create an ActiveRecord class with no underlying database table. This scheme lets me specify the legacy connection once, and share that connection between all my legacy models. Itâ€™s tidy, expressive, and saves resources.”</p>
</blockquote>
<p>Great, I had a technical solution to nicely connect to a legacy database.</p>
<p><a href="https://www.railsontherun.com/2007/4/2/migrating-legacy-app-part-2">Go to Part 2</a></p>
]]></content>
		</item>
		
		<item>
			<title>rspec textmate bundle edge</title>
			<link>https://matt.aimonetti.net/posts/2007-03-rspec-textmate-bundle-edge/</link>
			<pubDate>Fri, 30 Mar 2007 00:00:00 +0000</pubDate>
			
			<guid>https://matt.aimonetti.net/posts/2007-03-rspec-textmate-bundle-edge/</guid>
			<description>UPDATE: Aslak Hellesoy just mentioned in a comment that the trunk version of RSpec bundle for TextMate ( svn://rubyforge.org/var/svn/rspec/trunk ) doesn&amp;rsquo;t require the RSpec Gem installed anymore.
To install the bundle:
&amp;lt;code&amp;gt; cd ~/Library/Application\ Support/TextMate/Bundles/ svn co svn://rubyforge.org/var/svn/rspec/branches/0.9-dev/RSpec.tmbundle &amp;lt;/code&amp;gt;   I recently discovered RSpec, well, not really, but I finally got to start using RSpec.
For those who don&amp;rsquo;t know RSpec , RSpec is a BDD testing framework, or in better words: RSpec is a Behaviour Definition Framework well suited for practicing Behaviour Driven Development (BDD) in Ruby.</description>
			<content type="html"><![CDATA[<h2 id="update">UPDATE:</h2>
<p><a href="https://blog.aslakhellesoy.com/"> Aslak Hellesoy</a> just mentioned in a comment that the trunk version of RSpec bundle for TextMate ( svn://rubyforge.org/var/svn/rspec/trunk ) doesn&rsquo;t require the RSpec Gem installed anymore.</p>
<p>To install the bundle:</p>
<pre><code>&lt;code&gt;
cd ~/Library/Application\ Support/TextMate/Bundles/
 svn co svn://rubyforge.org/var/svn/rspec/branches/0.9-dev/RSpec.tmbundle
&lt;/code&gt;
</code></pre>
<hr>
<p>I recently discovered RSpec, well, not really, but I finally got to start using
RSpec.</p>
<p>For those who don&rsquo;t know
<a href="https://rspec.rubyforge.org/">RSpec</a> ,
RSpec is a BDD testing framework, or in better words: RSpec is a Behaviour
Definition Framework well suited for practicing Behaviour Driven Development
(BDD) in Ruby.</p>
<p>If you don&rsquo;t know what is BDD, then just check out
<a href="https://behaviour-driven.org/">https://behaviour-driven.org/</a>, in few words, it&rsquo;s TDD (Test Driven Development in better)</p>
<p>Anyway, I&rsquo;m working on a Rails project where we use the trunk/edge version RSpec
plugin. I&rsquo;m using my favorite editor:
<a href="https://macromates.com/">TextMate</a>
and I noticed that the RSpec team created a
<a href="https://rspec.rubyforge.org/tools/extensions/editors/textmate.html">cool
bundle for textmate</a>.</p>
<p>I was quite excited until I tried running a spec and realized that the task
failed giving some errors about some missing methods&hellip; Well, the thing is we
replaced &ldquo;context &hellip; do&rdquo; by &ldquo;describe &hellip; do&rdquo; and &ldquo;specify &hellip; do&rdquo; by &ldquo;it &hellip;
do&rdquo; see
<a href="https://blog.davidchelimsky.net/articles/2007/03/11/describe-it-with-rspec">David&rsquo;s
post</a> about this specific change in trunk:</p>
<p>The Textmate bundle uses the ruby gem instead of the plugin and since I&rsquo;m trying
to use methods only defined in trunk the bundle simply dies on me every time I
try to run my specs.</p>
<p>The only solution for me was to run a trunk version of the RSpec gem, here is
what to do:</p>
<p>Check out RSpec trunk from:
svn://rubyforge.org/var/svn/rspec/trunk</p>
<p>Check out RSpec trunk into its own project, or
if you&rsquo;re interested in</p>
<p>using/learning RSpec for a particular Rails
project, consider using</p>
<p>svn:externals to check out RSpec trunk into your
[RailsRoot]/vendor</p>
<p>directory:</p>
<p>svn propset svn:externals &ldquo;rspec
svn://rubyforge.org/var/svn/rspec/trunk&rdquo;</p>
<p>vendor</p>
<p>then update to grab the latest code from RSpec
trunk:</p>
<p>svn update
vendor</p>
<p>Next, build the gem.  You have to be
standing in vendor/rspec if you&rsquo;re</p>
<p>using svn:externals (as described above) or the
root of RSpec if you checked</p>
<p>it out as its own
project.</p>
<p>rake gem</p>
<p>then install
it:</p>
<p>gem install pkg/rspec-X.X.X.gem (where X.X.X is
the version number reported</p>
<p>in the output from &ldquo;rake gem&rdquo;)</p>
<p>&mdash;- from
<a href="https://rubyforge.org/pipermail/rspec-users/2006-November/000135.html">https://rubyforge.org/pipermail/rspec-users/2006-November/000135.html</a></p>
<p>That&rsquo;s it, now I can run my specs directly from Textmate the same way I was
doing with Unit Test.</p>
<p>( on a different post I&rsquo;ll explain why I couldn&rsquo;t simply run rake:spec )</p>
]]></content>
		</item>
		
	</channel>
</rss>
