<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>CodeGoalie</title><link>https://codegoalie.com/</link><description>Recent content on CodeGoalie</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Tue, 30 Jun 2026 11:04:53 -0400</lastBuildDate><atom:link href="https://codegoalie.com/index.xml" rel="self" type="application/rss+xml"/><item><title>Welcome, Juniors!</title><link>https://codegoalie.com/posts/welcome-juniors/</link><pubDate>Tue, 30 Jun 2026 11:04:53 -0400</pubDate><guid>https://codegoalie.com/posts/welcome-juniors/</guid><description>&lt;p>I believe one of the reasons I&amp;rsquo;ve been pretty successful in adopting and utilizing Agents iny engineering work is relying on the decades of hard fought knowledge, experience, and taste. How do folks without that get it in this age of AI?&lt;/p>
&lt;p>It&amp;rsquo;s unacceptable for me to say &amp;ldquo;AI is only for seniors and above&amp;rdquo; or other nonsensical takes. Here&amp;rsquo;s what I&amp;rsquo;m currently thinking. And as with most everything &amp;ldquo;rethought&amp;rdquo; for the AI era, it&amp;rsquo;s the same as before.&lt;/p>
&lt;h2 id="appropriate-scope">Appropriate scope&lt;/h2>
&lt;p>It&amp;rsquo;s unreasonable to expect a junior dev to architect an entire new service, or even feature. Continue to provide appropriate work, but allow for AI to help with even those small tasks. Thorough planning helps even with a small bugfix. You can provide critical feedback to the agent on test case edge cases, etc. It&amp;rsquo;s training for the big stuff but at a smaller scale. The same as its always been.&lt;/p>
&lt;h2 id="apprenticeship">Apprenticeship&lt;/h2>
&lt;p>I read this recently and it really resonated with me. The concept is to have a junior and a senior work closely together for an extended period of time to learn first hand, day to day on how the senior operates.&lt;/p>
&lt;p>One reason I find this super compelling is that there are many things that I do throughout the day that I would never think to capture in a training or lunch &amp;lsquo;n learn. Probably a lot of them I don&amp;rsquo;t even know I do.&lt;/p>
&lt;p>Also, I love watching and learning from people more skilled and experienced.&lt;/p>
&lt;p>I&amp;rsquo;m not worrying too much about new people coming up missing some aspects of the job that I know. The good ones will learn what they need and ignore all the extraneous crap that I&amp;rsquo;m burdened with ;)&lt;/p>
&lt;p>Happy learning!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Agents for System Design</title><link>https://codegoalie.com/posts/agents-for-system-design/</link><pubDate>Sat, 18 Apr 2026 05:54:21 -0400</pubDate><guid>https://codegoalie.com/posts/agents-for-system-design/</guid><description>&lt;p>System Design used to be reserved for the senior folks. They&amp;rsquo;ll hand down a
document showcasing the new architecture or new service. Agents are making it so
everyone can do some system design because even the smallest features can
benefit from more intentional design.&lt;/p>
&lt;p>Over the past couple months, I&amp;rsquo;ve been tasked with leading a very large
cross-team project to essentially replace the core data model in our business.
This has involved designing new services, new and novel interactions between
services, and adding new capabilities to existing services. I&amp;rsquo;ve leaned heavily
on agents to help produce and communicate my intent to other people (and other
agents). Here is advice I&amp;rsquo;ve picked up along this journey.&lt;/p>
&lt;h2 id="know-what-you-want">Know what you want&lt;/h2>
&lt;p>This is a general principle for all if not close to all interactions with an
agent and LLM. It&amp;rsquo;s not a magic oracle, even if it genuinely feels like it
sometimes. It can&amp;rsquo;t read your mind. It doesn&amp;rsquo;t have the context of your company,
team, feature, past mistakes, etc. It wasn&amp;rsquo;t at the last all-hands meeting to
absorb some of that new initiative from the leadership team. It wasn&amp;rsquo;t a part of
that ad-hoc conversation last week where we got clarity on an upcoming API
interaction.&lt;/p>
&lt;p>It doesn&amp;rsquo;t need to know that. It shouldn&amp;rsquo;t know that. It&amp;rsquo;s your job to determine
what it should know, and in order to do that, you need to determine what you want
it to do first. Every time you open up your agent, you should know what you want
from it and when you&amp;rsquo;ll be able to exit it (ctrl+d ctrl+d).&lt;/p>
&lt;p>As a principal engineer at PrizePicks, a lot of my work is designing new
systems, adding new capabilities to existing systems, or integrating 2 systems
together. The first step that I take is to create a proposal doc. There is a lot
of formatting and process around this typically in companies. I ignore most of
that here. I want the agent to produce a document which describes at a high
level how this new thing is going to work.&lt;/p>
&lt;p>That last sentence is pretty much the functional part of my initial prompt. The key
here is know what you want before you start:&lt;/p>
&lt;ul>
&lt;li>A document defining something in a 3rd party system (Notion, Linear docs,
etc.)&lt;/li>
&lt;li>A series of steps for me to execute some task&lt;/li>
&lt;li>JSON for a grafana chart&lt;/li>
&lt;li>Mermaid diagram of this flow/architecture&lt;/li>
&lt;li>etc.&lt;/li>
&lt;/ul>
&lt;p>Have an end in mind before you start. Agents are a tool. Waving a shovel around
wildly in the air is not the best way to dig a hole.&lt;/p>
&lt;h2 id="provide-the-load-bearing-walls">Provide the load bearing walls&lt;/h2>
&lt;p>This is a recent insight that I realized I&amp;rsquo;d been doing naturally, but I
articulated it to a colleague recently and it actually inspired this whole post.
This 5-second version is that if you&amp;rsquo;re building a tent with the help of an
agent, you need to bring the tent poles. It can build the waterproof and
functional covering. It can put in a door with a 2 sided zipper. But if you
don&amp;rsquo;t bring the poles, it&amp;rsquo;ll just be a pile of fabric on the floor.&lt;/p>
&lt;p>Conversely, you don&amp;rsquo;t need to build the whole tent out. It knows what tents are
and how, generally, they work. It&amp;rsquo;s your job to, first, communicate that you&amp;rsquo;re
building a tent (these are general purpose models). And then articulate what
makes your tent yours.&lt;/p>
&lt;p>A good recipe for this is to start with what you have. Talk about what you need.
Then be explicit about what you want. A while back, I had an agent research the
Epcot Flower &amp;amp; Garden festival menus for this year, comparing first a markdown
file then &lt;a href="https://codegoalie.com/flower-2026.html">a static HTML file&lt;/a>. My wife
and I went through the menus and picked the items we wanted to be sure to try.
Now, I wanted to combine the two &amp;ndash; Well, wait. Here&amp;rsquo;s the exact prompt I used:&lt;/p>
&lt;pre>&lt;code>❯ I have a full overview of the 2026 Epcot Flower &amp;amp; Garden festival in the
2026.[md|html] files. I've gone through them and noted my favorites in
2026-notes.md. I'd like to come up with a useful and intuitive guide to use
while I'm in Epcot to make sure I don't miss these choices. We'll be going
around the world showcase in one order or another so put the booths in the same
order as the world showcase starting with Mexico. I also would love to be able
to hide stuff I've already tried.
&lt;/code>&lt;/pre>&lt;p>This was in plan mode in Claude Code so it generated a
&lt;a href="https://codegoalie.com/agents-for-system-design-plan-example.md">plan&lt;/a>.&lt;/p>
&lt;h2 id="meticulously-review">Meticulously review&lt;/h2>
&lt;p>Once you have a plan or document, it &lt;em>needs&lt;/em> your review. You&amp;rsquo;ve provided a few
sentences and it&amp;rsquo;s generated a whole document. This upscaling of information is
lossy, &lt;strong>by definition&lt;/strong>. In fact, each step of the way, you&amp;rsquo;re going from lower
specificity to higher specificity and review is necessary.&lt;/p>
&lt;p>The earlier steps need more review as they&amp;rsquo;re setting the stage for everything
afterwards. A small misalignment in the initial plan will cascade and amplify
into the final product.&lt;/p>
&lt;p>I once missed that a message topic needed to have a version bump. The agent used
&lt;code>v1&lt;/code> in the plan, but we actually wanted &lt;code>v2&lt;/code>. Even the copilot during code
review after I manually fixed the version numbers was complaining that &amp;ldquo;it
should be &lt;code>v1&lt;/code> here.&amp;rdquo; 😩&lt;/p>
&lt;p>This ties directly into the first point in this post. Know what you want
beforehand so that you can evaluate it when the agent produces the artifact.&lt;/p>
&lt;h2 id="cutthroat-revisions">Cutthroat revisions&lt;/h2>
&lt;p>Since each phase feeds directly into another increase in specificity, be
ruthless in your revisions earlier rather than later. I use the same working model as I
do for code reviews: if this isn&amp;rsquo;t what you would have done, say something. It
will only get worse from here. The models are very good at making things sound
plausible and correct. That&amp;rsquo;s exactly what they do, in fact. &amp;ldquo;The new
multiplication function can live in the addition package since they are both
math.&amp;rdquo; Nope. Maybe you want to rename that package to newmath, or put
multiplication in its own package. You need to make the call now and update the
plan. It&amp;rsquo;s a one sentence change in the plan, but from here on out it gets more
ingrained (maybe AGENTS.md updates to include something like &amp;ldquo;All math features
are implemented in the &lt;code>addition&lt;/code> package&amp;rdquo; 😱)&lt;/p>
&lt;p>Functionally, I like to have the agent make the changes usually in the same
conversation as the original plan was created. However, since you have an
artifact, you can start a new conversation if you want. That&amp;rsquo;s the beauty of
working with artifacts outside of the harness.&lt;/p>
&lt;hr>
&lt;p>I find the system design part of this new Agentic Engineering paradigm to be the
most interactive. Some days I like that. Other days I appreciate being able to
hit a button and get a PR (more on that later). But the PR button only works
when the plan is solid. I used to spend days hand-writing a technical design doc
and it was often just OK. With agents, I get really great docs in often less
than an hour of focused work after days of
&lt;a href="https://codegoalie.com/posts/2025-05-24-use-your-noodler">noodling&lt;/a>.&lt;/p>
&lt;p>Happy designing!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Agents Calm Down</title><link>https://codegoalie.com/posts/agents-calm-down/</link><pubDate>Mon, 30 Mar 2026 07:21:16 -0400</pubDate><guid>https://codegoalie.com/posts/agents-calm-down/</guid><description>&lt;p>Agentic coding harnesses are violating the unix philosophy and trying to become
the &lt;em>everything app&lt;/em> for coding (and work and personal assistant and so on).&lt;/p>
&lt;h2 id="why-not-build-everything">Why not build everything?&lt;/h2>
&lt;p>Many of the articles I&amp;rsquo;m reading are saying what we&amp;rsquo;ve been saying all along,
&amp;ldquo;writing the code hasn&amp;rsquo;t been the bottleneck.&amp;rdquo; No project was late because
engineers didn&amp;rsquo;t spend enough time sitting at their desks typing code. And now
that writing the code is approaching zero, I think it&amp;rsquo;s more important than ever
to carefully, methodically consider every project and initiative.&lt;/p>
&lt;blockquote>
&lt;p>&amp;ldquo;This feature is not a good fit for coding agents so we aren&amp;rsquo;t going to put
it into our harness.&amp;rdquo;&lt;/p>
&lt;ul>
&lt;li>No AI company ever&lt;/li>
&lt;/ul>
&lt;/blockquote>
&lt;p>Non-engineering folks have long enjoyed the luxury of engineering being the
bottleneck (not writing code, but review, deploy, integration, etc.) and have
been able to change requirements, goals and targets while we were working. When
we can take a set of requirements and later that afternoon be dev complete&amp;hellip;
Just think about what would have happened if we&amp;rsquo;d implemented verbatim some
of those first draft project proposals?&lt;/p>
&lt;p>I&amp;rsquo;m working on a personal project to upgrade my personal daily task list from a
plain markdown file to use &lt;a href="https://www.rememberthemilk.com/">Remember The Milk&lt;/a>
(the only task tracking app which gets recurring items right, but I digress). I
have a pretty decent idea of what I want. I&amp;rsquo;ve been working in this flow for
over 8 years after all. I&amp;rsquo;m, of course, having an agent write all the code. But
I&amp;rsquo;m going slow. I&amp;rsquo;m carefully considering each feature and more precisely how it
should work than I ever have &lt;em>ahead of time&lt;/em> before. I feel this great
responsibility to move intentionally &lt;strong>because&lt;/strong> I have this great power to push
a button, fold 5 pieces of clothes, turn back to my laptop and have a working
feature.&lt;/p>
&lt;p>To me, LLMs and agents and all of it, from the start, has never been about
getting faster. It&amp;rsquo;s about reducing the &amp;ldquo;manual&amp;rdquo; effort of willing a (software)
thing into existence. As I&amp;rsquo;ve been gaining experience with agents et al, I keep
coming back time and time again to the best practices of the industry: &amp;ldquo;have a
really good and detailed scope doc,&amp;rdquo; &amp;ldquo;compare that to the code and form a
focused implementation plan,&amp;rdquo; &amp;ldquo;break that down into units of work that depend on
each other or can be done in parallel.&amp;rdquo; We always wanted that but it was too
time consuming to do and we relied on each other&amp;rsquo;s existing context. Many
tickets don&amp;rsquo;t have any body description. We just talked about the project scope
in the kick off, but didn&amp;rsquo;t formalize a document. Ironically, the machine is
forcing (and enabling) us to do the things that would have been best all along,
even for humans.&lt;/p>
&lt;h2 id="do-one-thing-well">Do one thing well&lt;/h2>
&lt;p>Time and again the best software is focused and does one thing really well.
That&amp;rsquo;s the unix philosophy. Composability over batteries included. Make a simple
and powerful tool to let those using it combine it with other simple and
powerful tools to make something greater than the sum of the tools themselves.&lt;/p>
&lt;p>These new releases in the agent harnesses are hard to reason about because
many of the new features feel half-baked and not rooted in solving a real
problem. I end up feeling obligated to find use for them. It&amp;rsquo;s FOMO a bit.
&amp;ldquo;Well, if they implemented it and released it, it must be something good. I must
be missing something if I can&amp;rsquo;t find the use case.&amp;rdquo;&lt;/p>
&lt;p>It&amp;rsquo;s hard to face this down. The company worth tens of billions of dollars is
churning out features on the most talked about software of the moment and my gut
is telling me to ignore most of it. I got bored and frustrated really quickly
babysitting the agent. &amp;ldquo;Yes&amp;rdquo; &amp;ldquo;Approve&amp;rdquo; over and over. Same prompt. Same slash
command. Same skill. Tweak it a bit here and there. Now, I&amp;rsquo;m automating it and
running into some longing for more focus on a simple tool that I can work &lt;em>with&lt;/em>
not indefinitely inside of.&lt;/p>
&lt;h2 id="do-less">Do less&lt;/h2>
&lt;p>I don&amp;rsquo;t want to leave on a down note so let&amp;rsquo;s talk solutions. Do less. Make
more. Let&amp;rsquo;s build an ecosystem around this tool. Let&amp;rsquo;s solve the rest of the
SDLC competently. LLMs are a versatile technology and are made even more
powerful with agent harnesses. They aren&amp;rsquo;t a silver bullet either. I love that
we&amp;rsquo;re pushing the envelope of what can these things do. I love that we don&amp;rsquo;t
know yet. It&amp;rsquo;s exciting to be a part of.&lt;/p>
&lt;p>The more I work with agents the more I see how important the &amp;ldquo;old&amp;rdquo; best
practices are. The more pre-planning matters. The more detailed specs matter.
The more nailing down inter-service interacations matter. Start at the
boundaries and work inward on both sides. Hand offs. Metrics. Automated
end-to-end testing. There&amp;rsquo;s nothing new here. It&amp;rsquo;s just compressed and
accelerated; and can be exhausting at times. In this age where we can build
anything, the taste and discipline to not build something matters. I&amp;rsquo;d love to
see that in the tools themselves.&lt;/p>
&lt;p>Happy shipping!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Use Your Noodler</title><link>https://codegoalie.com/posts/2025-05-24-use-your-noodler/</link><pubDate>Sat, 24 May 2025 06:52:56 -0400</pubDate><guid>https://codegoalie.com/posts/2025-05-24-use-your-noodler/</guid><description>&lt;p>A former coworker of mine over 8 years ago put this image into my head that has
never left. He was working as my manager at the time and he had an upcoming
large, foundational shifting feature that he wanted to let me know was coming. He
said &amp;ldquo;Don&amp;rsquo;t do anything right now, but just put this in your noodler and see
what comes out.&amp;rdquo;&lt;/p>
&lt;p>He went on to explain that a former boss of &lt;em>his&lt;/em> introduced the idea of the
noodler to him. Now, I&amp;rsquo;m not your boss (I can confidently say that because I&amp;rsquo;m
no ones boss as of this writing ;) ), but I&amp;rsquo;d still like to share this image
with you that&amp;rsquo;s helped me so much and I&amp;rsquo;ve never been able to shake.&lt;/p>
&lt;p>If you haven&amp;rsquo;t guessed by now, the noodler is the back part of your brain. Back
near the subconscious, it&amp;rsquo;s like a rock tumbler. It&amp;rsquo;s always spinning and
tumbling ideas without conscious effort. You just throw raw stuff into it and
in a few days or so, see what pops out. Sometimes it&amp;rsquo;s just a smoother rock and
sometimes it&amp;rsquo;s a true gem.&lt;/p>
&lt;p>I like this metaphor for a few reasons. First, it&amp;rsquo;s a pretty vivid, concrete
concept. I always imagine that red, kid&amp;rsquo;s science kit version of a rock tumbler
that I always wanted. Now I have one and it&amp;rsquo;s turning half-baked, super
hazy concepts into novel, actionable ideas.&lt;/p>
&lt;p>Second, it&amp;rsquo;s an escape hatch. Do this one easy thing, make progress, done for
the day. Take something off your plate. You can rest easier knowing that
something, somewhere is happening, but you don&amp;rsquo;t need to spend active energy on
it, right now. Wash the dishes and think about the birds outside. Mow the lawn
and listen to that podcast. It&amp;rsquo;s OK. Some other part of you has got this.&lt;/p>
&lt;p>Lastly, it works. Not all the time. But more often than not, something comes to
me and I can make a small step, or a bigger leap. And if it doesn&amp;rsquo;t, typically,
I&amp;rsquo;m no worse off.&lt;/p>
&lt;p>Happy noodling!!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>golibnotify 0.2.0 released!</title><link>https://codegoalie.com/posts/golibnotify-0-2-0/</link><pubDate>Mon, 22 Jul 2024 05:18:09 -0400</pubDate><guid>https://codegoalie.com/posts/golibnotify-0-2-0/</guid><description>&lt;p>&lt;a href="https://github.com/codegoalie/golibnotify">&lt;code>golibnotify&lt;/code>&lt;/a> is
a Go library for sending desktop notifications on Linux. It is
a wrapper around the &lt;code>libnotify&lt;/code> library.&lt;/p>
&lt;p>There are some memory leak fixes in the latest release, &lt;code>v0.2.0&lt;/code>.&lt;/p>
&lt;p>Big thank you to &lt;a href="https://github.com/omhaal">Stefan van den Akker (@omhaal)&lt;/a>
for fixing some unfreed memory in the &lt;code>SimpleNotifier&lt;/code>. I&amp;rsquo;m not a c or cGo export
so I really appreciate it!&lt;/p>
&lt;p>Be sure to update your go.mod files to &lt;code>v0.2.0&lt;/code> and let me know if you run into
any other bugs or issues!&lt;/p>
&lt;p>Happy notifying!&lt;/p></description></item><item><title>Format JSON in Nvim with jq</title><link>https://codegoalie.com/posts/format-json-nvim-jq/</link><pubDate>Mon, 12 Feb 2024 16:09:11 -0500</pubDate><guid>https://codegoalie.com/posts/format-json-nvim-jq/</guid><description>&lt;p>I often get large JSON files which contain no newlines or indentation. I&amp;rsquo;d like
to look at these reasonably in neovim, but it&amp;rsquo;s been cumbersome until today.&lt;/p>
&lt;p>TL;DR: You can replace the contents of the buffer with output formatted by jq
with one command: &lt;code>:%!jq .&lt;/code>&lt;/p>
&lt;p>Other techniques I&amp;rsquo;ve used, from worse to lest worse:&lt;/p>
&lt;ol>
&lt;li>Replacing every &lt;code>,&lt;/code> with &lt;code>,\r&lt;/code> and then using &lt;code>=&lt;/code> to auto-indent the lines.
This rarely works well.&lt;/li>
&lt;li>Using &lt;code>jq&lt;/code> externally. &lt;code>cat input.json | jq . &amp;gt; output.json&lt;/code>. This kind of
sucks because you now have 2 files&amp;hellip;&lt;/li>
&lt;/ol>
&lt;p>Now, you can open the file in neovim and type &lt;code>:%!jq .&lt;/code>. Magically, the buffer
will be nicely formatted.&lt;/p>
&lt;p>Roughly, this is entering a command, &lt;code>:&lt;/code>, on the whole buffer, &lt;code>%&lt;/code>, then
executing a shell command, &lt;code>!&lt;/code>, of &lt;code>jq .&lt;/code> the most basic &lt;code>jq&lt;/code> invocation.
Presumably, you could entry and &lt;code>jq&lt;/code> filter command to form some other JSON
instead of just formatting the given JSON, but I&amp;rsquo;ll leave that up to you to play
with.&lt;/p>
&lt;p>Happy formatting!!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>AI and I, or You're Holding That Wrong</title><link>https://codegoalie.com/posts/ai-and-i/</link><pubDate>Mon, 15 May 2023 19:59:01 -0400</pubDate><guid>https://codegoalie.com/posts/ai-and-i/</guid><description>&lt;p>How can a tool that is indescernably wrong be anything more than a toy?&lt;/p>
&lt;p>You&amp;rsquo;re holding that wrong. A month or so ago, I would have been the first to
laugh you off if you started talking to me about &lt;a href="1">ChatGPT&lt;/a> being an
experience like the first time you programmed or &amp;ldquo;saw the internet.&amp;rdquo; It can&amp;rsquo;t
even answer basic questions like those I ask my smart speaker everyday? (That&amp;rsquo;s
hyperbole. I don&amp;rsquo;t speak to me smart speaker nearly everyday.) Also, it lies to
you; like to your face lies to you. What even is this? A fancy &lt;a href="2">Markov chain&lt;/a>?&lt;/p>
&lt;p>Well, yes, actually it is. Then I heard &lt;a href="3">Simon Willison&lt;/a> on &lt;a href="4">The
Changelog&lt;/a> and I finally got the mental model.&lt;/p>
&lt;blockquote>
&lt;p>A calculator for words&lt;/p>
&lt;/blockquote>
&lt;p>&amp;ndash; &lt;a href="5">Simon Willison&lt;/a>&lt;/p>
&lt;p>What makes these seem so terrible at first glance is the interface. Imagine if a
calculator has a single text prompt as an interface. No buttons. &amp;ldquo;Tell me the
calculation you desire.&amp;rdquo; OK, so you as it to do your taxes. Unquestionably, a
calculator can&amp;rsquo;t do that. But if that&amp;rsquo;s your expectation, you&amp;rsquo;re terribly
disappointed and go back to carrying the one with paper and pencil.&lt;/p>
&lt;p>A calculator does not know your intentions or your context. It can&amp;rsquo;t answer even
slightly complex questions. But, if you know how to wield it, it&amp;rsquo;s incredibly
useful. It can &lt;strong>help&lt;/strong> you do your taxes and in record time*. In fact, all the
accountants that never learned to use a calculator are unemployed; replaced by
those that did.&lt;/p>
&lt;p>These new LLMs are terribly persuasive. We&amp;rsquo;ve become used to a person being at
the other end of written words. Text messages, emails, social media posts, news
articles. A vast majority of the content we consume is written words. We&amp;rsquo;ve been
conditioned to assume there&amp;rsquo;s a person at the other end. LLMs flip that
assumption on its head. Despite stringing together the words to be quite
convincing to the contrary, it has no feeling. It fact, it doesn&amp;rsquo;t even know
what it&amp;rsquo;s saying.&lt;/p>
&lt;p>Briefly, (if you already know technical details about LLMs, save yourself
from getting mad at me and skip this paragraph) LLMs are a next word/paragraph
predictor. Give some input words or sentences, it can guess, statistically which
word or sentence should come next. There&amp;rsquo;s also randomness built in so you don&amp;rsquo;t
get the same output twice. That&amp;rsquo;s it. It&amp;rsquo;s funny only because most text is also
funny in that context. It&amp;rsquo;s bad at facts because you can&amp;rsquo;t give random answers
&lt;em>and&lt;/em> be correct all the time.&lt;/p>
&lt;p>So, it can&amp;rsquo;t be right and it doesn&amp;rsquo;t know what it&amp;rsquo;s saying. How do I think about
this? What is it good at? LLMs are really good at creating a bunch of useful
words. They aren&amp;rsquo;t great out of the box. You can&amp;rsquo;t copy/paste straight from
ChatGPT into your homework and call it a day. But it can give you a list of
terrible ideas for something with a few gems sprinkled in. It can generate a
first draft for you.&lt;/p>
&lt;h1 id="how-to-think-about-all-this">How to think about all this?&lt;/h1>
&lt;p>First, it&amp;rsquo;s not the be all, end all. It&amp;rsquo;s not a silver bullet. But, it can help.
It&amp;rsquo;s a starting point. It&amp;rsquo;s a some, or most, of the way there. It&amp;rsquo;s an intern or
beginner needing correction. It saves keystrokes. It&amp;rsquo;s a first draft. It won&amp;rsquo;t
replace you. Someone who uses it will.&lt;/p>
&lt;h1 id="how-i-have-used-it-to-date">How I have used it to date?&lt;/h1>
&lt;p>I&amp;rsquo;m just scratching the surface on all of this and things are moving at an
extremely fast pace. I don&amp;rsquo;t claim to be an expert but here are some examples of
ways that I&amp;rsquo;ve found LLMs useful.&lt;/p>
&lt;p>First and most significantly, &lt;a href="6">Github Copilot&lt;/a>. If you take nothing away from this post,
start using Copilot (or one of the open-source alternatives) today. Get it
integrated into your editor. The neovim integration is particularly slick. When
you pause typing, some low-lighted text will appear after your cursor. It is
suggested code from Copilot. It&amp;rsquo;s especially good at handling errors or filling
small utility functions, and filling in function arguments. By accepting the
suggestion, you can save a ton of time and frustration from typos. However, it&amp;rsquo;s
not always syntactically or logically correct. &lt;strong>You must double check its
work.&lt;/strong> But even so, it&amp;rsquo;s a game changer for me, constantly, all day long.&lt;/p>
&lt;p>Next, generating ideas. But (another gem from Simon) is to ask for tens of
ideas; like 30 - 40. Most will be useless, but there will be a few gems in there.
OR, more likely there will be a few that spur an actual good idea.&lt;/p>
&lt;p>Then, I&amp;rsquo;ve used LLMs to help draft technical prompts. It&amp;rsquo;s writing that I don&amp;rsquo;t
really need to be personal or &amp;ldquo;in my voice.&amp;rdquo; I really just needed some test. In
fact, the LLM added some context and details that I wouldn&amp;rsquo;t have thought to
add.&lt;/p>
&lt;p>Help wriring small scripts or programs; especially using an API or package I&amp;rsquo;m
not familiar with or use that often. The other day, I needed to read a CSV file,
use it to fetch some related data, generate some SQL queries and write them to
a different file. I don&amp;rsquo;t work with files day to day nor CSV, but I could
quickly get a scaffold back from the LLM and fill in the actual &amp;ldquo;business logic&amp;rdquo;
bits.&lt;/p>
&lt;p>How have you been using LLMs?&lt;/p>
&lt;p>One last note, I didn&amp;rsquo;t use any help with this post. :)&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p>
&lt;ul>
&lt;li>when compared to those not using a calculator&lt;/li>
&lt;/ul></description></item><item><title>One-liner to copy a Github PR link from the terminal</title><link>https://codegoalie.com/posts/copy-pr-link/</link><pubDate>Wed, 04 Jan 2023 14:35:12 -0500</pubDate><guid>https://codegoalie.com/posts/copy-pr-link/</guid><description>&lt;p>Here&amp;rsquo;s a super quick one-liner to copy the current branch&amp;rsquo;s PR URL to your
clipboard (for posting into Slack, tickets, etc.)&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-bash" data-lang="bash">$ gh pr view --json url --jq .url | &amp;lt;pbcopy | xclip -sel c&amp;gt;
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Remember to replace the copy command with your platform&amp;rsquo;s specific command.&lt;/p>
&lt;p>This would also make a good shell alias.&lt;/p>
&lt;p>Also, also, I might try setting up &lt;a href="https://github.com/Slackadays/Clipboard">Clipboard&lt;/a> for multi-platform goodness.&lt;/p>
&lt;p>Happy PR-ing!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Web Scraping 2.0</title><link>https://codegoalie.com/posts/web-scraping-two-dot-oh/</link><pubDate>Wed, 23 Jun 2021 06:21:51 -0400</pubDate><guid>https://codegoalie.com/posts/web-scraping-two-dot-oh/</guid><description>&lt;p>With the wide adoption of robust front-end frameworks and CSS-in-JS,
traditional methods of targeting xpath or CSS selectors for scraping data from
web pages are becoming ineffective. However, this new paradigm of front-end
development leaves a key opportunity to improve the web scraping experience.&lt;/p>
&lt;p>Having data that&amp;rsquo;s not readily available in an API is something that I&amp;rsquo;ve kind
of become obsessed with over the past year or so. Even with access to
&lt;a href="https://github.com/awesomedata/awesome-public-datasets">public&lt;/a>
&lt;a href="https://github.com/dolthub/dolt">datasets&lt;/a> becoming more and more prevalant, I
still wanted access to data from websites or companies that I use but have no
interest in separating their data from their platform. So, how do you scrape a
React or Angular or other front-end framework app/site? While scraping the data
from the HTML may not be feasible or break constantly, you can use their API.
The same API the front-end uses. However, often these private APIs are resistant
to general use through opaque authentication and authorization mechanisms which
make them more work than it&amp;rsquo;s worth to try and write a traditional API client.&lt;/p>
&lt;h2 id="why-not-both">Why not both?&lt;/h2>
&lt;p>Instead of an either/or approach, a hybrid approach can be used by leveraging
browser automation &lt;em>and&lt;/em> API requests to quickly and reliably get the data we
need. Specifically, executing JS &lt;code>fetch&lt;/code> requests using browser automation tools
(almost all allow arbitrary JS execution in the current &amp;ldquo;page&amp;rdquo;). Parse this
request back into the native automation language (typically JSON string returned
from JS). Bam! You have a pseudo API!&lt;/p>
&lt;p>I&amp;rsquo;ve been very successful in pulling large amounts of data from an actively
scraper resistant environment using this approach. One of the really nice things
is that authentication/authorization for the private API requests is handled
virtually automatically by the browser through cookies.&lt;/p>
&lt;p>Here&amp;rsquo;s a rough outline of the entire process:&lt;/p>
&lt;ol>
&lt;li>Manually go through the web application performing the actions intended to be
automated while watching the network dev tools tab.&lt;/li>
&lt;li>Note any requests of interest.&lt;/li>
&lt;li>Generalize those requests and reverse engineer a subset of the API.&lt;/li>
&lt;li>Begin automation.&lt;/li>
&lt;li>Automate authentication, if necessary (Type creds into login form).&lt;/li>
&lt;li>Evaluate JS on the page to execute the AJAX/XHR/private API requests.&lt;/li>
&lt;li>Parse the returned string into datatypes in your native automation language.&lt;/li>
&lt;li>???&lt;/li>
&lt;li>Profit!!?&lt;/li>
&lt;/ol>
&lt;p>My intuition leads me to believe there are some common patterns here which may
be surfaceable in a library, but my experience isn&amp;rsquo;t quite to the point where I
feel confident providing the right abstractions. But, stay tuned and we&amp;rsquo;ll see
how this idea unfolds.&lt;/p>
&lt;p>Let me know how your experience scraping data from JS heavy web apps goes! I&amp;rsquo;d
love to know if this works for you or if this ends up being more hassle than
it&amp;rsquo;s worth.&lt;/p>
&lt;p>Happy scraping!&lt;/p></description></item><item><title>Magic PR Journeys</title><link>https://codegoalie.com/posts/magic-pr-journeys/</link><pubDate>Mon, 22 Mar 2021 06:45:22 -0400</pubDate><guid>https://codegoalie.com/posts/magic-pr-journeys/</guid><description>&lt;p>I was recently having a conversation about Pull Request reviews with a colleague
of mine and I mentioned that when I&amp;rsquo;m ready to look at code for a PR, I review
one commit at a time in order. After a confused pause, she asked how I could
get the full context by only looking at one commit at a time. I supposed to her
that perhaps the full context is not what facilitates a better review. Instead,
we should follow the journey the developer who opened the PR has set out for us
through their commits.&lt;/p>
&lt;p>I have many more thoughts on this subject, but I&amp;rsquo;d like to hear yours too. Email
me at &lt;a href="mailto:chris@codegoalie.com">chris@codegoalie.com&lt;/a> and let me know what you think about the above
supposition. Possible? Nonsensical? Outright dumb? :)&lt;/p>
&lt;p>Here&amp;rsquo;s to your next magical PR journey!&lt;/p>
&lt;p>— Chris&lt;/p></description></item><item><title>Commit Before Code</title><link>https://codegoalie.com/posts/commit-before-code/</link><pubDate>Fri, 26 Jun 2020 06:43:29 -0400</pubDate><guid>https://codegoalie.com/posts/commit-before-code/</guid><description>&lt;p>I propose a case for writing all of your commit messages for a feature, bug,
pull request &lt;em>before&lt;/em> writing a single line of code and afterward not adding
any additional commits to your branch. Plan and execute. Give clarity and focus
to your reviewers. Here&amp;rsquo;s how.&lt;/p>
&lt;p>This is an idea that&amp;rsquo;s been floating around in my head for a while now:
pre-planning commits in your branches. In fact, I checked my older posts
because I thought there might be a pretty good chance I had written this post
already. There wasn&amp;rsquo;t. So, here it is.&lt;/p>
&lt;h2 id="what-am-i-talking-about">What am I talking about?&lt;/h2>
&lt;p>Making all your commits to complete your task &lt;em>before&lt;/em> you begin coding.
Literally using &lt;code>--allow-empty&lt;/code> to outline all the tasks your branch needs to
do before you write one line of code. Every commit after that of code changes
are all &lt;code>fixup&lt;/code> commits to one of the original commits. No new commits allowed.&lt;/p>
&lt;h2 id="why-would-anyone-do-that">Why would anyone do that?&lt;/h2>
&lt;p>I find the exercise of planning my attack in the form of concrete commits
beneficial for &lt;strong>clarity&lt;/strong> and &lt;strong>focus&lt;/strong>.&lt;/p>
&lt;p>First, I can think abstractly about the work to be done. I don&amp;rsquo;t know which
lines of code will change or even what they will change into, but rather, I can
focus solely on what those changes need to achieve.&lt;/p>
&lt;p>I can think at a much higher level and coordinate the expected changes together
without getting bogged down by the intricacies or specific implementation
details. I don&amp;rsquo;t need to think about error handling, variable naming, design
patterns, code smells, testability, etc. (unless any of those are core to the
rationale of the branch). It&amp;rsquo;s almost a pure-er way of processing the task at
hand. I focus only on what are the smallest set of steps to reach the goal.&lt;/p>
&lt;p>Secondly, and often more importantly, I force myself to remain focused on the
task at hand. If I make a change that doesn&amp;rsquo;t fit into any of the predetermined
commits, there&amp;rsquo;s a very good chance that the change doesn&amp;rsquo;t belong in this
branch and should be made elsewhere.&lt;/p>
&lt;p>Most often these are housekeeping tasks; small improvements to the code that I
happen to notice while doing something unrelated. Sometimes these are areas
that don&amp;rsquo;t adhere to newly adopted best practices. Or, improvements in
readability. These aren&amp;rsquo;t things that are critical, but help keep code quality
up over time. I&amp;rsquo;ll get into what to do with these kinds of changes later.&lt;/p>
&lt;h2 id="ok-but-how-can-i-do-this">Ok, but how can I do this?&lt;/h2>
&lt;p>Let&amp;rsquo;s take an example and build out our branch of empty commits. Imagine we&amp;rsquo;re
working on an app to track vacations. We have an entity that holds our check-in
and check-out dates. What we want now is to display the number of days and
nights of the stay. For example, a stay from July 14th to 20th is 7 days/6
nights.&lt;/p>
&lt;p>One thing to notice about this new feature is that the numbers are always one
off from each other. We can calculate one and then derive the other.&lt;/p>
&lt;p>I like to write my tests first (in one commit) and then get them to pass in
another. I&amp;rsquo;ll also prefix my test-only commits with &amp;ldquo;Ensure&amp;rdquo;. Using this
pattern, I&amp;rsquo;d want to write test for and then implement the number of days
calculation. Then test and implement displaying to users. Here&amp;rsquo;s the commands to
acheive this:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-sh" data-lang="sh">$ git commit --allow-empty -m &lt;span style="color:#e6db74">&amp;#34;Ensure amount of days can be calculated from trips&amp;#34;&lt;/span>
$ git commit --allow-empty -m &lt;span style="color:#e6db74">&amp;#34;Calculate amount of days from trips&amp;#34;&lt;/span>
$ git commit --allow-empty -m &lt;span style="color:#e6db74">&amp;#34;Ensure users can see days/nights for a trip&amp;#34;&lt;/span>
$ git commit --allow-empty -m &lt;span style="color:#e6db74">&amp;#34;Display days/nights for trips&amp;#34;&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then after writing the tests for the calculation, I would create a &lt;code>fixup&lt;/code>
commit to &lt;a href="https://codegoalie.com/2013/04/04/better-pull-requests-with-git-autosquash">autosquash&lt;/a> into the first commit from above:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-sh" data-lang="sh">$ git commit --fixup HEAD~~~ &lt;span style="color:#75715e"># using a relative commit reference&lt;/span>
&lt;span style="color:#75715e"># or with the sha1 (prefix)&lt;/span>
$ git commit --fixup 06aa143
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Learn more about &lt;a href="https://codegoalie.com/2016/04/06/git-references">git references&lt;/a>.&lt;/p>
&lt;p>When all is said and done (or even before that), you can have git clean things
up for you with:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-sh" data-lang="sh">$ git rebase master --autosquash
&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="what-about-those-small-unrelated-changes">What about those small, unrelated changes?&lt;/h2>
&lt;p>These are changes I, personally, love to make. I believe this is where the
rubber meets the road in software as a craft. The holy trail of the huge
rewrite is often so tempting, but if you can&amp;rsquo;t put new learnings or best
practices into existing code then how can you think that you&amp;rsquo;ll be able to do
it in a brand new system. If you can prove that you are a good enough developer
to make the existing system its best, then you know you are ready to tackle a
rewrite. However, you also won&amp;rsquo;t need to. ;)&lt;/p>
&lt;p>So, what could be the harm of slipping in some minor improvements with your other
work? I&amp;rsquo;m already in here. Let&amp;rsquo;s just fix it really quick. Well, this will get
you into trouble in at least 2 ways.&lt;/p>
&lt;p>First, if the rest of your branch becomes obsolete or a better solution
arrives before you merge, the codebase doesn&amp;rsquo;t get to benefit from your
unmerged, unrelated change. Or worse still, if your merged branch needs to be
reverted, you will also be reverting your unrelated change.&lt;/p>
&lt;p>Secondly, it has a very real chance to hold up your PR during review. There&amp;rsquo;s
no better way to almost guarantee a flame war than think you can squeeze in
a small, quick change. &amp;ldquo;Why is this fix here?&amp;rdquo; &amp;ldquo;If you&amp;rsquo;re fixing this, why
didn&amp;rsquo;t you fix that?&amp;rdquo; &amp;ldquo;You should fix it in this way instead.&amp;rdquo;, etc. Your
2 second &amp;ldquo;improvement&amp;rdquo; will undoubedly attract comments and suggestions like
moths to a flame. The &lt;strong>actual&lt;/strong> point of the PR will be fine, but you&amp;rsquo;ll get
stuck going around and around on your small addiiton.&lt;/p>
&lt;h2 id="if-you-cant-make-these-changes-in-your-current-branch-where-do-they-go">If you can&amp;rsquo;t make these changes in your current branch, where do they go?&lt;/h2>
&lt;p>&lt;strong>TL;DR&lt;/strong> Move them into another branch and open a separate PR.&lt;/p>
&lt;p>There are 2 ways to do this. One uses the stash and one uses commits and cherry
picking. I&amp;rsquo;ll start with stash.&lt;/p>
&lt;p>Use the &lt;a href="https://git-scm.com/docs/git-stash">git-stash&lt;/a> to move changes across branches. The stash is a temporary
holding place for uncommitted changes. You can stash these changes on one branch
and apply them to another. I&amp;rsquo;ll assume you&amp;rsquo;ve committed all changes with fixups
and want to move all uncommitted changes to another branch.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-sh" data-lang="sh">$ git stash save
$ git checkout master
$ git checkout -b a-good-name-for-changes
$ git stash pop
$ git add .
$ git commit
$ git push
&lt;/code>&lt;/pre>&lt;/div>&lt;p>I always prefer &lt;code>git stash pop&lt;/code> to &lt;code>git stash apply&lt;/code> because the former removes
the stash entry when applying it and keeps your stash clean. Once it&amp;rsquo;s applied
and committed, you no longer need that stash and there&amp;rsquo;s no sense in keeping it
around.&lt;/p>
&lt;p>Now, for the second way. This way is a little less dangerous since you always
have your changes committed, but maybe only by a hair. Here you&amp;rsquo;ll commit to
your working branch. Then create a new branch and cherry pick that commit into
the new branch. This technique also works will if your &amp;ldquo;small&amp;rdquo; fix has multiple
commits.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-sh" data-lang="sh">$ git commit
&lt;span style="color:#f92672">[&lt;/span>commit-before-code e4fe22f&lt;span style="color:#f92672">]&lt;/span> Prefer single quoted strings
&lt;span style="color:#ae81ff">1&lt;/span> file changed, &lt;span style="color:#ae81ff">3&lt;/span> insertions&lt;span style="color:#f92672">(&lt;/span>+&lt;span style="color:#f92672">)&lt;/span>, &lt;span style="color:#ae81ff">3&lt;/span> deletions&lt;span style="color:#f92672">(&lt;/span>-&lt;span style="color:#f92672">)&lt;/span>
$ git checkout master
$ git checkout -b string-style-fixes
$ git cherry-pick e4fe22f
$ git push
&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>ProTip: &lt;code>cherry-pick&lt;/code> takes any git commit reference. Utilize the branch name
to cherry pick the tip of that branch into your current branch.&lt;/p>
&lt;/blockquote>
&lt;p>The really cool thing about this method is that if your fix branch gets merged
before your feature branch, you can simply rebase on master (which you should be
doing anyway) and git will detect the duplicate changes and automatically remove
the cherry picked commit.&lt;/p>
&lt;hr>
&lt;p>Next time you are starting to work on a new branch, give this method a try and
see if it helps keep you clear on your objective and focused on nailing it.&lt;/p>
&lt;p>Let me know how it works out for you.&lt;/p>
&lt;p>Happy committing!&lt;/p>
&lt;p>— Chris&lt;/p></description></item><item><title>Cleaning Up Docker Images</title><link>https://codegoalie.com/posts/cleaning-up-docker-images/</link><pubDate>Mon, 30 Dec 2019 16:13:36 -0500</pubDate><guid>https://codegoalie.com/posts/cleaning-up-docker-images/</guid><description>&lt;p>After a while of using docker locally for development, you may notice that you
have a lot of images and containers laying around on your disk that you no
longer use. This post shows you an effective way to clean up 50 of GB or more
of disk space.&lt;/p>
&lt;p>The first, best thing to do is clean up dangling images. These are docker images
that are not referenced by a container. These can be orphaned when containers are
removed or intermediate steps that don&amp;rsquo;t get cleaned up. One quick command can
remove them:&lt;/p>
&lt;pre>&lt;code>$ docker image prune
&lt;/code>&lt;/pre>&lt;p>Typically, if you&amp;rsquo;ve been using docker for a while, this will clear up quite a bit
of space. But, there&amp;rsquo;s more we can do.&lt;/p>
&lt;p>The next step you might think to do is remove other images that you know you don&amp;rsquo;t use.
We can list them with the &lt;code>docker images&lt;/code> command. However, you won&amp;rsquo;t be able
to delete them directly because they are being referenced by containers (otherwise
they would have been removed by the prune command). So, let&amp;rsquo;s look at containers:&lt;/p>
&lt;pre>&lt;code>$ docker ps -a
&lt;/code>&lt;/pre>&lt;blockquote>
&lt;p>Note: the &lt;code>a&lt;/code> flag shows all containers not just those running. You probably
don&amp;rsquo;t want to remove a container that&amp;rsquo;s currently running anyway.&lt;/p>
&lt;/blockquote>
&lt;p>Wow. That&amp;rsquo;s a long list. Way down at the bottom I noticed some old and temporary
projects and experiments. Here&amp;rsquo;s an example of some less notables from my list:&lt;/p>
&lt;pre>&lt;code>68585b76a752 46d00b64e6cb &amp;quot;/bin/sh -c yarn&amp;quot; 13 months ago Exited (1) 13 months ago upbeat_tesla
3cb298f62318 3bc06921fcd0 &amp;quot;/bin/sh -c yarn&amp;quot; 14 months ago Exited (1) 14 months ago charming_benz
31e91aaa9111 3bc06921fcd0 &amp;quot;/bin/sh -c yarn&amp;quot; 14 months ago Exited (1) 14 months ago upbeat_lovelace
79428b687b22 6533ab88e0ff &amp;quot;basj&amp;quot; 16 months ago Created welcomely_web_run_75
&lt;/code>&lt;/pre>&lt;p>Ok, so now copy and paste the container ID (first column) for each one you&amp;hellip; J/K.&lt;/p>
&lt;p>I also noticed that this output has the created time in the fourth column. This
is helpful, but not particularly useful. I do have some long running projects
and would prefer not to simply remove containers that I&amp;rsquo;ve created long ago.&lt;/p>
&lt;p>However, the very next column shows the last time the container was executed. I
would like to remove containers that I haven&amp;rsquo;t run in a while. We can grep for
rows of the output which exited many months ago:&lt;/p>
&lt;pre>&lt;code> $ docker ps -a | grep -E &amp;quot;Exited \([0-9]{1,3}\) 2[0-3] months ago&amp;quot;
&lt;/code>&lt;/pre>&lt;p>This looks scary. But, I promise I actually wrote this by hand and it&amp;rsquo;s pretty
simple. If I&amp;rsquo;m being honest, it&amp;rsquo;s probably too simple, but it worked for my case.&lt;/p>
&lt;p>First, we use the &lt;code>E&lt;/code> flag to enable the regex engine. Then we want to match rows
with the string like &amp;ldquo;Existed (&lt;!-- raw HTML omitted -->) &amp;lt;some number more than 20&amp;gt; months
ago&amp;rdquo;. Most of that is plain strings. Really just for the numbers we want to use
the regex. The first is the exit code in the parenthesis. Most containers had
&lt;code>0&lt;/code> or &lt;code>1&lt;/code> exit codes. But, a few had &lt;code>137&lt;/code>. So I just matched on any up to 3
digit number within the parenthesis: &lt;code>[0-9]{1,3}&lt;/code>.&lt;/p>
&lt;p>Second, we match a plain 2 then any units digit of months between 0 and 3,
inclusively: &lt;code>2[0-3]&lt;/code>. My results had the oldest container stopping 23 months
ago. You mileage may vary and I&amp;rsquo;ll leave it up to you to modify and re-run to
suit your situation.&lt;/p>
&lt;p>Now that we&amp;rsquo;ve got a good list of containers to delete, let&amp;rsquo;s use some
command-line fu to save a ton of copy/pasting. Let&amp;rsquo;s pipe this filtered list
into &lt;code>awk&lt;/code> to get rid of the rest of the text save for the first hash (field).&lt;/p>
&lt;pre>&lt;code>awk '{print $1}'
&lt;/code>&lt;/pre>&lt;p>Then, pass each row (which now only contains the ID hash of the container) into
&lt;code>docker rm&lt;/code>. To do this, we can use &lt;code>xargs&lt;/code>:&lt;/p>
&lt;pre>&lt;code>xargs -i@ docker rm @
&lt;/code>&lt;/pre>&lt;p>Putting it all together:&lt;/p>
&lt;pre>&lt;code>$ docker ps -a | grep -E &amp;quot;Exited \([0-9]{1,3}\) 2[0-3] months ago&amp;quot; | awk '{print $1}' | xargs -i@ docker rm @
&lt;/code>&lt;/pre>&lt;p>Then, go back to the top and remove dangiling images:&lt;/p>
&lt;pre>&lt;code>$ docker image prune
&lt;/code>&lt;/pre>&lt;p>There you have it. I removed containers I hadn&amp;rsquo;t run for more than 8 months or so and freed up almost 50GB.
I hope you have similar or better results! Let me know how you fare: &lt;a href="mailto:chris@codegoalie.com">chris@codegoalie.com&lt;/a>&lt;/p>
&lt;p>Happy &lt;code>docker rm&lt;/code>-ing!&lt;/p></description></item><item><title>Buffalo: Render a Template to String</title><link>https://codegoalie.com/posts/buffalo-render-template-to-string/</link><pubDate>Wed, 06 Mar 2019 15:43:24 -0500</pubDate><guid>https://codegoalie.com/posts/buffalo-render-template-to-string/</guid><description>&lt;p>The Golang web app framework, &lt;a href="https://gobuffalo.io">Buffalo&lt;/a>, has a very good
templating system called &lt;a href="https://github.com/gobuffalo/plush">Plush&lt;/a>. It adds
some nice features to the standard library templating specific to web applications
such as partials and local context. It&amp;rsquo;s pretty intuitive if you&amp;rsquo;re coming from
&lt;a href="https://rubyonrails.org/">Rails&lt;/a>.&lt;/p>
&lt;p>While the default setup makes rendering a template as a response to a request super
easy, using rendered template content elsewhere isn&amp;rsquo;t so obvious.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Once you see it though, it&amp;rsquo;s pretty straightforward to render a template to a string
within your action handler functions. Typically, we&amp;rsquo;d render a template like this:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-go" data-lang="go">&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">homeHandler&lt;/span>(&lt;span style="color:#a6e22e">c&lt;/span> &lt;span style="color:#a6e22e">buffalo&lt;/span>.&lt;span style="color:#a6e22e">Context&lt;/span>) &lt;span style="color:#66d9ef">error&lt;/span> {
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">c&lt;/span>.&lt;span style="color:#a6e22e">Render&lt;/span>(&lt;span style="color:#ae81ff">200&lt;/span>, &lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">HTML&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;index.html&amp;#34;&lt;/span>))
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Today I needed to return some HTML in a JSON resposne to a webhook to display some of
our content within &lt;a href="https://www.helpscout.com/">HelpScout&lt;/a> for their dynamic app
integration. Originally, I had a simple link to render which I did as:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-go" data-lang="go">&lt;span style="color:#a6e22e">render&lt;/span>(&lt;span style="color:#ae81ff">200&lt;/span>, &lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">JSON&lt;/span>(
&lt;span style="color:#66d9ef">struct&lt;/span> {
&lt;span style="color:#a6e22e">HTML&lt;/span> &lt;span style="color:#66d9ef">string&lt;/span> &lt;span style="color:#e6db74">`json:&amp;#34;html&amp;#34;`&lt;/span>
}{
&lt;span style="color:#a6e22e">HTML&lt;/span>: &lt;span style="color:#a6e22e">fmt&lt;/span>.&lt;span style="color:#a6e22e">Sprintf&lt;/span>(&lt;span style="color:#e6db74">`&amp;lt;a href=&amp;#34;%s/users/%s&amp;#34;&amp;gt;%s&amp;#39;s profile&amp;lt;/a&amp;gt;`&lt;/span>, &lt;span style="color:#a6e22e">HOST&lt;/span>, &lt;span style="color:#a6e22e">user&lt;/span>.&lt;span style="color:#a6e22e">ID&lt;/span>, &lt;span style="color:#a6e22e">user&lt;/span>.&lt;span style="color:#a6e22e">FullName&lt;/span>()),
}),
)
&lt;/code>&lt;/pre>&lt;/div>&lt;p>This &lt;em>barely&lt;/em> worked for this case, but it did work. Then we wanted to add more info and
I wasn&amp;rsquo;t willing to write HTML within a &lt;code>Sprintf&lt;/code> call. There are three steps to render
an arbitrary template to a string:&lt;/p>
&lt;ul>
&lt;li>Allocate an &lt;code>io.Writer&lt;/code> to hold the rendered template&amp;rsquo;s contents&lt;/li>
&lt;li>Render the template with a &lt;code>Renderer&lt;/code>.&lt;/li>
&lt;li>Read the string from the &lt;code>Writer&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>Here&amp;rsquo;s the code:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-go" data-lang="go">&lt;span style="color:#75715e">// allocate a buffer to render the template into
&lt;/span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">respBuf&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#f92672">&amp;amp;&lt;/span>&lt;span style="color:#a6e22e">bytes&lt;/span>.&lt;span style="color:#a6e22e">Buffer&lt;/span>{}
&lt;span style="color:#75715e">// set any required values in the context (could be any `render.Data`)
&lt;/span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">c&lt;/span>.&lt;span style="color:#a6e22e">Set&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;user&amp;#34;&lt;/span>, &lt;span style="color:#a6e22e">user&lt;/span>)
&lt;span style="color:#75715e">// create the Renderer with the HTML method and call Render with the buffer and the necessary data
&lt;/span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#a6e22e">err&lt;/span> = &lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">HTML&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;helpscout/sidebar.html&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;layouts/zero.html&amp;#34;&lt;/span>).&lt;span style="color:#a6e22e">Render&lt;/span>(&lt;span style="color:#a6e22e">respBuf&lt;/span>, &lt;span style="color:#a6e22e">c&lt;/span>.&lt;span style="color:#a6e22e">Data&lt;/span>())
&lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#a6e22e">err&lt;/span> &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#66d9ef">nil&lt;/span> {
&lt;span style="color:#a6e22e">err&lt;/span> = &lt;span style="color:#a6e22e">errors&lt;/span>.&lt;span style="color:#a6e22e">WithStack&lt;/span>(&lt;span style="color:#a6e22e">err&lt;/span>)
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">err&lt;/span>
}
&lt;span style="color:#75715e">// read the string out of the buffer (and in this case render it into a JSON response)
&lt;/span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">c&lt;/span>.&lt;span style="color:#a6e22e">Render&lt;/span>(&lt;span style="color:#ae81ff">200&lt;/span>, &lt;span style="color:#a6e22e">r&lt;/span>.&lt;span style="color:#a6e22e">JSON&lt;/span>(&lt;span style="color:#a6e22e">helpscoutResponse&lt;/span>{&lt;span style="color:#a6e22e">HTML&lt;/span>: &lt;span style="color:#a6e22e">respBuf&lt;/span>.&lt;span style="color:#a6e22e">String&lt;/span>()}))
&lt;/code>&lt;/pre>&lt;/div>&lt;p>That&amp;rsquo;s it. It&amp;rsquo;s pretty straightforward once you see it laid out. Hope this helps you (as
I&amp;rsquo;m sure it will help me in 6 months).&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Service 'Objects' in Buffalo</title><link>https://codegoalie.com/posts/service-objects-in-buffalo/</link><pubDate>Wed, 27 Feb 2019 05:09:02 -0500</pubDate><guid>https://codegoalie.com/posts/service-objects-in-buffalo/</guid><description>&lt;p>For many recent projects, I&amp;rsquo;ve been using the excellent
&lt;a href="https://gobuffalo.io/en">Buffalo&lt;/a> web development eco-system. It&amp;rsquo;s a great
collection of tools and packages for building web applications without needing
to reinvent the wheel for each app. In this post, I&amp;rsquo;ll be highlighting a
technique I use based on the service object design pattern of abstracting
business logic from your applicaton implementation to increase readability and
reusability.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;h2 id="but-why">But, why?&lt;/h2>
&lt;p>Here&amp;rsquo;s a scenario I find myself in with increasing frequency. I&amp;rsquo;ve just
implemented some great new feature or process. It&amp;rsquo;s good to go and super
helpful in its intended usage. All&amp;rsquo;s good.&lt;/p>
&lt;p>Then, you deiscover another, slightly different, use for the same feature. For
example, the system can send one-off reminder emails to individual users, but
now we want to remind all users. Or, I&amp;rsquo;d like to manually kick off that
background data integrity routine, but only for a single account and not the
entire user base. Or, I&amp;rsquo;d like to queue this process up in a background worker,
but only in certain cases.&lt;/p>
&lt;p>There are proper extractions here for these exact scenarios. Typically, this is
the extract function or method refactoring step. We will talk about that in a
minute, but the first thing I want to address is the &lt;strong>where&lt;/strong> does that
abstraction live.&lt;/p>
&lt;h2 id="a-place-for-everything-and-everything-in-its-place-until">A place for everything and everything in its place, until&lt;/h2>
&lt;p>The universal answer to almost any question in programming and software design
is &amp;ldquo;Sure, it could.&amp;rdquo; For a certain case, almost any imaginable specific
solution approaches the ideal solution. Should this be a method on the model?
Sure, it could. Wouldn&amp;rsquo;t this be better in the controller? Sure, it could. How
about we extract this into its own repo and it will live in a completely
separate open-source project? Sure, it could.&lt;/p>
&lt;p>To combat this, I like to personify my functions, classes, and methods as super
lazy beings. They are constantly asking me, &amp;ldquo;Do I &lt;em>have&lt;/em> to do that?&amp;rdquo; and &amp;ldquo;What
if I don&amp;rsquo;t want to know about all that?&amp;rdquo; I find this extremely helpful in
following the single responsibility principle and avoiding scope creep within
code constructs.&lt;/p>
&lt;blockquote>
&lt;p>Imagine your functions as super lazy people that don&amp;rsquo;t want to do more than
they absolutely &lt;em>have&lt;/em> to.&lt;/p>
&lt;/blockquote>
&lt;p>For example, my models don&amp;rsquo;t like to send emails. My email sending functions
don&amp;rsquo;t want to know about my user models, just email address strings. Route
handlers don&amp;rsquo;t feel like learning SQL. You get the idea.&lt;/p>
&lt;p>But (and there&amp;rsquo;s always a but), sometimes there isn&amp;rsquo;t a really good,
immediately known place to put some piece of logic. This is where the service
&amp;ldquo;object&amp;rdquo; pattern comes in. I almost think of it as a catch-all, last resort
solution to design questins. Will a service work best for you? Sure, it could.&lt;/p>
&lt;h2 id="ok-what-is-it-_exactly_">Ok what is it &lt;em>exactly&lt;/em>&lt;/h2>
&lt;p>Hopefully by now, you&amp;rsquo;re on board with at least the idea of using a service to
contain some kind of cross-cutting, or self-contained unit of logic.
Specifically, in &lt;code>go&lt;/code> in the &lt;code>Buffalo&lt;/code> world, what is a service?&lt;/p>
&lt;p>I put services as exported functions in a &lt;code>services&lt;/code> package. The directory
structure looks like this:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-diff" data-lang="diff"> actions/
mailers/
templates/
&lt;span style="color:#a6e22e">+ services/
&lt;/span>&lt;span style="color:#a6e22e">+ notify_weekly_winner.go
&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And I implement one like this:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-go" data-lang="go">&lt;span style="color:#75715e">// service/notify_weekly_winner.go
&lt;/span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#f92672">package&lt;/span> &lt;span style="color:#a6e22e">services&lt;/span>
&lt;span style="color:#75715e">// NotifyWeeklyWinner sends a congratulations notification to a weekly winner
&lt;/span>&lt;span style="color:#75715e">&lt;/span>&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">NotifyWeeklyWinner&lt;/span>(&lt;span style="color:#a6e22e">email&lt;/span>, &lt;span style="color:#a6e22e">firstName&lt;/span> &lt;span style="color:#66d9ef">string&lt;/span>, &lt;span style="color:#a6e22e">dogsWalked&lt;/span> &lt;span style="color:#66d9ef">int&lt;/span>) &lt;span style="color:#66d9ef">error&lt;/span> {
&lt;span style="color:#a6e22e">giftCardCode&lt;/span>, &lt;span style="color:#a6e22e">_&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#a6e22e">GetGiftCardForWalkingDogs&lt;/span>(&lt;span style="color:#a6e22e">dogsWalked&lt;/span>) &lt;span style="color:#75715e">// another service ;)
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">mailers&lt;/span>.&lt;span style="color:#a6e22e">SendWeeklyWinnerEmail&lt;/span>(&lt;span style="color:#a6e22e">email&lt;/span>, &lt;span style="color:#a6e22e">firstName&lt;/span>, &lt;span style="color:#a6e22e">giftCardCode&lt;/span>)
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>I know what you&amp;rsquo;re thinking: &amp;ldquo;Ok, this is a really simple example just to show
the concept. A real service would be way more complex, right?&amp;rdquo; Sure, it could.
However, I think even this short example is actually very exemplary. Let&amp;rsquo;s see
an alternative implementation and back into how we ended up here.&lt;/p>
&lt;h2 id="add-to-route-handler-controller">Add to route handler (controller)&lt;/h2>
&lt;p>Probably the first implementation of this process was in a route handler
function (or controller) somewhere. Maybe there&amp;rsquo;s a specific button in the
interface to notify a weekly winner which maps to a handler which does some
controller-y stuff (validates params, fetches data from DB, etc.), then has the
two lines from the service above, then redirects to another path.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-go" data-lang="go">&lt;span style="color:#75715e">// actions/notifications.go
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">notifyOfWinningHandler&lt;/span>(&lt;span style="color:#a6e22e">c&lt;/span> &lt;span style="color:#a6e22e">buffalo&lt;/span>.&lt;span style="color:#a6e22e">Context&lt;/span>) &lt;span style="color:#66d9ef">error&lt;/span> {
&lt;span style="color:#75715e">// load some models
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#a6e22e">giftCardCode&lt;/span>, &lt;span style="color:#a6e22e">_&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#a6e22e">GetGiftCardForWalkingDogs&lt;/span>(&lt;span style="color:#a6e22e">dogsWalked&lt;/span>)
&lt;span style="color:#75715e">// actually handle error
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#a6e22e">err&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#a6e22e">mailers&lt;/span>.&lt;span style="color:#a6e22e">SendWeeklyWinnerEmail&lt;/span>(&lt;span style="color:#a6e22e">email&lt;/span>, &lt;span style="color:#a6e22e">firstName&lt;/span>, &lt;span style="color:#a6e22e">giftCardCode&lt;/span>)
&lt;span style="color:#66d9ef">if&lt;/span> &lt;span style="color:#a6e22e">err&lt;/span> &lt;span style="color:#f92672">!=&lt;/span> &lt;span style="color:#66d9ef">nil&lt;/span> {
&lt;span style="color:#75715e">// report error
&lt;/span>&lt;span style="color:#75715e">&lt;/span> &lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">errors&lt;/span>.&lt;span style="color:#a6e22e">WithStack&lt;/span>(&lt;span style="color:#a6e22e">err&lt;/span>)
}
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">c&lt;/span>.&lt;span style="color:#a6e22e">Redirect&lt;/span>(&lt;span style="color:#ae81ff">302&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;/home&amp;#34;&lt;/span>)
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Ok, actually seems reasonable. Could this be a better solution? Sure, it could.&lt;/p>
&lt;p>So, time for a confession. I just made the above service example to show a
super simple example. I gave no thought to the rest of the application around
it or what it might even do. Now that we&amp;rsquo;re stuck with it, let&amp;rsquo;s take a second
to think about the world we&amp;rsquo;ve created.&lt;/p>
&lt;p>We know that every week we send a gift card to someone (with a first name and
an email address) who has walked some dogs. The amount of the card may be based
on the number of dogs walked. We&amp;rsquo;ve implemented some handler to send a
notification with the gift card code to such a person.&lt;/p>
&lt;p>We do have some known unknowns though. We don&amp;rsquo;t know what criteria constitutes
a winner. We don&amp;rsquo;t know if there are one or multiple weekly winners. We don&amp;rsquo;t
even know if this system has a &lt;code>User&lt;/code> model. All that is a &lt;strong>great thing!&lt;/strong> We
don&amp;rsquo;t need to know any of those things to send an email. Our implementation
doesn&amp;rsquo;t need (or want) to know it either.&lt;/p>
&lt;p>However, I&amp;rsquo;m not happy. Based on this handler, it would seem that someone
somewhere needs to click a link or button every week to notify the winner. We
can do better.&lt;/p>
&lt;h2 id="using-a-background-worker">Using a background worker&lt;/h2>
&lt;p>Let&amp;rsquo;s say we don&amp;rsquo;t trust humans and want to send the notification each week on
an automated schedule. Let&amp;rsquo;s also say we have a background task system which
does this. Then we&amp;rsquo;d simply extract the logic into a worker.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-go" data-lang="go">&lt;span style="color:#75715e">// actions/worker.go
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#a6e22e">w&lt;/span> &lt;span style="color:#a6e22e">worker&lt;/span>.&lt;span style="color:#a6e22e">Worker&lt;/span>
&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">init&lt;/span>() {
&lt;span style="color:#a6e22e">_&lt;/span> = &lt;span style="color:#a6e22e">w&lt;/span>.&lt;span style="color:#a6e22e">Register&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;notify_weekly_winner&amp;#34;&lt;/span>, &lt;span style="color:#66d9ef">func&lt;/span>(&lt;span style="color:#a6e22e">args&lt;/span> &lt;span style="color:#a6e22e">worker&lt;/span>.&lt;span style="color:#a6e22e">Args&lt;/span>) &lt;span style="color:#66d9ef">error&lt;/span> {
&lt;span style="color:#75715e">// load from args, etc.
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#a6e22e">giftCardCode&lt;/span>, &lt;span style="color:#a6e22e">_&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#a6e22e">GetGiftCardForWalkingDogs&lt;/span>(&lt;span style="color:#a6e22e">dogsWalked&lt;/span>)
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">mailers&lt;/span>.&lt;span style="color:#a6e22e">SendWeeklyWinnerEmail&lt;/span>(&lt;span style="color:#a6e22e">email&lt;/span>, &lt;span style="color:#a6e22e">firstName&lt;/span>, &lt;span style="color:#a6e22e">giftCardCode&lt;/span>)
})
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>The nice thing here is that we can also keep our handler, if we need a
manual fail-safe.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-go" data-lang="go">&lt;span style="color:#75715e">// actions/notifications.go
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">notifyOfWinningHandler&lt;/span>(&lt;span style="color:#a6e22e">c&lt;/span> &lt;span style="color:#a6e22e">buffalo&lt;/span>.&lt;span style="color:#a6e22e">Context&lt;/span>) &lt;span style="color:#66d9ef">error&lt;/span> {
&lt;span style="color:#75715e">// load some models
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#a6e22e">_&lt;/span> = &lt;span style="color:#a6e22e">w&lt;/span>.&lt;span style="color:#a6e22e">Perform&lt;/span>(&lt;span style="color:#a6e22e">worker&lt;/span>.&lt;span style="color:#a6e22e">Job&lt;/span>{
&lt;span style="color:#a6e22e">Handler&lt;/span>: &lt;span style="color:#e6db74">&amp;#34;notify_weekly_winner&amp;#34;&lt;/span>,
&lt;span style="color:#a6e22e">Args&lt;/span>: &lt;span style="color:#a6e22e">worker&lt;/span>.&lt;span style="color:#a6e22e">Args&lt;/span>{
&lt;span style="color:#e6db74">&amp;#34;firstName&amp;#34;&lt;/span>: &lt;span style="color:#a6e22e">firstName&lt;/span>,
&lt;span style="color:#e6db74">&amp;#34;email&amp;#34;&lt;/span>: &lt;span style="color:#a6e22e">email&lt;/span>,
&lt;span style="color:#e6db74">&amp;#34;dogsWalked&amp;#34;&lt;/span>: len(&lt;span style="color:#a6e22e">dogs&lt;/span>),
},
})
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">c&lt;/span>.&lt;span style="color:#a6e22e">Redirect&lt;/span>(&lt;span style="color:#ae81ff">302&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;/home&amp;#34;&lt;/span>)
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is fine. It&amp;rsquo;s not very testable. Could it be justifed extracting to a
service just for better tesability? Sure, it could. You might also have a great
testing harness for background jobs and this isn&amp;rsquo;t an issue. However, I&amp;rsquo;m going
to get a little hand wavy here with the specifics, but I find myself in the
below type of situation somewhat regulary. I bet you do too.&lt;/p>
&lt;p>There&amp;rsquo;s that random, one-off-that-becomes-semi-weekly, completely unanticipated
feature request. The CEO needs wants to send a gift card to his personal dog
walker who&amp;rsquo;s not in the system. We want to back-fill the past 6 months of
winners that we tracked in a spreadsheet. This is where the rubber meets the road.&lt;/p>
&lt;blockquote>
&lt;p>The hallmark of a well designed sytem is its ability to handle unexpected change.&lt;/p>
&lt;/blockquote>
&lt;p>Using our service, we can easily add a grift task to send arbitrary notifications.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-go" data-lang="go">&lt;span style="color:#75715e">// grifts/notify.go
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">var&lt;/span> &lt;span style="color:#a6e22e">_&lt;/span> = &lt;span style="color:#a6e22e">grift&lt;/span>.&lt;span style="color:#a6e22e">Namespace&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;noitfy&amp;#34;&lt;/span>, &lt;span style="color:#66d9ef">func&lt;/span>() {
&lt;span style="color:#a6e22e">grift&lt;/span>.&lt;span style="color:#a6e22e">Desc&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;winner&amp;#34;&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;Send a gift card for walking dogs&amp;#34;&lt;/span>)
&lt;span style="color:#a6e22e">grit&lt;/span>.&lt;span style="color:#a6e22e">Add&lt;/span>(&lt;span style="color:#e6db74">&amp;#34;winner&amp;#34;&lt;/span>, &lt;span style="color:#66d9ef">func&lt;/span>(&lt;span style="color:#a6e22e">c&lt;/span> &lt;span style="color:#f92672">*&lt;/span>&lt;span style="color:#a6e22e">grift&lt;/span>.&lt;span style="color:#a6e22e">Context&lt;/span>) &lt;span style="color:#66d9ef">error&lt;/span> {
&lt;span style="color:#a6e22e">email&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#a6e22e">c&lt;/span>.&lt;span style="color:#a6e22e">Args&lt;/span>[&lt;span style="color:#ae81ff">0&lt;/span>]
&lt;span style="color:#a6e22e">firstName&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#a6e22e">c&lt;/span>.&lt;span style="color:#a6e22e">Args&lt;/span>[&lt;span style="color:#ae81ff">1&lt;/span>]
&lt;span style="color:#a6e22e">dogsWalked&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#a6e22e">c&lt;/span>.&lt;span style="color:#a6e22e">Args&lt;/span>[&lt;span style="color:#ae81ff">2&lt;/span>]
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">service&lt;/span>.&lt;span style="color:#a6e22e">NotifyWeeklyWinner&lt;/span>(&lt;span style="color:#a6e22e">email&lt;/span>, &lt;span style="color:#a6e22e">firstName&lt;/span>, &lt;span style="color:#a6e22e">dogsWalked&lt;/span>)
})
})
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Or we can upload a CSV to send notifications.&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-go" data-lang="go">&lt;span style="color:#75715e">// actions/upload.go
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">func&lt;/span> &lt;span style="color:#a6e22e">uploadWinnersHandler&lt;/span>(&lt;span style="color:#a6e22e">c&lt;/span> &lt;span style="color:#a6e22e">buffalo&lt;/span>.&lt;span style="color:#a6e22e">Context&lt;/span>) &lt;span style="color:#66d9ef">error&lt;/span> {
&lt;span style="color:#75715e">// read from CSV
&lt;/span>&lt;span style="color:#75715e">&lt;/span>
&lt;span style="color:#66d9ef">for&lt;/span> &lt;span style="color:#a6e22e">_&lt;/span>, &lt;span style="color:#a6e22e">winner&lt;/span> &lt;span style="color:#f92672">:=&lt;/span> &lt;span style="color:#66d9ef">range&lt;/span> &lt;span style="color:#a6e22e">winners&lt;/span> {
&lt;span style="color:#a6e22e">service&lt;/span>.&lt;span style="color:#a6e22e">NotifyWeeklyWinner&lt;/span>(&lt;span style="color:#a6e22e">winner&lt;/span>.&lt;span style="color:#a6e22e">Email&lt;/span>, &lt;span style="color:#a6e22e">winner&lt;/span>.&lt;span style="color:#a6e22e">FirstName&lt;/span>, &lt;span style="color:#a6e22e">winner&lt;/span>.&lt;span style="color:#a6e22e">DogsWalked&lt;/span>)
}
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#a6e22e">c&lt;/span>.&lt;span style="color:#a6e22e">Redirect&lt;/span>(&lt;span style="color:#ae81ff">302&lt;/span>, &lt;span style="color:#e6db74">&amp;#34;/home&amp;#34;&lt;/span>)
}
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Thank you for taking this journey into service &amp;ldquo;objects&amp;rdquo; with me. As always,
please feel free to contact me with any questions, suggestions, criticisms, or
thoughts at &lt;a href="mailto:chris@codegoalie.com">chris@codegoalie.com&lt;/a>.&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Ruby refactoring: Open/Closed Principle</title><link>https://codegoalie.com/posts/ruby-open-closed/</link><pubDate>Fri, 12 Jan 2018 08:20:15 -0500</pubDate><guid>https://codegoalie.com/posts/ruby-open-closed/</guid><description>&lt;p>Let&amp;rsquo;s examine a refactoring to move code to follow the
&lt;a href="https://en.wikipedia.org/wiki/Open/closed_principle">open/closed principle&lt;/a>.
We&amp;rsquo;ll see how the resulting calling code becomes much easier to read locally,
without having to open other files or classes to understand what&amp;rsquo;s going on.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;h2 id="openclosed-principle">Open/closed principle&lt;/h2>
&lt;p>First, let&amp;rsquo;s do a quick recap of the open/closed principle. Classes should be
open to extension, but closed to modification. What does that mean? Let&amp;rsquo;s take
it a half at a time.&lt;/p>
&lt;p>&amp;ldquo;Classes should be open to extension.&amp;rdquo; This means building
your classes in a way that they are simple and single-use enough to be reusable
or combine-able. This is the difference between building a Lego brick and a
fully built spaceship. The spaceship is more complete, but when you&amp;rsquo;re tired of
playing spaceships, you can&amp;rsquo;t easily reconfigure it into something else.&lt;/p>
&lt;p>Second, &amp;ldquo;classes should be closed to modification.&amp;rdquo; Violating this
principle will require you to modify far off code to implement your current
feature. You should structure your code to avoid this because you may forget
to change that far off code, other developers on the team may not know to change
that code, and it&amp;rsquo;s often a mystery why this far off code is even related.
More practically, this often manifests in a list of classes, types, &amp;ldquo;allowed&amp;rdquo;
things, &amp;ldquo;blacklisted&amp;rdquo; stuff, etc. If you add a new class and then have to add
that class to a list somewhere, you&amp;rsquo;re probably not following open/closed.&lt;/p>
&lt;h2 id="sending-update-notifications">Sending update notifications&lt;/h2>
&lt;p>I recently had a project where we wanted to send some update notifications to
users when entities they were interested in were updated by other users. This
Rails application exposes a JSON API and has a bulk update mechanism. The
controller action which handles these bulk requests is generic such that many
types of models can be updated simultaneously. After successful updates, we
schedule a background job to send the update notifications:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">if&lt;/span> entity&lt;span style="color:#f92672">.&lt;/span>save
&lt;span style="color:#66d9ef">SendUpdateNotificationJob&lt;/span>&lt;span style="color:#f92672">.&lt;/span>perform_later(entity)
&lt;span style="color:#f92672">...&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Initially we only sent updates for new or updated Posts:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SendUpdateNotificationJob&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#66d9ef">ApplicationJob&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">perform&lt;/span>(entity)
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">unless&lt;/span> entity&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Post&lt;/span>
&lt;span style="color:#75715e"># send push notifications here&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="adding-more-notification-types">Adding more notification types&lt;/h2>
&lt;p>Seems reasonable enough. However, new and updated post notifications were such
a hit that when we added responses to the application, people asked to get
updates for them as well. Super easy to do that:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-diff" data-lang="diff">&lt;span style="color:#f92672">- return unless entity.class == Post
&lt;/span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+ return unless entity.class == Post || entitty.class == Response
&lt;/span>&lt;span style="color:#a6e22e">&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>And then bulletins&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-diff" data-lang="diff">&lt;span style="color:#f92672">- return unless entity.class == Post || entitty.class == Response
&lt;/span>&lt;span style="color:#f92672">&lt;/span>&lt;span style="color:#a6e22e">+ return if entity.class == Post || entitty.class == Response || entitty.class == Bulletin
&lt;/span>&lt;span style="color:#a6e22e">&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Your level of pain tolerance may vary, but to me, this is already &lt;strong>way&lt;/strong> out
of control. Even though we aren&amp;rsquo;t expressing it as an array or list explicitly,
we are building up a list of classes which we decided earler was a sign of
violating open/closed.&lt;/p>
&lt;h2 id="naming-conditionals">Naming conditionals&lt;/h2>
&lt;p>So, how do we fix this? A really nice refactoring technique I like to use is
what I call &amp;ldquo;naming conditionals&amp;rdquo; (super trademarked;
&lt;a href="https://www.youtube.com/watch?v=Md1MDHroXGU">not to be used without express written consent of Ricky Bobby, inc.&lt;/a>).
This is pretty easy to do. I take a conditional, extact it to a method and
give it a name. Let&amp;rsquo;s do that here:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">______?&lt;/span>(entity)
entity&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Post&lt;/span> &lt;span style="color:#f92672">||&lt;/span> entitty&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Response&lt;/span> &lt;span style="color:#f92672">||&lt;/span> entitty&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Bulletin&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now the hardest part of programming: naming this method. I like to keep it
simple, so how about &lt;code>send_updates?&lt;/code>? Now our calling code reads like this:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SendUpdateNotificationJob&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#66d9ef">ApplicationJob&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">perform&lt;/span>(entity)
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">unless&lt;/span> send_updates?(entity)
&lt;span style="color:#75715e"># send push notifications here&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">send_updates?&lt;/span>(entity)
entity&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Post&lt;/span> &lt;span style="color:#f92672">||&lt;/span> entitty&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Response&lt;/span> &lt;span style="color:#f92672">||&lt;/span> entitty&lt;span style="color:#f92672">.&lt;/span>class &lt;span style="color:#f92672">==&lt;/span> &lt;span style="color:#66d9ef">Bulletin&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>The calling code is much easier to read: Don&amp;rsquo;t send updates unless you should.&lt;/p>
&lt;p>&lt;em>But&lt;/em>, we haven&amp;rsquo;t solved the open/closed problem yet.&lt;/p>
&lt;h2 id="reverse-dependency-injection">Reverse dependency injection&lt;/h2>
&lt;p>One of my favorite discussions in programming is about who doesn&amp;rsquo;t care about
things. In this case, I would say that this job does not care about which
classes the entities are that it gets. It only cares about if it can send
notifications for them, and then doing so. In this case, it would not check
the classes of the entity.&lt;/p>
&lt;p>If tho doesn&amp;rsquo;t know about the classes, then who does? Well, the entities know
their classes. What if the job asked them if updates should be sent for
themselves?&lt;/p>
&lt;p>Then we&amp;rsquo;d have code like:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">SendUpdateNotificationJob&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#66d9ef">ApplicationJob&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">perform&lt;/span>(entity)
&lt;span style="color:#66d9ef">return&lt;/span> &lt;span style="color:#66d9ef">unless&lt;/span> entity&lt;span style="color:#f92672">.&lt;/span>send_updates?
&lt;span style="color:#75715e"># send push notifications here&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>That seems pretty straightforward to me.&lt;/p>
&lt;blockquote>
&lt;p>Quick aside: It might also be worth removing that conditional from the job
and preforming the check before even scheduling the background job. This would
allow you to send notifications for &amp;ldquo;unallowed&amp;rdquo; types if really necessary but
put the gate keeping burden upon the scheduler of the job. Trade-offs&amp;hellip;&lt;/p>
&lt;/blockquote>
&lt;h2 id="set-a-default-override-when-necessary">Set a default, override when necessary&lt;/h2>
&lt;p>With Rails 5+, the concept of an &lt;code>ApplicationRecord&lt;/code> was introduced to give a
single parent class for your models within your application. This is a great
place to add code or configuration to be shared by all models.&lt;/p>
&lt;p>For most models, we don&amp;rsquo;t want to send updates:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">ApplicationRecord&lt;/span> &lt;span style="color:#f92672">&amp;lt;&lt;/span> &lt;span style="color:#66d9ef">ActiveRecord&lt;/span>&lt;span style="color:#f92672">::&lt;/span>&lt;span style="color:#66d9ef">Base&lt;/span>
&lt;span style="color:#f92672">...&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">send_updates?&lt;/span>
&lt;span style="color:#66d9ef">false&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Any class we want to send updates for can say so:&lt;/p>
&lt;div class="highlight">&lt;pre style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4">&lt;code class="language-ruby" data-lang="ruby">&lt;span style="color:#66d9ef">class&lt;/span> &lt;span style="color:#a6e22e">Post&lt;/span>
&lt;span style="color:#f92672">...&lt;/span>
&lt;span style="color:#66d9ef">def&lt;/span> &lt;span style="color:#a6e22e">send_updates?&lt;/span>
&lt;span style="color:#66d9ef">true&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;span style="color:#66d9ef">end&lt;/span>
&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now, we don&amp;rsquo;t ever have to &lt;em>open&lt;/em> the send updates job and add more classes to
the list. When we add &lt;code>NewsArtlcles&lt;/code> next month, it&amp;rsquo;ll be super straightforward
to allow or disallow notifications for them. Further, we can add more logic in
the &lt;code>send_updates?&lt;/code> method; like only sending updates bulletin created after
2pm on a Sunday.&lt;/p>
&lt;p>If you find yourself adding and removing from lists of classes in your
application, take a moment to think about the open/closed principle and
whether or not it can help you make more readable, modifiable, and exemplary
code.&lt;/p>
&lt;p>Happy open/closing!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Poor Man's React Router</title><link>https://codegoalie.com/posts/react-routing/</link><pubDate>Sat, 03 Jun 2017 12:11:17 -0400</pubDate><guid>https://codegoalie.com/posts/react-routing/</guid><description>&lt;p>Recently at &lt;a href="1">Videofruit&lt;/a>, we had a fun internal exercise of building an app
in single workday. That app ended up being an &lt;a href="2">Email Service Provider picker&lt;/a>
where you answer a series of questions and we recommend an email service
provider to meet your needs. In this post, we&amp;rsquo;ll breakdown a simplified version
of that app focusing in on how we built a routing mechanism that is simple but
effective and uses no external dependencies.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>The ESP picker app essentially consists of 4 pages: the landing page, a question
page, an email collection page, and the recommendation page. We&amp;rsquo;ve implemented
each of these pages as their own component and will now demonstrate how we
built a sub-system to decide which component to render and then renders it.&lt;/p>
&lt;p>Surprise, surprise. In typical React fasion, we&amp;rsquo;ve implemented this component
selection logic wthin yet another component. This &lt;code>PagePicker&lt;/code> component exists
near the root of the component hierarchy and has its own state which holds the
current component to render. &lt;code>PagePicker&lt;/code> also defines a set of callbacks to
pass into each page in order to update that state and then render new
components.&lt;/p>
&lt;pre>&lt;code>import React, { Component } from &amp;quot;react&amp;quot;;
import LandingPage from &amp;quot;./LandingPage&amp;quot;;
import QuestionPage from &amp;quot;./QuestionPage&amp;quot;;
import RecommendationPage from &amp;quot;./RecommendationPage&amp;quot;;
import questions from &amp;quot;./questions.js&amp;quot;;
class PagePicker extends Component {
constructor(props) {
super(props);
this.state - {
currentPage: &amp;quot;LandingPage&amp;quot;,
currentQuestion: 0
};
thisstartQuestions = this.startQuestions.bind(this);
this.goToRecommendationPage = this.goToRecommendationPage.bind(this);
}
startQuestions() {
this.setState({ currentPage: &amp;quot;QuestionPage&amp;quot;, currentQuestion: 0 });
}
nextQuestion() {
this.setState(prevState =&amp;gt; {
let nextQuestion= prevState.currentQuestion + 1;
if (nextQuestion &amp;gt;= questions.length) {
return { currentPage: &amp;quot;RecommendationPage&amp;quot; };
} else {
return { currentQuestion: nextQuestion };
}
});
}
calculateRecommendation() {
// Your logic here
return &amp;quot;super-awesome-recommendation&amp;quot;;
}
render() {
switch (this.state.currentPage) {
case &amp;quot;LandingPage&amp;quot;:
return (
&amp;lt;LandingPage
startQuestions={this.startQuestions}
/&amp;gt;
);
break;
case &amp;quot;QuestionPage&amp;quot;:
return (
&amp;lt;QuestionPage
question={questions[this.state.currentQuestion]}
nextQuestion={this.nextQuestion}
/&amp;gt;
);
break;
case &amp;quot;RecommendationPage&amp;quot;:
return (
&amp;lt;RecommendationPage
recommendation={this.calculateRecommendation()}
/&amp;gt;
);
break;
}
}
}
&lt;/code>&lt;/pre>&lt;p>As you can see, this approach is pretty straight forward and, most importantly,
it requires no third-party dependencies. As with any implementation, there are
caveats and trade-offs. Firstly, this approach does not work with an app where
you expect the number of pages to grow large. The &lt;code>switch&lt;/code> statement can easily
get unweildy and hard to maintain.&lt;/p>
&lt;p>If your app has pages which need to communicate to eachother directly, this
approach could cause problems. Our app is very linear and each page is very
separate in both state and function. We take advantage of that in this
technique.&lt;/p>
&lt;p>Overall, we&amp;rsquo;re pleased with the declarative layout of this approach and that
the current page being shown is clearly defined in the state. Any of the
transition callbacks can contain more complex logic which would be fuctionally
encapsulated and easily testable. We hope you find some value in this technique
too.&lt;/p>
&lt;p>Happy routing!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>How shell scripting saves my side projects</title><link>https://codegoalie.com/posts/how-shell-scripting-saves-my-side-projects/</link><pubDate>Tue, 19 Jul 2016 17:58:03 -0400</pubDate><guid>https://codegoalie.com/posts/how-shell-scripting-saves-my-side-projects/</guid><description>&lt;p>I work on a lot of little side projects. Many of them are short-lived and small
scale. I start them to learn a new technology, to learn a new concept, try an
idea, or just to see if I can actually build something cool. I should also
mention that my memory is terrible. I &amp;ldquo;remember&amp;rdquo; things by figuring them out
again. Rote memorization is basically non-existent to me. I&amp;rsquo;ve recently come up
with a new best practice for my side projects which has saved my butt several
times now.&lt;/p>
&lt;p>It&amp;rsquo;s a &lt;code>deploy.sh&lt;/code> script and I put one in every project that I do which needs
to be built, deployed, or executed beyond the typical compile step. This
very blog &lt;a href="blog-deploy-dot-sh">has one&lt;/a>. There are also a few best practices
I&amp;rsquo;ve developed for making this file useful and not just another headache.&lt;/p>
&lt;h1 id="runable">Runable&lt;/h1>
&lt;p>This seems like a no-brainer, but hear me out. This file should be executable on
its own. It should not be &lt;code>deploy.rb&lt;/code>. It should not need to be compiled or
otherwise prepared to run. You are writing a script. Script away all of that
tedium. If you need to deploy with ruby, make your &lt;code>deploy.sh&lt;/code> simply contain
&lt;code>ruby deploy.rb&lt;/code>. The point here is that you can &lt;code>cd&lt;/code> into your project and run
this script. Period. If you have to remember to initialize your Python
virtualenv first, you&amp;rsquo;ve missed the point. Set it and forget it.&lt;/p>
&lt;h1 id="helpful">Helpful&lt;/h1>
&lt;p>Not &lt;em>everything&lt;/em> can be scripted away. Sometimes a deploy requires some unique
information, such as an environment or version number. Every microservice I
create is meant to run in a &lt;a href="docker">docker&lt;/a> container on
&lt;a href="kubernetes">kubernetes&lt;/a>. In order to automate building, tagging, pushing the
image, and then updating the deployment, the deploy script needs to know the
version number. Since I&amp;rsquo;ve deployed 10 times today to &amp;ldquo;fix&amp;rdquo; that one bug, I can
easily remember to pass the version to the script: &lt;code>./deploy.sh v1.0.1337&lt;/code>.
However, I won&amp;rsquo;t be so hip to that fact tomorrow. Good thing we are writing a
script. Just add some checks and helpful error messages to guide your future
self down the right path. Here&amp;rsquo;s an easy one for requiring an argument to
your script:&lt;/p>
&lt;pre>&lt;code>#!/bin/bash
if [ -z &amp;quot;$1&amp;quot; ]
then
echo &amp;quot;Please provide a version number, like v35&amp;quot;
exit 1
fi
# other deploy code here
&lt;/code>&lt;/pre>&lt;p>It may seem like a drag, but you&amp;rsquo;ll be so happy that you took the time to
take care of your own self now.&lt;/p>
&lt;h1 id="complete">Complete&lt;/h1>
&lt;p>Lastly, your deploy script needs to do every step on its own. It&amp;rsquo;s a grown-up
script now and can handle it. If you need to do just one more thing after the
deploy finishes, you might as well just &lt;code>rm deploy.sh&lt;/code>. Even steps which you
might consider &amp;ldquo;optional&amp;rdquo; now, &lt;strong>need&lt;/strong> to be included. For example, this blog
is &lt;a href="aws-s3-static">hosted on AWS S3&lt;/a> and CDN&amp;rsquo;ed by CloudFront. It really is
enough to only upload (read: sync; save those bits) the files. Eventually the
cache will expire and the new content will be shown. However, in just one more
line in the &lt;code>deploy.sh&lt;/code>, I can invalidate the CloudFront distribution and see
this awesome new post right away. If you think it&amp;rsquo;s optional, it&amp;rsquo;s required.&lt;/p>
&lt;p>Well, those are my three tips for keeping your side project deployments sane.&lt;/p>
&lt;p>Happy deploying!!&lt;/p>
&lt;p>&lt;strong>P.S.&lt;/strong> I&amp;rsquo;ve recently had a resurgence of shell scripting in general. In the
past, I&amp;rsquo;ve certainly been one to (ab)use
&lt;a href="sub-search">zsh&amp;rsquo;s history substring search&lt;/a> to re-run the same set of commands
over and again. See also: &amp;ldquo;Up 12 times then enter. 6 times.&amp;rdquo; By committing those
mini-scripts to &lt;code>~/bin/&lt;/code>, it really has made me much more efficient. A practical
example is streamlining my workflow at work. We use Github for code hosting and
reviews. We also use &lt;a href="youtrack">YouTrack&lt;/a> for our project management. I wrote a
&lt;a href="goutrack">command line client for YouTrack&lt;/a> and combined all the commands I was
doing to &lt;a href="checkout-story">checkout branches by story number&lt;/a> or create new
branches as well as marking stories In Progress/Under Review/etc. into shell
scripts like &lt;code>review_story c-1234&lt;/code> or&lt;/p>
&lt;pre>&lt;code>$ start_story -t bug -s c-1234 -b this-is-a-heisenbug
Applying &amp;quot;Assignee: me In Progress&amp;quot; to story c-1234
Switched to new branch 'bugs/c-1234-this-is-a-heisenbug'
&lt;/code>&lt;/pre>&lt;p>Get creative and really push yourself to save some time. Again, you&amp;rsquo;ll thank
yourself, and then me. ;)&lt;/p></description></item><item><title>Git References</title><link>https://codegoalie.com/posts/git-refs/</link><pubDate>Wed, 06 Apr 2016 23:04:17 -0400</pubDate><guid>https://codegoalie.com/posts/git-refs/</guid><description>&lt;p>Everyone knows how to checkout a branch, &lt;code>git checkout master&lt;/code>, or how to look
at a specific commit, &lt;code>git show a1c8b6d&lt;/code>. But few know that branches, tags,
and commit SHAs are typically interchangeable in these and many other &lt;code>git&lt;/code>
commands. Plus there is a whole set of modifiers to reference commits near to
specific commits. In this post, we&amp;rsquo;ll explore all these techniques to become
expert &lt;code>git&lt;/code> referencers.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;h1 id="references">References&lt;/h1>
&lt;p>Below we will explore the different ways we can express a commit in &lt;code>git&lt;/code>. While
each technique has its own strengths and weaknesses, being able to wield a lot
of &lt;code>git&lt;/code>&amp;rsquo;s power and saving a lot of time comes from using these references
interchangeably.&lt;/p>
&lt;h2 id="sha1s">SHA1s&lt;/h2>
&lt;p>This first and most recognizable way to reference a commit is by its SHA1. This
is the full or part of the long random looking string of letters and numbers.
These are generated based on the contents of the commit, including current state
of the repo&amp;rsquo;s files, commit message, author and committer, and timestamp. If any
of those items change, a new SHA1 will be generated. Here are some examples of
&lt;code>git&lt;/code> commands using the SHA1.&lt;/p>
&lt;pre>&lt;code>git show abc123
git cherry-pick 321bca
git reset bbbaa4
&lt;/code>&lt;/pre>&lt;h2 id="branch-names">Branch Names&lt;/h2>
&lt;p>Branch names are also something that are a big part of a &lt;code>git&lt;/code> workflow. Under
the hood, branch names are just aliases for commit SHA1s. Literally, you can see
the branch names in the &lt;code>.git/refs/heads&lt;/code> directory of your repo. Each file
there contains one line which has the SHA1 of the commit it references. Here are
some common usages of branch names:&lt;/p>
&lt;pre>&lt;code>git checkout master
git rebase stable
git merge features/new-hottness
git cherry-pick bugs/broken-email-form
&lt;/code>&lt;/pre>&lt;p>An important aspect of branch names is the commit they reference can change. For
example, when you create a new commit the branch which you are currently on
automatically gets updated to the new SHA1.&lt;/p>
&lt;h2 id="tags">Tags&lt;/h2>
&lt;p>Tags are very similar to branch names in that they are also friendlier aliases
for commit SHA1s. However, unlike branches, tags cannot be changed once created.
This makes them ideal for marking fixed, important commits in the history of
your code base. Releases and versions are a good usage for tags. Here are some
example commands using tags:&lt;/p>
&lt;pre>&lt;code>git tag v1.0.0
git checkout -b 1.1-backport v1.1.0
git show v0.9.0
&lt;/code>&lt;/pre>&lt;h2 id="head">HEAD&lt;/h2>
&lt;p>The &lt;code>HEAD&lt;/code> commit is the current tip of the branch you are on. Similar to the
&lt;code>pwd&lt;/code> program, &lt;code>HEAD&lt;/code> tells you where you are. On its own, the useful command is
&lt;code>show&lt;/code> which will show you the details of the last commit you made.&lt;/p>
&lt;h1 id="modifiers">Modifiers&lt;/h1>
&lt;p>&lt;code>git&lt;/code> also allows you to specify commits by their relation to other commits. In
the &lt;code>git&lt;/code> data structure the only explicit relationship between commits is
child-parent. That is, the child commit knows its parent, but the parent does
not know its child/children. Many of the commands which show or span multiple
commits, such as &lt;code>log&lt;/code> or &lt;code>diff&lt;/code>, actually traverse the git tree to aggregate
their output.&lt;/p>
&lt;h2 id="first-parent">First Parent&lt;/h2>
&lt;p>The &lt;code>~&lt;/code> modifier follows a references first parent. For example, &lt;code>HEAD~&lt;/code>
references the first parent of the current commit. The first parent modifier can
be repeated: &lt;code>HEAD~~&lt;/code> references the first parent of the first parent of the
current commit. Also, a number can be specified for many generations: &lt;code>HEAD~5&lt;/code>
follows ancestors back 5 generations. Here are some other uses of the first
parent modifier:&lt;/p>
&lt;pre>&lt;code>// Move the second to last commit into the current branch
git cherry-pick bugs/broken-email-form~
// Modify some of the last 5 commits on your branch
git rebase HEAD~6
// Mark your current changes to fixup into two commits ago
git commit -a --fixup HEAD~
&lt;/code>&lt;/pre>&lt;h2 id="other-parents">Other Parents&lt;/h2>
&lt;p>Through merges, a commit can have multiple parents. The last modifier of the day
specifies any parent of a commit. The caret, &lt;code>^&lt;/code>, modifies the reference to
follow its first parent; the same as &amp;lsquo;~&amp;rsquo;. However, specifying a number along
with the caret follows subsequent parent commits. For example, reference the
last commit of a branch before it was merged into the current branch with
&lt;code>HEAD^2&lt;/code>.&lt;/p>
&lt;h1 id="bringing-it-all-together">Bringing it all together&lt;/h1>
&lt;p>Any of the above references can be combined with any number of modifiers to
express the exact commit succinctly. Here are some examples:&lt;/p>
&lt;pre>&lt;code>// See the 3rd to last commit from the last branch merged to the stable branch
git show stable^2~~~
// Pull second to last commit from version 2 into your current branch
git cherry-pick v2.0.0~
// Create a new branch 2 commits back from a known SHA1
git checkout -b branch-from-history abcd122~~
&lt;/code>&lt;/pre>&lt;p>The above examples might seem extremely specific, but knowing and using these
techniques can turn wasted time digging through git logs or copy and pasting
SHA1s into a quick one-liner. Impress your friends and co-workers, save your own
time, and begin thinking of your &lt;code>git&lt;/code> history relatively.&lt;/p>
&lt;p>Happy referencing!!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Working with Containers: beyond the tutorial</title><link>https://codegoalie.com/posts/working-with-containers/</link><pubDate>Thu, 04 Feb 2016 15:11:50 -0500</pubDate><guid>https://codegoalie.com/posts/working-with-containers/</guid><description>&lt;p>Over the past few months, I&amp;rsquo;ve been getting my hands dirty with containers,
Docker, and Kubernetes in an effort to get some hands on experience working
toward microservices. I&amp;rsquo;ve been building up a small application to generate and
serve Sudoku puzzles. My original goal was to see how many puzzles with unique
solution I could actually find, but that&amp;rsquo;s another post entirely. There are
already
&lt;a href="https://docs.docker.com/engine/userguide/basics/">many&lt;/a>
&lt;a href="http://kubernetes.io/v1.1/examples/guestbook-go/README.html">great&lt;/a>
&lt;a href="https://cloud.google.com/container-engine/docs/tutorials/guestbook">tutorials&lt;/a>
about
&lt;a href="https://docs.docker.com/">Docker&lt;/a>
and
&lt;a href="http://kubernetes.io/v1.1/docs/whatisk8s.html">Kubernetes&lt;/a>
on &lt;a href="https://cloud.google.com/container-engine/docs/">Google Container Engine&lt;/a>,
so I won&amp;rsquo;t go into getting started details here. This post is meant to explain
some of the stickier points that I had to pickup the hard way. I hope to save
you one or two headaches.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;h2 id="turn-key-kubernetes">Turn Key Kubernetes&lt;/h2>
&lt;p>Typically, I&amp;rsquo;ve used AWS for my infrastructure needs, but Google Container
Engine runs kubernetes for you and can spin up a new cluster with one command.
Again, there are many tutorials about the specifics but here are a few things I
didn&amp;rsquo;t know going in which would have been helpful.&lt;/p>
&lt;h3 id="keeping-costs-down">Keeping costs down&lt;/h3>
&lt;p>By default your cluster is composed of 3 &lt;code>n1-standard-1&lt;/code> instances. When just
getting started this is probably more than you need in both resources and cost.
Since I was more interested in playing with containers than messing with
compute engine instances (that&amp;rsquo;s the whole point of containers), I didn&amp;rsquo;t pay
any attention to them, but you should. It&amp;rsquo;s super easy and quick to change both
the number of instances and the instance types in your cluster.&lt;/p>
&lt;p>Google Container Engine clusters are built on the idea of &lt;a href="https://cloud.google.com/compute/docs/instance-groups/">instance
groups&lt;/a>, which
are just one or more instance defined by the same &lt;a href="https://cloud.google.com/compute/docs/instance-templates">instance
template&lt;/a>. The
template described the instances you want in your group with attributes like
machine type and base image, etc. In the Google Cloud Console, you can design
a new template right in the interface (pick a new machine type from a drop down)
and use smaller or larger instances.&lt;/p>
&lt;p>Scaling the number of instances in your cluster is even easier. Edit the
Instance Group and change the &amp;ldquo;Number of Instances&amp;rdquo; textbox value. You can even
enter 0 to stop getting billed for the instance time. This works great when you
don&amp;rsquo;t need the instances to be up 24/7 while just playing around.&lt;/p>
&lt;h3 id="persistent-storage">Persistent Storage&lt;/h3>
&lt;p>When a pod is restarted or rescheduled, it gets recreated from scratch. Anything
that was stored on disk is gone. This can cause unexpected issues. For example,
I was using redis for storing Sudoku puzzles and if the redis-master pod
restarted, I lost all contents of the database. This can be unexpected because
when running redis locally, the disk snapshots always remain even when
restarting the redis-server process. With containers, this is not the case. If
you need to store anything to disk that you care about, you&amp;rsquo;ll need to store
that in a volume backed by a Google Persistent Disk. Once again, there are many
tutorials on the specifics.&lt;/p>
&lt;h3 id="stuck-in-creatingcontainer">Stuck in CreatingContainer&lt;/h3>
&lt;p>When using a Google persistent disks, I was running into pods getting
rescheduled onto new nodes (instance), but the disk remained attached to the
previous node. Since Google Cloud persistent disks can only be attached to one
node at a time, this caused the pod to hang during creation and never start.
The quick fix to this is just detach the disk from it&amp;rsquo;s current node.
Kubernetes will attach it to the correct node for you.&lt;/p>
&lt;pre>&lt;code>gcloud compute instances detach-disk &amp;lt;instance-name&amp;gt; --disk &amp;lt;disk-name&amp;gt;
&lt;/code>&lt;/pre>&lt;p>There&amp;rsquo;s currently an effort to redesign the volumne mount/dismount system in
Kubernetes to address this issue. I also think that as redis was maxing out the
memory on the nodes and crashing, it was causing unnecessary havok on my
cluster.&lt;/p>
&lt;h2 id="restarting-a-pod">&amp;ldquo;Restarting&amp;rdquo; a pod&lt;/h2>
&lt;p>Early on my Sudoku generator was very naive and had exponention performance, so
it would get &amp;ldquo;stuck&amp;rdquo; trying to come up with new puzzles. Locally, I was just
restarting the process. But when I got it into the cluster, it wasn&amp;rsquo;t always
clear if it was broken, or just getting held up (I did fix this and went from
a puzzle every few minutes to a few puzzles a second). The great feature of
using replication controllers is that it will keep the specified number of pods
running. So to &amp;ldquo;restart&amp;rdquo; a pod that&amp;rsquo;s being managed by a replication controller,
just delete it. The replication controller will bring up a new one. If you
aren&amp;rsquo;t using a replication controller to manage your pods, do so.&lt;/p>
&lt;p>Hopefully these tips will make your container journey a little smoother.&lt;/p></description></item><item><title>New blog; New identity</title><link>https://codegoalie.com/posts/new-blog-new-identity/</link><pubDate>Thu, 04 Feb 2016 14:52:18 -0500</pubDate><guid>https://codegoalie.com/posts/new-blog-new-identity/</guid><description>&lt;p>You may have noticed a few changes around here. First, a new domain name:
codegoalie.com. I am moving away from ChrisMar035 in favor os something, as I
said on Twitter, that &amp;ldquo;better show my love of programming and blocking
vulcanized rubber disks with my body.&amp;rdquo; Also, my last name is not Mar.&lt;/p>
&lt;p>Along with Twitter, I&amp;rsquo;ll be moving other usernames to codegoalie shortly. I
already snagged &lt;a href="mailto:codegoalie@gmail.com">codegoalie@gmail.com&lt;/a>. Either way, if you see codegoalie or
chrismar035 anywhere, it&amp;rsquo;s probably me.&lt;/p>
&lt;p>&lt;strong>Update 2016-07027:&lt;/strong> I updated my Github username to
&lt;a href="https://github.com/codegoalie">@codegoalie&lt;/a>. If you&amp;rsquo;ve cloned some public
repos or were following me, change those links. I&amp;rsquo;ve also re-registered
@chrismar035 again and will be updating repos with links to the new
corresponding ones.&lt;/p></description></item><item><title>Useful command line expansions</title><link>https://codegoalie.com/posts/2014-08-17-useful-command-line-expansions/</link><pubDate>Mon, 25 Aug 2014 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2014-08-17-useful-command-line-expansions/</guid><description>&lt;p>Here&amp;rsquo;s a quick trick I&amp;rsquo;ve been using for a while, but have found that not many
others know about it. It&amp;rsquo;s a way to grab the arguments from the last command you
executed. Command line expansion allows you to &lt;a href="http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_04.html">do many
things&lt;/a>, but
today we&amp;rsquo;ll focus on just argument expansion.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>First to simply repeat the last command with &lt;code>!!&lt;/code>. This is most helpful when
needing to prefix a command; with something like &lt;code>sudo&lt;/code> or &lt;code>bundle exec&lt;/code>.&lt;/p>
&lt;pre>&lt;code>$ mv /really/long/path/with/more/dirs/file /another/deeply/nested/dir/structure
mv: cannot move `...' to `...': Permission denied
$ sudo !!
&lt;/code>&lt;/pre>&lt;p>Learn more about bang-bang on &lt;a href="https://sysadmincasts.com/episodes/32-cli-monday-history">episode 32 of sysadmin
casts&lt;/a>.&lt;/p>
&lt;p>Expanding on this concept, how about only part of the previous command? The
&lt;code>!$&lt;/code> history expansion expands to the last argument (or token) from the previous
command. Working off the previous example, if we now want to edit that freshly
moved file:&lt;/p>
&lt;pre>&lt;code>$ vim !$
&lt;/code>&lt;/pre>&lt;p>which expands to&lt;/p>
&lt;pre>&lt;code>$ vim /another/deeply/nested/dir/structure
&lt;/code>&lt;/pre>&lt;p>Quick and easy! There are many ways to use history expansion to get parts of the
previous (and others from history) command. &lt;code>!$&lt;/code> is by far the one I use the
most. You&amp;rsquo;ll do yourself a huge favor to commit that to muscle memory.&lt;/p>
&lt;p>To get an argument other than the last, you can use &lt;code>!:x&lt;/code> where &lt;code>x&lt;/code> is the (0
based) index of the arguemnt, or a range, or &lt;code>*&lt;/code> to get all the arguments.&lt;/p>
&lt;pre>&lt;code>$ vim /another/deeply/nested/dir/structure
$ git checkout -b features/laser-sharks
!:2 =&amp;gt; -b
!:0 =&amp;gt; git
!:$ =&amp;gt; features/laser-sharks
!:^ =&amp;gt; checkout
!:1-2 =&amp;gt; checkout -b
!:-2 =&amp;gt; git checkout -b
!:2-$ =&amp;gt; -b features/laser-sharks
!:* =&amp;gt; checkout -b features/laser-sharks
&lt;/code>&lt;/pre>&lt;blockquote>
&lt;p>ZSH power tip: Tapping &lt;code>tab&lt;/code> with any of these expansions in ZSH will expand
them inline to preview before executing.&lt;/p>
&lt;/blockquote>
&lt;p>Happy history-ing!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Delete multiple branches with git</title><link>https://codegoalie.com/posts/2014-06-25-delete-multiple-branches-with-git/</link><pubDate>Wed, 25 Jun 2014 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2014-06-25-delete-multiple-branches-with-git/</guid><description>&lt;p>When working on projects with multiple developers following a feature branching
workflow, you can end up with a lot of branch laying around. I&amp;rsquo;ve been trying to
optimize my branch cleanup workflow for a while now and had a big breakthrough
recently.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>&lt;strong>UPDATE:&lt;/strong> I now use a &lt;a href="https://github.com/pengwynn/dotfiles/blob/master/bin/git-sweep">shell
script&lt;/a>
which has the meat of the git-sweep functionality. Thanks to @pengwynn
for letting me steal that.&lt;/p>
&lt;p>Before we get to that, I must mention &lt;a href="http://lab.arc90.com/2012/04/03/git-sweep/">git-sweep&lt;/a>.
It has been revolutionary to keeping branches (both locally and remote) clean.
If you care at all about the output of &lt;code>git branch&lt;/code>, install that now.&lt;/p>
&lt;p>However, there&amp;rsquo;s another simpler trick I just recently discovered. Deleting
multiple local branches with one command.&lt;/p>
&lt;pre>&lt;code>$ git branch -D old-branch-1 old-branch-2
&lt;/code>&lt;/pre>
&lt;p>That&amp;rsquo;s it! Simply pass as many branches into &lt;code>branch -D&lt;/code> as you want and &lt;code>git&lt;/code>
will gladly delete them all.&lt;/p>
&lt;h3 id="but-why-do-you-need-this">But why do you need this?&lt;/h3>
&lt;p>I just said that &lt;code>git-sweep&lt;/code> cleans up local and remote branches after they are
merged into &lt;code>master&lt;/code>. So, why would we ever need to delete local branches? For
one, you might not merge branches into master, but still want to delete them.
But more likely, you&amp;rsquo;ll need to do this after pulling down a colleague&amp;rsquo;s branch
to review. Once you give them the green light, it&amp;rsquo;s best practice for them to
rebase onto &lt;code>master&lt;/code> (interactively to prevent accidentally merging &lt;code>!fixup&lt;/code>
commits). However, you will have one state of the branch locally, but they&amp;rsquo;ve
merged a different, rebased state. This is just enough of a change to fool
&lt;code>git-sweep&lt;/code>, and &lt;code>git&lt;/code> herself, into missing the fact that these branches are
the same. Luckily, there is a quick way to identify and remove those branches
too.&lt;/p>
&lt;p>Handily, &lt;code>git-branch&lt;/code> has a super verbose mode which can be shown with the
&amp;ldquo;double v&amp;rdquo; flag (&lt;code>-vv&lt;/code>). This displays the branch name, HEAD commit, remote
tracking branch, and HEAD commit message.&lt;/p>
&lt;pre>&lt;code>$ git branch -vv
* gh-pages 123456 [origin/gh-pages] Show new features on the project website
master 654321 [origin/master] Merge features/super-new-feature into master
&lt;/code>&lt;/pre>
&lt;p>Additionally, super verbose mode will also show us when a remote tracking branch
disappears (is deleted). Immediately following the tracking branch name, we&amp;rsquo;ll
notice a &amp;ldquo;gone&amp;rdquo;.&lt;/p>
&lt;pre>&lt;code>$ git branch -vv
* master 654321 [origin/master] Merge features/super-new-feature into master
old-feature 523621 [origin/old-feature: gone] Users can see the brand new feature
&lt;/code>&lt;/pre>
&lt;p>I like to &lt;code>grep&lt;/code> for that and filter out the branches which I don&amp;rsquo;t want to
delete. Basically, my whole cleanup procedure goes like this:&lt;/p>
&lt;pre>&lt;code>$ git branch -vv | grep gone]
old-feature-1 523621 [origin/old-feature-1: gone] Link to the new account page
old-feature-2 856956 [origin/old-feature-2: gone] Toggle turtle visibility with feature flag
$ git branch -D old-feature-1 old-feature-2
Deleted branch old-feature-1 (was 523621).
Deleted branch old-feature-2 (was 856956).
&lt;/code>&lt;/pre>
&lt;p>And there you have it, removing multiple branches in git with a bonus of
finding branches who&amp;rsquo;ve lost their remote tracks.&lt;/p>
&lt;p>Happy branching!!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Go Concurrency by Example</title><link>https://codegoalie.com/posts/2014-05-05-go-concurrency-2-examples/</link><pubDate>Sat, 14 Jun 2014 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2014-05-05-go-concurrency-2-examples/</guid><description>&lt;p>Recently I&amp;rsquo;ve been dabling in Go. I was lured in by the lore of a purposefully
simple language with amazing concurrency features. While that is true, I have to
admit that I stayed around for the documentation. &lt;a href="http://golang.org">Golang.org&lt;/a>
has a this great &lt;a href="http://tour.golang.org">Tour&lt;/a> which walks you through the
basics of the language through interactive examples and exercises. Secondly, the
&lt;code>godoc&lt;/code> command has a &lt;code>--server&lt;/code> flag which spins up essentially a local copy of
golang.org but the docs pages also include any locale packages you have pulled
down, or that &lt;strong>you&amp;rsquo;ve developed&lt;/strong>. Ok, enough gushing about Go documentation.&lt;/p>
&lt;p>The end of the tour talks about concurrency and has some exercises to help you
learn by doing. I found this method very compelling and came up with two
different methods for handling concurrency in Go; each suited for slightly
different use cases.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;h2 id="primer">Primer&lt;/h2>
&lt;p>If you aren&amp;rsquo;t familiar with concurrency in Go, this section is for you. I will
touch on some key points which are necessary to understand the examples below.
This is not an in-depth guide. I, myself, am still learning the ropes, but this
should cover us enough.&lt;/p>
&lt;p>The idomatic way to handle concurrency in Go is through something called a
&lt;code>goroutine&lt;/code>. A goroutine is something like a lightweight thread. They are cheap
to create and are ideal for small little jobs. Think of using goroutines as if
to say &amp;ldquo;Someone else go do this real quick.&amp;rdquo; A thread will go do your bidding
and your program can continue to execute.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;p>However, what about results from a goroutine? Many uses of concurrency involve a
collection phase where results from the concurrent tasks are reduced down to a
final result. This is where &lt;code>channels&lt;/code> come in. Think of a channel like a typed
Unix pipe. Data written in at one end can be read from the other end.&lt;/p>
&lt;p>Say we wanted to add all the digits from one to ten. We could let two goroutines
work on the first and half last each, then combine the individual results.&lt;/p>
&lt;pre>&lt;code>func summer(start int, end int, c chan int) {
sum := 0
for i := start; i &amp;lt;= end; i++ {
sum += i
}
c &amp;lt;- sum
}
func main() {
c := make(chan int)
go summer(1, 5, c)
go summer(6, 10, c)
// read the values from the channel
first_half := &amp;lt;- c
last_half := &amp;lt;- c
fmt.Println(first_half, last_half, first_half + last_half)
}
&lt;/code>&lt;/pre>
&lt;h2 id="worker-driven-concurrency">Worker driven concurrency&lt;/h2>
&lt;p>Concurrency with a known amount of return values, like the above example, is
fairly straightforward, but also quite contrived. A (slightly) more realistic
example would include a case where the exact number of values to be sent through
a channel is unknown. Reads from channels will wait until a value is available
(similarly writes also wait for an empty space in a channel). The &lt;code>range&lt;/code>
function will wait-read on a channel until the channel is closed. Closing a
channel should only be done on the writing end as trying to write to a closed
channel will &lt;code>panic&lt;/code>. This wait-read cycle allows us to setup a loop waiting for
values on a channel and break out of the loop once the channel is closed.&lt;/p>
&lt;p>In the example below we are calculating the decimal part of division in a
goroutine with the &lt;code>decimal_divide&lt;/code> function. Since we won&amp;rsquo;t know exactly how
many digits the decimal result will be we can wait on the digits and print them
as we get them. Once &lt;code>decimal_divide&lt;/code> completes the division, it signals &lt;code>main&lt;/code>
by closing the channel.&lt;/p>
&lt;pre>&lt;code>func decimal_divide(numerator, denominator int, c chan int) {
// do long division &amp;quot;by hand&amp;quot;
for ; numerator != 0; numerator = numerator % denominator {
numerator = numerator * 10
// send the next calculated digit back to main
c &amp;lt;- numerator / denominator
}
// all done; close the channel
close(c)
}
func main() {
numerator := 22
denominator := 7
// print the integer part of the result
fmt.Print(numerator / denominator, &amp;quot;.&amp;quot;)
// calculate the decimal part digit by digit
c := make(chan int)
go decimal_divide(numerator, denominator, c)
for digit := range c {
fmt.Print(digit)
}
fmt.Print(&amp;quot;\n&amp;quot;)
}
&lt;/code>&lt;/pre>
&lt;h2 id="multi-worker-concurrency">Multi-worker concurrency&lt;/h2>
&lt;p>In the example above, is fairly &amp;ldquo;linear&amp;rdquo; since the input of the next step is the
output of the previous. It isn&amp;rsquo;t straightforward to add additional working in
that case. However, let&amp;rsquo;s look at a &amp;ldquo;fan out&amp;rdquo; style of problem where we won&amp;rsquo;t
know the number of workers, nor the number of expected values. These kinds of
problems can be thought of as graph traversal problems.&lt;/p>
&lt;p>Suppose we had a list of cities each with their own list of immediately
neighboring cities which were connected by roads.&lt;/p>
&lt;pre>&lt;code>type cityList map[string][]string
var list = cityList{
&amp;quot;Cleveland&amp;quot;:
[]string{&amp;quot;Columbus&amp;quot;,
&amp;quot;Toledo&amp;quot;,
&amp;quot;Pittsburg&amp;quot;},
&amp;quot;Columbus&amp;quot;:
[]string{&amp;quot;Cincinati&amp;quot;,
&amp;quot;Cleveland&amp;quot;,
&amp;quot;Pittsburg&amp;quot;,
&amp;quot;Indinapolis&amp;quot;},
&amp;quot;Toledo&amp;quot;:
[]string{&amp;quot;Detroit&amp;quot;,
&amp;quot;Columbus&amp;quot;},
&amp;quot;London&amp;quot;:
[]string{&amp;quot;Bristol&amp;quot;,
&amp;quot;Sheffield&amp;quot;},
&amp;quot;Sheffield&amp;quot;:
[]string{&amp;quot;London&amp;quot;,
&amp;quot;Bristol&amp;quot;,
&amp;quot;Liverpool&amp;quot;}
}
&lt;/code>&lt;/pre>
&lt;p>Using this information and a starting city, you could generate a list all the
cities which could be visited by car. Each time a city&amp;rsquo;s neighbors are found,
a new goroutine can be used to fetch each neighbor&amp;rsquo;s neighbors. Since, we won&amp;rsquo;t
know, in advance, how many neighbors each city has or how many neighbors each
neighbor will have. We&amp;rsquo;ll have to do some housekeeping of on our own to make
sure everyone is accounted. Further, after we see a city for the first time,
there&amp;rsquo;s no reason to re-visit its neighbors again (and avoid graph loops).&lt;/p>
&lt;pre>&lt;code>func main() {
startingCity := &amp;quot;Cleveland&amp;quot;;
// keep track of cities we've visited to avoid infinite loops
fetchedCities := map[string]bool{startingCity: true}
// pass the neighbors after fetching
c := make(chan []string)
var fetchNeighbors = func(c chan []string, city string, list cityList) {
if neighbors, ok := list[city]; ok {
// if we've found the city on the map, send back the neighbors
c &amp;lt;- neighbors;
} else {
// otherwise send no neighbors back
// could be a good place for an error message, etc.
c &amp;lt;- []string{};
}
}
// track how many cities' neighbors are still to be fetched
// start at one because of the starting city
stillToFetch := 1;
// go fetch the first set of neighbors
go fetchNeighbors(c, startingCity, cityMap);
// while we are still fetching neighbors
for stillToFetch &amp;gt; 0 {
// read the neighbors from the channel
neighbors := &amp;lt;- c
// track that we've fetched a set of neighbors
stillToFetch--;
for _, city := range neighbors {
// if we haven't seen this city before
if !fetchedCities[city] {
// mark it as seen
fetchedCities[city] = true
// now we have one more city to fetch
stillToFetch ++
// fetch
go fetchNeighbors(c, city, cityMap);
// print out the name of the neighbor as visitable
fmt.Println(city);
}
}
}
}
&lt;/code>&lt;/pre>
&lt;p>As you can see we&amp;rsquo;ve had to use the &lt;code>stillToFetch&lt;/code> variable to keep track of
how many sets of neighbors to read from the channel. Each time we get a new set
of neighbors, we can subtract one to say that we&amp;rsquo;ve fetched neighbors. And on
the flip side, each new neighbor that we haven&amp;rsquo;t seen yet, we add one to say
that we have another set of neighbors to fetch.&lt;/p>
&lt;p>These examples show some basic techniques to work with concurrency in go and
many more techniques exist to create performant, robust applications. For full,
working examples please see &lt;a href="https://gist.github.com/chrismar035/a59c50329ab7c87033c2">the
gist&lt;/a>
to accompany this post. With the knowledge above, I hope you are inspired to
take advantage of the wonderful power amd simplicity of go concurrency. Please
link to any such work in the comments below.&lt;/p></description></item><item><title>Android Development: first impressions</title><link>https://codegoalie.com/posts/2013-11-08-android-development-first-impressions/</link><pubDate>Fri, 08 Nov 2013 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-11-08-android-development-first-impressions/</guid><description>&lt;p>As a web application developer working in a company full of mobile app
developers with a mobile focus and as a full time Android user, there&amp;rsquo;s a
natural gravity in my universe toward mobile apps and the power of the app plus
server backend paradigm. Naturally, I wanted to build my own app and really see
what it is like on the other side of the API.&lt;/p>
&lt;p>{% img left /images/android_first/car_icon.webp 150 150 Car Payment Calculaor %}
As with any new platform, language or environment, I read up extensively on the
Android ecosystem, poured over countless resources on design princiles and best
practices&amp;ndash;NOT. I jumped right in. Since I was shopping for a new car at the
time, I whipped up a quick and dirty [Car Payment
Calculator][6]. I mostly wanted to see the whole process of building an app
and deploying it to the Anroid market. I must say the process is extremely
simple and straightforward. However, the car payment app doesn&amp;rsquo;t really do
anything&amp;hellip;
&lt;!-- raw HTML omitted -->&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>A few form fields, a button and some quick math. No networking, no
server-side, no authorization, no fun. So, I set out on my second app: a push
notification service; something like [Boxcar][7] or [Notify My Android][9]. As
an Android user with a tablet and a phone, it&amp;rsquo;s really annoying to get all my
notifications twice. I could also scratch my own itch with some home
automation notifications as well as external services. But most importantly, I
knew this was something that I could actually build. This post isn&amp;rsquo;t about
Push Something (that will come later), so enough about that.&lt;/p>
&lt;p>I followed the [Google+ Sign-in for Android tutorial][8] and then the [GCM
setup tutorial][5] and finally a great [ListView tutorial][4]. Now I know that
each of these tutorials are meant to get you started and intentionally limit
the scope to only the topic at hand, but I must admit the app I ended up with,
while functional, seemed like a giant pile of spaghetti. I wasn&amp;rsquo;t sure why
certain pieces of code went where, what purpose different arguments provided
to many methods (is it the class context variable, &lt;code>getApplicationContext()&lt;/code>,
or am I passing the Activity with &lt;code>this&lt;/code>?). And even at two activities,
debugging was becoming a game of pick a file and scroll, scroll, scroll looking
for the correct group of statements.&lt;/p>
&lt;p>{% img right /images/android_first/uh_oh_android.jpg 400 200 Uh Oh Android %}
Now, I am not complaining or blaming the tutorials here. This is exactly what my
beloved Rails community does to new develoeprs as well. Dump all business logic
into the controller. No No. Move it into the model. NO NO. Service objects or
concerns and so on. Having been through that process and been at many stages
simultaneously, I am familiar and comfortable with the evolution of a Rails app.
However, being new to Android, I must admit I felt a bit lost and even
considered the possibility that Android apps were forever doomed to be a mess
of deeply nested ifs and try/catch blocks, 200+ character lines of code and
methods with a staggaring list of arguments.&lt;/p>
&lt;p>Thankfully, I am the only developer on my little side project and I had to take
a break from Android land to do a little catchup work on the server side. As a
budding Rails app itself, I found myself being able to see further ahead than
ever before in my Rails code and allow myself the luxury of writing code which
doesn&amp;rsquo;t make large design decisions too soon. Through experience, I am building
a solid and extensible base on which to build the rest of the app. Whoopty doo.
That&amp;rsquo;s my job 5 days a week. Then I thought, why not be able to utilize some
basic OOP principles in my Java code too? These tutorials were (as most are) a
starting point; a launch pad to get the juices flowing and enable the reader
to build something truly awesome.&lt;/p>
&lt;p>And that bings me to where I am at today, not rebuilding but refactoring. In the
same way I would enfore single responsibility and avoid &amp;ldquo;just throw that code
anywhere&amp;rdquo; in my Ruby code, I should do so in Java code as well. When I sat down
to write this post, I meant to document some frustration with my first Android
experiences and document my plan moving forward. But after getting this far in,
I think I&amp;rsquo;m seeing something else and one of the reasons I started
loving programming to begin with: there are always other ways to acheive the
desired results. [Give 10 developers the same requirements][3] and you&amp;rsquo;ll get
&lt;em>at least&lt;/em> 10 different programs. Some good, some not as good. And that is the
reality of software development. It&amp;rsquo;s easy to blame the language, or the
documentation, or the framework for your bad code, but at the end of the day
it&amp;rsquo;s &lt;em>&lt;strong>YOUR&lt;/strong>&lt;/em> code. Own it. Be proud of it. Don&amp;rsquo;t let language or framework
limitations bring down your work. You can be as awesome as you choose to be.
So don&amp;rsquo;t settle for &amp;lsquo;it works&amp;rsquo;; rest when &amp;lsquo;it&amp;rsquo;s aweosme!&amp;rsquo; Your future self
with thank your current self; instead of swearing at him. ;)&lt;/p>
&lt;p>&lt;a href="http://www.youtube.com/watch?v=l-gQLqv9f4o">{% img /images/android_first/The-Time-to-Be-Awesome-is-Now-Kid-President1.jpg %}&lt;/a>&lt;/p>
&lt;p>[2]:
[3]: &lt;a href="http://exercism.io/">http://exercism.io/&lt;/a>
[4]: &lt;a href="http://www.vogella.com/articles/AndroidListView/article.html">http://www.vogella.com/articles/AndroidListView/article.html&lt;/a>
[5]: &lt;a href="http://developer.android.com/google/gcm/gs.html">http://developer.android.com/google/gcm/gs.html&lt;/a>
[6]: &lt;a href="https://play.google.com/store/apps/details?id=com.chrismar035.carpaymentcalculator">https://play.google.com/store/apps/details?id=com.chrismar035.carpaymentcalculator&lt;/a>
[7]: &lt;a href="http://boxcar.io">http://boxcar.io&lt;/a>
[8]: &lt;a href="https://developers.google.com/+/mobile/android/sign-in">https://developers.google.com/+/mobile/android/sign-in&lt;/a>
[9]: &lt;a href="http://www.notifymyandroid.com">http://www.notifymyandroid.com&lt;/a>&lt;/p></description></item><item><title>Commit Message Starters</title><link>https://codegoalie.com/posts/2013-05-14-commit-message-starters/</link><pubDate>Tue, 14 May 2013 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-05-14-commit-message-starters/</guid><description>&lt;p>As I&amp;rsquo;ve been working in git and crafting my commits with rebase
working toward creating pull requests which are easy to read,
review, and comment, I&amp;rsquo;ve been noticing myself fall into
habits of naming commit messages similarly which contain code to
acheive similar ends. Further, when I struggle to find the correct
words for a commit message, it&amp;rsquo;s often easier to being with
a familiar word to get things flowing.&lt;/p>
&lt;p>{% img right /images/readthesource.jpg 460 276 Read the source %}
Over the past few months, I&amp;rsquo;ve also had the pleasure of working
with some great developers. As such, I&amp;rsquo;ve been afforded the
opportunity to review a lot of their code. If there is one thing I recommend
to all developers, from novice to expert, it&amp;rsquo;s &lt;em>&lt;strong>read code&lt;/strong>&lt;/em>.
Your own, your friend&amp;rsquo;s, strangers, projects you admire, anything you can get
your hands on.
Not only will it enlighten you to how others write code, new coding patterns
and syntax, but it will empower you to be able to figure out how the code you
use works and how to fix it.&lt;/p>
&lt;p>As a quick aside, I was able recently to dig into the Ruby source code, even
into the C, to discover exaclty what was happening with Range bracket
operator access on an empty Array. It felt great to be able to see how Ruby
herself was implemented and know exactly why my code worked; to go beyond &amp;ldquo;well,
it worked in irb so it must be correct.&amp;rdquo;&lt;/p>
&lt;p>The great thing about reviewing pull requests is that I am able to open
discussions with the authors and inquire as to why they made certain decisions
and what their motiviations were for writing certain code. Also, it gave me a
chance to see code which was not polished and final. Thereby, recognizing
anti-patterns and less than best practices.&lt;/p>
&lt;p>Coming back to the topic of this post. These anti-patterns and less than best-
practices extend to commit messages as well. Below I&amp;rsquo;ve listed some of the dos
and don&amp;rsquo;ts which I have started to use in my everyday committing.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;h2 id="what-i-like">What I like&lt;/h2>
&lt;p>These words I often use to start commit messages which make some common
changes in the codebase.&lt;/p>
&lt;h3 id="ensure">Ensure&lt;/h3>
&lt;pre>&lt;code>Ensure phone numbers strip extraneous characters
Ensure deactivation resets users' api tokens
&lt;/code>&lt;/pre>
&lt;p>I use &amp;ldquo;Ensure&amp;rdquo; to start a commit which contains tests for my code. These commits
are often the first commits in a pull request, especially if I am using TDD. A
whole commit just for test? Surely, that&amp;rsquo;s overkill? There are two reasons I
like to encapsulate tests into their own commits.&lt;/p>
&lt;p>{% img left /images/ensure.jpg Ensure %} First, this standardization allows
others to know which commits will define
and test the behavior I aim to implement. We all know that tests can be a great
documentation tool and prefixing commit messages which contain &amp;ldquo;Ensure&amp;rdquo; allow
people to find them easier.&lt;/p>
&lt;p>Second, if the tests are in their own commit(s) &lt;em>before&lt;/em> the implementation
commits, it&amp;rsquo;s very easy for a reviewer to simulate the red-green test cycle.
Either through a &lt;code>checkout&lt;/code> or selecting a commit to be &amp;lsquo;editied&amp;rsquo; in an
interactive rebase, the state of the repo &lt;em>after&lt;/em> the tests are written, but
&lt;em>before&lt;/em> the task is implemented can be recreated. Tests are run at that point
and a reviewer can cofirm that the new tests do indeed fail. The rebase is
continued and the tests can be run again. This time they succeed. A review has
very simply been able to confirm that the tests are working correctly.&lt;/p>
&lt;h3 id="boyscout">Boyscout&lt;/h3>
&lt;pre>&lt;code>Boyscout the user model specs
Boyscout line lengths in the sessions controller
&lt;/code>&lt;/pre>
&lt;p>Boyscouting refers to updating the format and/or style of code without changing
the behavior. I picked it up from a presentation about code styles which I now
cannot find to reference here. However, I did find this
&lt;a href="http://www.cimgf.com/zds-code-style-guide/">written reference&lt;/a> online.
The term refers to a famous quote by the founder of the Boyscouts,
Robert Stephenson Smyth Baden-Powell,
&lt;a href="http://www.scouting.org/scoutsource/CubScouts/Parents/About/history.aspx">&amp;ldquo;Try and leave this world a little better than you found
it&amp;rdquo;&lt;/a>.&lt;/p>
&lt;p>Continuing to think of the reviewer when committing, just by looking at the
message, expectations are set that this commit does not change functionality,
only formatting. Review of a change like that is much easier when you know that
nothing is supposed to happen.&lt;/p>
&lt;h3 id="migrate">Migrate&lt;/h3>
&lt;pre>&lt;code>Migrate a unique index for user email addresses
Migrate timestamp columns onto the comments table
&lt;/code>&lt;/pre>
&lt;p>As you might have guessed, I use &amp;ldquo;Migrate&amp;rdquo; to start commit messages which
contain migrations. As a best practice, we like to isolate migrations to their
own commits containing only the migration class definition and the changes to
the schema file. It also can be useful, but not 100% reliable, to quickly see
if a particular set of commits has migrations; say before a deploy or after
pulling down the latest changes. Again, along the theme of setting expectations
for others.&lt;/p>
&lt;h2 id="what-i-avoid">What I avoid&lt;/h2>
&lt;p>These words often start a commit message off on the wrong foot. Being very
generic on their own, they often lead to very generic commit messages.&lt;/p>
&lt;h3 id="fixed">Fixed&lt;/h3>
&lt;pre>&lt;code>Fixed broken specs
Fixed editing a user
&lt;/code>&lt;/pre>
&lt;p>{% img right /images/fixedit.jpg FIXED!!! %}
First off, past tense should be avoided in commit messages. The rule of thumb
is to write a commit message as if you were commanding the code to take an
action. Secondly, commit messages should describe the reason for a change, not
the change itself. If someone would like a know what the changes were, they
need to do no more that a &lt;code>git show&lt;/code> or click in github. However, to reason
why the change was made or what it is attempting to do is much harder to
determine from the code itself. Great commit messages can be the difference
between &lt;code>Fixed broken specs&lt;/code> and &lt;code>Activate users after registration in user specs&lt;/code>.&lt;/p>
&lt;h3 id="added">Added&lt;/h3>
&lt;pre>&lt;code>Added new Order model
Added full_name method to User model
&lt;/code>&lt;/pre>
&lt;p>&amp;ldquo;Added&amp;rdquo; is not strictly a not so best practice, but I see it go awry more often
than I see it used for good. Again, &amp;ldquo;added&amp;rdquo; has a great tendnecy to lean toward
&lt;em>what&lt;/em> happened instead of &lt;em>why&lt;/em> did it happen. I, myself, sometimes write a
commit starting with &amp;ldquo;added&amp;rdquo;. For example, &lt;code>Added jquery javascript library&lt;/code>
at first glance seems perfectly reasonable. I didn&amp;rsquo;t fix anything. I didn&amp;rsquo;t
write a great new feature. I just added jQuery. However, when I find myself
with a commit message like this, I go through the practice of adding &amp;ldquo;in order
to&amp;rdquo; and then trying to finish the commit message. &lt;code>Added jquery javascript library&lt;/code> in order to &lt;code>provide DOM manipulation methods&lt;/code>. Put it
together for &lt;code>Provide DOM manipulation methods with jQuery&lt;/code>. Now, I&amp;rsquo;ve given
some context to why I added jQuery instead of simply restating the code changes
in the commit message.&lt;/p>
&lt;p>That&amp;rsquo;s all I have for now. Please comment below with your commit message best
practices and tendencies. I bet you guys have some great tips too!&lt;/p>
&lt;p>See ya soon and keep committing!&lt;/p>
&lt;p>&amp;ndash;Chris&lt;/p></description></item><item><title>Better pull requests with git --autosquash</title><link>https://codegoalie.com/posts/2013-04-04-better-pull-requests-with-autosquash/</link><pubDate>Thu, 04 Apr 2013 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-04-04-better-pull-requests-with-autosquash/</guid><description>&lt;p>&lt;strong>UPDATE (Jun 7, 2013):&lt;/strong> I created an &lt;a href="http://ascii.io/a/3467">ascii.io video demo of
autosquash&lt;/a> for your viewing pleasure.&lt;/p>
&lt;p>Pull requests are an extremly crucial part of our workflow at Mobile
Defense. We pride ourselves on producing quality code and we do not
subscribe to the git-blame &amp;ldquo;I didn&amp;rsquo;t write it&amp;rdquo; culture. We all take
responsibility for all the code we produce, as a team. As such, being
able to review our code efficiently and thoroughly &lt;strong>before&lt;/strong> it gets
into &lt;code>master&lt;/code> is a goal we are constantly looking to improve upon.&lt;/p>
&lt;p>A somewhat paradox in reviewing code arises when the need for reviewers
to see the updates based on their feedback quickly and efficiently and
for the developer to be able to &amp;lsquo;fixup&amp;rsquo; their branch before merging to
ensure the code enters &lt;code>master&lt;/code> as cleanly as possible. That&amp;rsquo;s where
git-rebase comes in.&lt;/p>
&lt;p>Rebase is an extremely powerful tool in the git toolbelt. Combine
commits, edit commits in-place, rewrite history, etc. It&amp;rsquo;s especially
great for cleaning up your topic branches before submitting for code
review. However, remembering which commits need to be squashed into which
can be tricky especially when being the reviewee and the reviewer on
multiple pull requests daily. Well, it turns out git already has a really
clever, built-in way to organize and automate the branch cleanup process.
It is perfectly suited for making changes based on pull request feedback.
It&amp;rsquo;s called autosquash.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Here was a typical pull request workflow:&lt;/p>
&lt;ol>
&lt;li>Code up a feature; commit early and often.&lt;/li>
&lt;li>Push to github and open a pull request.&lt;/li>
&lt;li>Do a quick self-review of my code.&lt;/li>
&lt;li>Ask others to review my code.&lt;/li>
&lt;li>Add temporary commits in response to comments.&lt;/li>
&lt;li>When the branch is approved for merge, rebase and fixup the
temporary commits into the original commits.&lt;/li>
&lt;li>Merge the branch.&lt;/li>
&lt;/ol>
&lt;p>As you might have experienced or noted in the workflow above, how do you
keep organized and remember which temporary commits should be squashed
into which original commits? The problem I ran into time and time
again was that as soon as I started an interactive rebase I would be
unable to remember exactly which commits needed to be changed, squashed,
or fixedup. So, I had been developing some commit message conventions for
temporary commits.&lt;/p>
&lt;p>For example, a commit which I knew was incomplete work or needed to be
looked at again would have it&amp;rsquo;s message prefixed with an excalmation
mark.&lt;/p>
&lt;pre>&lt;code>! Possible logic error in the complex_redirect logic
&lt;/code>&lt;/pre>
&lt;p>Further, commits which I knew I wanted to squash into previous commits
would be prefixed with four hyphens and have a message which I would be
able to make sense of when editing the rebase todo file.&lt;/p>
&lt;pre>&lt;code>---- into the first set of unit tests
&lt;/code>&lt;/pre>
&lt;p>This worked fairly well as long as I left myself good notes. But, surely
there must be a better way!&lt;/p>
&lt;h2 id="enter-autosquash">Enter autosquash&lt;/h2>
&lt;p>The &lt;code>--autosquash&lt;/code> flag on git-rebase is exactly what I was looking
for. During an interactive rebase, it processes messages to stage squashes
and fixups. These messages are setup with flags on git-commit at commit
time, which is when you are most likely to know what you ultimately
intend to do with commits. Further, it works via the commit message
so it&amp;rsquo;s easy for humans to understand as well!&lt;/p>
&lt;p>Say you have a feature branch with three commits: (viewing git logs with
the &lt;a href="https://codegoalie.com/2013/02/08/help-i-lost-a-commit-from-days-ago/#lg">incredibly awesome lg
alias&lt;/a>)&lt;/p>
&lt;pre>&lt;code>* cdaa049 (HEAD, features/new_hotness) Add new hotness to UI (66 seconds ago) &amp;lt;Chris Marshall&amp;gt;
* e14aa92 Implement new hotness backend (2 minutes ago) &amp;lt;Chris Marshall&amp;gt;
* 293070e Ensure new hotness works (2 minutes ago) &amp;lt;Chris Marshall&amp;gt;
* de72adc (origin/master, origin/HEAD, master) Add git internals meetup talk slides (6 months ago) &amp;lt;Chris Marshall&amp;gt;
&lt;/code>&lt;/pre>
&lt;p>Now let&amp;rsquo;s say you get a review comment on the commit for the tests
(&amp;lsquo;Ensure &amp;hellip;') which asks to add a test for a missed edge case.&lt;/p>
&lt;p>So we will code up our edge case fix and as we commit, we&amp;rsquo;ll add the
flag to specify what we ultimately will do with the commit.&lt;/p>
&lt;p>Git-commit has two such flags: &lt;code>--fixup&lt;/code> and &lt;code>--squash&lt;/code> with each of these
we will specify the commit &lt;strong>into which&lt;/strong> we want to fixup or squash. In
our example, we want to fixup into the first commit after master:
&lt;code>293070e&lt;/code>.&lt;/p>
&lt;p>We can do that with:&lt;/p>
&lt;pre>&lt;code>$ git commit --fixup=293070e
&lt;/code>&lt;/pre>
&lt;p>Which will produce a commmit with a message of:&lt;/p>
&lt;pre>&lt;code>fixup! Ensure new hotness works
&lt;/code>&lt;/pre>
&lt;p>A commit message formatted this way tells git-rebase (with &lt;code>--autosquash&lt;/code>)
to fix the patch in this commit up into the commit with the message &amp;ldquo;Ensure
new hotness works&amp;rdquo;. The power of using the commit message instead of SHA1
to identify commits is that this will work even after a rebase without
&lt;code>--autosquash&lt;/code> (e.g. pulling in lastest master changes).&lt;/p>
&lt;p>Here&amp;rsquo;s how it would look in github:&lt;/p>
&lt;p>&lt;img src="https://codegoalie.com/images/autosquash/fourth-commit.png" alt="Screenshot of Github PR with fixup commit linked incomment">&lt;/p>
&lt;p>&lt;em>Obviously, don&amp;rsquo;t have conversations with
yourself on github. This is purely educational ;)&lt;/em>&lt;/p>
&lt;hr>
&lt;p>Now the fun part! When the pull request is approved, you can rebase with
autosquash (and interactive) and watch as git does the work for you:&lt;/p>
&lt;pre>&lt;code>$ git rebase master -i --autosquash
&lt;/code>&lt;/pre>
&lt;p>Produces the rebase todo file:&lt;/p>
&lt;pre>&lt;code>pick 293070e Ensure new hotness works
fixup 3877fdf fixup! Ensure new hotness works
pick e14aa92 Implement new hotness backend
pick cdaa049 Add new hotness to UI
&lt;/code>&lt;/pre>
&lt;p>Simply save it and git rebases the branch as if you had changed the file
yourself. You can then merge and have a beer for all your efforts!&lt;/p>
&lt;h2 id="automating-autosquash">Automating autosquash&lt;/h2>
&lt;p>Adding the long &lt;code>--autosquash&lt;/code> flag all the time can get tiresome. Luckily,
you can add the &lt;code>rebase.autosquash&lt;/code> config value to run autosquash
automatically for every interactive rebase.&lt;/p>
&lt;pre>&lt;code>$ git config --global rebase.autosquash true
&lt;/code>&lt;/pre>
&lt;p>If no commits with the &lt;code>fixup!&lt;/code> or &lt;code>squash!&lt;/code> syntax are found, the rebase
continues normally. To override the autosquash default value, simply pass
the &lt;code>--no-autosquash&lt;/code> flag to rebase.&lt;/p>
&lt;p>Happy squashing!!&lt;/p>
&lt;p>&amp;ndash;Chris&lt;/p></description></item><item><title>Oh my! What large hot fixes you have</title><link>https://codegoalie.com/posts/2013-03-16-oh-my-what-large-hot-fixes-you-have/</link><pubDate>Tue, 26 Feb 2013 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-oh-my-what-large-hot-fixes-you-have/</guid><description>&lt;p>We&amp;rsquo;ve all been there: just finished a nice new feature, deployed it out
to production only to find that you&amp;rsquo;ve completely overlooked an edge
case or use case which is now totally breaking your app. Sometimes you
have to push a big hot fix. It has to get in immediately. It can&amp;rsquo;t wait
for writing correct tests or other better abstractions and
implementations. What to do? What to do?&lt;/p>
&lt;p>Well, there&amp;rsquo;s the common way of hacking as fast as you can until you&amp;rsquo;re
pretty sure the bug is fixed, commit everything in a big &amp;ldquo;Avert
crisis!!&amp;rdquo; commit. However, I think we can do better.&lt;/p>
&lt;p>First step checkout a new branch at your current &amp;lsquo;production,&amp;rsquo; or
similar. Call it production_pre_fix. Don&amp;rsquo;t check it out or work on it,
just leave it there as a placeholder.&lt;/p>
&lt;pre>&lt;code>$ git checkout production
$ git branch production_pre_fix
&lt;/code>&lt;/pre>
&lt;p>Now for the fun part: hack away! But, follow your usual development
practices of committing early and often. Refactor a method. Commit.
Add some if checks for edge cases. Commit. Get the shit fixed and
deployed. Go on. I&amp;rsquo;ll wait.&lt;/p>
&lt;p>Ok, alarms are quiet now and you&amp;rsquo;re done breaking shit? Good. Now
let&amp;rsquo;s get to work on the real fix. I&amp;rsquo;m glad your hacked together bunch
of duct tape fix is holding, but let&amp;rsquo;s not leave things like that. I
know you and I bet you&amp;rsquo;ve got some good work there. You probably don&amp;rsquo;t
want to just throw it all away. That&amp;rsquo;s cool. Why don&amp;rsquo;t we use the duct
tape as a basis for the permanent fix? Here&amp;rsquo;s how:&lt;/p>
&lt;p>First, get a clean branch off master&lt;/p>
&lt;pre>&lt;code>$ git checkout master
$ git checkout -b bugs/prod_fix
&lt;/code>&lt;/pre>
&lt;p>Then, write tests to account for your new found bugs.&lt;/p>
&lt;p>Next, cherry pick your current fix onto this branch.&lt;/p>
&lt;pre>&lt;code>$ git cherry-pick production_pre_fix..production
&lt;/code>&lt;/pre>
&lt;p>You may have noticed I passed two branch names with two periods in between to cherry-pick. What the fuck, right? Well, as we all know, two commit SHA1s separated by two periods is a range of commits. For exmple, &lt;!-- raw HTML omitted -->2e45f..34b79&lt;!-- raw HTML omitted -->. You are saying that you&amp;rsquo;d like to use all the commits starting at &lt;!-- raw HTML omitted -->34b79&lt;!-- raw HTML omitted --> and following parent links back until you reach &lt;!-- raw HTML omitted -->2e45f&lt;!-- raw HTML omitted -->.&lt;/p>
&lt;p>But I&amp;rsquo;ve used brach names here, which are just human friendly shortcuts
for SHA1s. Remember branch names are basically pointers to a particular
commit. They can be used in any git command which would otherwise take
a commit SHA1. Add that to the fact that cherry-pick can take a range
and suddenly your doing some pretty powerful stuff with a pretty simple
command. Go you!&lt;/p>
&lt;p>Now a little housekeeping,&lt;/p>
&lt;ul>
&lt;li>Make sure your fix actually passes your tests.&lt;/li>
&lt;li>Refactor and make your fix nice. Rebase, as necessary.&lt;/li>
&lt;li>Start pull request and get the feature merged back into master.&lt;/li>
&lt;/ul>
&lt;p>Then we need to reset your temp fix in production. Like this:&lt;/p>
&lt;pre>&lt;code>$ git checkout production
$ git reset --hard production_pre_fix
$ git branch -d production_pre_fix
$ git push -f
&lt;/code>&lt;/pre>
&lt;p>Woah woah woah! No, I didn&amp;rsquo;t. I just force pushed a non-topic branch.
Isn&amp;rsquo;t that a big no-no? Usually, yes and I would expect to be taken out
back and beaten until I learned my lesson. However, until I&amp;rsquo;m told of
a good reason otherwise: production or other released branches are not
shared among developers. They are an exact representation of what is
to be deployed next to the environment they represent.&lt;/p>
&lt;p>Why aren&amp;rsquo;t release branches an accurate representation of what is
currently deployed to the environment they represent? Because if you
want to know that, look at the environment. There&amp;rsquo;s no need for
duplicate information. A branch like production should be curated and
hold what will be deployed next to production. You might not do that
curating and updating until moments before the deploy. But for all
that time until you deploy, if you had to emergency deploy, whatever
is in the branch will be deployed.&lt;/p>
&lt;p>Back to business, we&amp;rsquo;ve reset production back to not include the duct
tape. Now it&amp;rsquo;s time to merge master and our fix up to it.&lt;/p>
&lt;pre>&lt;code>$ git checkout production
$ git merge master
&lt;/code>&lt;/pre>
&lt;p>Congratulations! You&amp;rsquo;ve not only saved your company from sure collapse
by fixing a huge production bug. But you&amp;rsquo;ve also reconciled your
technical debt and prevented other developers behind you from cursing
your name at the duct tape-y hacks you introduced to the code base.
That deserves a beer!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Zeus gem error: "panic: runtime error: invalid memory address or nil pointer dereference"</title><link>https://codegoalie.com/posts/2013-03-16-zeus-gem-error-panic-runtime-error-invalid-memory-address-or-nil-pointer-dereference/</link><pubDate>Tue, 12 Feb 2013 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-zeus-gem-error-panic-runtime-error-invalid-memory-address-or-nil-pointer-dereference/</guid><description>&lt;p>I was getting this error and the &lt;!-- raw HTML omitted -->excellent Zeus rails environment loader gem&lt;!-- raw HTML omitted --> was crashing making it a huge bummer to dev.&lt;/p>
&lt;p>Luckily, I found a fix in &lt;!-- raw HTML omitted -->one of the open issues on the project&lt;!-- raw HTML omitted -->.&lt;/p>
&lt;p>It was easy to fix, just run a bundle install to add the missing gems:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Easy as that. Hope this helps someone else!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Help! I lost a commit from days ago!!!</title><link>https://codegoalie.com/posts/2013-03-16-help-i-lost-a-commit-from-days-ago/</link><pubDate>Fri, 08 Feb 2013 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-help-i-lost-a-commit-from-days-ago/</guid><description>&lt;p>Oh no! I&amp;rsquo;m screwed! Better try to remember what work I did and recreate
it&amp;hellip; :( J/K! This is git! Of course there&amp;rsquo;s a slick way to recover what
you lost. Here&amp;rsquo;s my situation: I was working on a feature branch happily
coding away. Finished the feature, rebased it quickly to fix a typo and
then merged it into master. All&amp;rsquo;s well in my world. However, that was
days ago and today I just realized that I accidentally removed one of my
commits from the feature branch while I was working on it. No worries.
Here&amp;rsquo;s how I got the commit back with relative ease.&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->
First, let me give you a lay of the land. I use the incredible git lg alias.&lt;/p>
&lt;pre>&lt;code>lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&amp;lt;%an&amp;gt;%Creset' --abbrev-commit --
&lt;/code>&lt;/pre>
&lt;p>Seriously, steal that now. Use it a thousand times a day. I wish I
could attribute it to the original author, but I have since forgotten
where I originally saw it. At any rate, every few weeks I see it posted
anew on a different site.&lt;/p>
&lt;p>Anyway, here&amp;rsquo;s where I was at before the recovery:&lt;/p>
&lt;script type="text/javascript" src="https://gist.github.com/4738855.js?file=lost_commit.sh">&lt;/script>
&lt;p>Well&amp;hellip;now what? Redo all that work in the lost commit. Nah. Reflog to the rescue! Git&amp;rsquo;s &lt;!-- raw HTML omitted -->reflog&lt;!-- raw HTML omitted --> is a (by default) 90 day record of everywhere your HEAD ref was pointing. Anytime you do a checkout, create branch, commit, rebase; anytime the &amp;lsquo;current&amp;rsquo; commit of your working directory changes, the reflog gets a new entry. You can think of the reflog as a record of what you&amp;rsquo;ve been doing. If you&amp;rsquo;ve had it in your working directory in the past 30 days, it&amp;rsquo;s in the reflog.&lt;/p>
&lt;p>Remember what the commit message was for my lost commit? Nice! We can easily grep for it:&lt;/p>
&lt;pre>&lt;code>chrismar035:super_sweet_rails_app(master) $ git reflog | grep &amp;quot;commit message&amp;quot;
&lt;/code>&lt;/pre>
&lt;p>What&amp;rsquo;s that? I didn&amp;rsquo;t tell you the commit message for the lost commit? Well, I don&amp;rsquo;t remember either! Now we are screwed.&lt;/p>
&lt;p>Gotcha again! We can still find it. We can use the ancient art of looking for what we lost. It&amp;rsquo;s easy. Simply do a &lt;!-- raw HTML omitted -->git reflog&lt;!-- raw HTML omitted --> and you will see a list of everywhere you&amp;rsquo;ve been:&lt;/p>
&lt;script type="text/javascript" src="https://gist.github.com/4738855.js?file=reflog.sh">&lt;/script>
&lt;p>AHA! Not only did you find the &lt;!-- raw HTML omitted -->LOST COMMIT!!!&lt;!-- raw HTML omitted -->, but we can also look at what happened too. Apparently, on a mad dash to get the feature merged before going out and getting my drink on with some chaps, I accidentally rebased my commit right out of the project. Damnit.&lt;/p>
&lt;p>Oh well, at least you found it for me. Thanks. Now, we&amp;rsquo;ve only got one real choice to fix this. We have to cherry-pick the commit out of the reflog back into master. Because I&amp;rsquo;ve already merged my feature branch into master and pushed it, I cannot go back and rebase or otherwise edit that pushed history of master. I&amp;rsquo;ve got to bite the bullet and add a commit straight onto master&amp;hellip; Everyone screws up once in a while.&lt;/p>
&lt;p>In the reflog, there are two ways to reference the commit: the SHA1 and the &lt;!-- raw HTML omitted -->HEAD@{integer}&lt;!-- raw HTML omitted --> reference. Either one will work. I like the SHA1 because I can double click in the terminal and it gets correctly highlighted for copying. Copy it and we&amp;rsquo;ll paste it back into the command line with:&lt;/p>
&lt;pre>&lt;code>chrismar035:super_sweet_rails_app(master) $ git cherry-pick 9a7de0e
&lt;/code>&lt;/pre>
&lt;p>&lt;code>lg&lt;/code> that again and see how we look:&lt;/p>
&lt;script type="text/javascript" src="https://gist.github.com/4738855.js?file=all_fixed.sh">&lt;/script>
&lt;p>Nice! Now, notice that the SHA1 changed from what you copied out of the reflog. Remember, commit SHA1s are based on their content (files, dirs, commit messages and meta data) AND their parent(s). So, if you change the parent of the commit, you change the commit (Same reason all the SHA1s change when you rebase). In reality, the commit you cherry-picked is duplicated on to the branch you cherry-pick it into. However, in our case that&amp;rsquo;s exactly what we wanted, because I messed up and deleted the commit in the first place.&lt;/p>
&lt;p>Nice work! Push and have a beer!! :)&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>SuperBowl Commercial Bingo Card Generator</title><link>https://codegoalie.com/posts/2013-03-16-superbowl-commercial-bingo-card-generator/</link><pubDate>Sun, 05 Feb 2012 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-superbowl-commercial-bingo-card-generator/</guid><description>&lt;p>Everybody loves the SuperBowl commercials! Last year, I hacked up a script to randomly generate items to create your own bingo cards. This year, I improved the script to actually generate the cards as a PDF file based on an excel sheet of bingo items.&lt;/p>
&lt;p>Here it is:&lt;/p>
&lt;script type="text/javascript" src="https://gist.github.com/812932.js">&lt;/script>
&lt;p>Check out &lt;a href="https://gist.github.com/chrismar035/812932#comment-81123">the second comment for more info&lt;/a>.&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Ruby on Rails/ActiveSupport: To delegate or not to delegate</title><link>https://codegoalie.com/posts/2013-03-16-ruby-on-rails-slash-activesupport-to-delegate-or-not-to-delegate/</link><pubDate>Fri, 12 Aug 2011 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-ruby-on-rails-slash-activesupport-to-delegate-or-not-to-delegate/</guid><description>&lt;p>This is an account of my adventure with delegation from problem to apparent solution to bug in ActiveSupport to you&amp;rsquo;re doing it wrong!&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->TL;DR&lt;!-- raw HTML omitted -->&lt;/p>
&lt;p>Delegation is used when you want to forward a method call from on class/model to an associated class/model. The &lt;!-- raw HTML omitted -->Ruby on Rails Guides&lt;!-- raw HTML omitted --> use the example of a User model which has a Profile associated with it. This is a great example with a little subtlety which I overlooked. If you aren&amp;rsquo;t famaliar with delegation, go ahead and get yourself learned. I won&amp;rsquo;t wait for you though. This is text just come back when you&amp;rsquo;re up to speed.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;pre>&lt;code># app/views/drivers/show.html.haml
.truck_number
-if @driver.truck
= @driver.truck.number
-else
Not Driving any Truck
&lt;/code>&lt;/pre>
&lt;p>NBD. Here&amp;rsquo;s our problem:&lt;/p>
&lt;h3 id="the-problem">The Problem&lt;/h3>
&lt;p>As when any good application which acts as a font-end for a database, we track history on all edits, etc. So, when we update the Driver in a Truck, we want to add history for the Truck and the Driver. If the Driver is already in another Truck we want to show, in his history, that he moved from Truck 1001 into Truck 2002. We&amp;rsquo;ll say we have a create_history method included into our Entity classes whose declaration looks something like:&lt;/p>
&lt;pre>&lt;code>def create_history(attribute, prev_value, new_value)
&lt;/code>&lt;/pre>
&lt;p>So, we want to call something like:&lt;/p>
&lt;pre>&lt;code>@driver.create_history('Truck Number', @driver.truck.number, @new_truck.number)
&lt;/code>&lt;/pre>
&lt;p>Jackpot! Works perfectly. We get the old Truck number (1001) from the @driver instance and the new Truck number (2002) directly from the @truck instance. We are geniuses.
Hold the phone though. What if that Driver didn&amp;rsquo;t have a previous truck&amp;hellip; Spoiler Alert: &lt;!-- raw HTML omitted -->NoMethodError: undefined method &amp;lsquo;number&amp;rsquo; for nil:NilClass&lt;!-- raw HTML omitted --> I guess we could check that a Truck exists each time we want to access any attributes for Driver.truck. But, really, what do we expect Driver.truck.number to be if the Driver is not in a Truck? Nil would work&amp;hellip;&lt;/p>
&lt;h3 id="delegate-for-science">Delegate: for science!&lt;/h3>
&lt;p>I&amp;rsquo;ll allow it. Let&amp;rsquo;s delegate and allow_nil:&lt;/p>
&lt;pre>&lt;code># app/models/driver.rb
class Driver &amp;lt; ActiveRecord::Model
delegate :number, :to =&amp;gt; :truck, :prefix =&amp;gt; true, :allow_nil =&amp;gt; true
# ...
end
&lt;/code>&lt;/pre>
&lt;p>Works! Now, we&amp;rsquo;ve got history showing: Driver had no Truck and moved
into Truck 2002. Geniusness times 2. Delegation to perferction.&lt;/p>
&lt;hr>
&lt;p>Sometime later&amp;hellip;&lt;/p>
&lt;p>Instead of the Truck number, maybe we want to store the id of the Truck
in the history. Perhaps we know the truck number may change over time and want to link up the correct Truck record. Seems easy:&lt;/p>
&lt;pre>&lt;code>delegate :id, to: :truck, prefix: true, allow_nil: true
&lt;/code>&lt;/pre>
&lt;p>But, when our Driver doesn&amp;rsquo;t have a &amp;lsquo;previous&amp;rsquo; truck:&lt;/p>
&lt;pre>&lt;code>RuntimeError - Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
&lt;/code>&lt;/pre>
&lt;p>WTF? I allowed nil. I know he doesn&amp;rsquo;t have a previous truck. I just want
my nil back and I&amp;rsquo;ll go about my business. Let&amp;rsquo;s get our hard hats on and
get digging into the source. I&amp;rsquo;ll save you some googling and just tell
you that the Delegation module is in ActiveSupport in the Core Extensions
under Module. Scroll, scroll, scroll. There! Line 136! They(we)(whomever)
are only rescuing from NoMethodErrors. Calling id on nil raises a
RuntimeError, which isn&amp;rsquo;t rescued and bubbles up to us. This is me
stomping my feet and wining. My knee jerk reaction was to just rescue
RuntimeErrors too:&lt;/p>
&lt;pre>&lt;code>rescue NoMethodError, RuntimeError
&lt;/code>&lt;/pre>
&lt;h3 id="were-gonna-be-famous">We&amp;rsquo;re gonna be Famous&lt;/h3>
&lt;p>It works! AND, how cool are we? We get to submit a bug fix to Rails.
Uber-cool. Uh-oh, uneasyness&amp;hellip;crap&amp;hellip;
It just doesn&amp;rsquo;t feel right to just catch any old RuntimeError and
possibly, silently fail to nil. However, the urge to try and submit a
simple &amp;lsquo;fix&amp;rsquo; to Rails was strong. Instead, I started doing more research
into delegate and Ruby Exception handling. Here&amp;rsquo;s what I&amp;rsquo;ve come up with:&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p>
&lt;h3 id="the-moral-of-the-story">The Moral of the Story&lt;/h3>
&lt;p>You should delegate when you want to hide an architectural aspect and
expose the expected abstraction. In the Ruby on Rails Guides example,
we expect a user to have a name through @user.name even through name
actually resided in Profile. However, in our example, a Driver isn&amp;rsquo;t
expected to have a truck_id. A truck has an id, but a driver does not
have a truck_id.&lt;/p>
&lt;p>One of the classic &amp;lsquo;bad smells&amp;rsquo; in code for refactoring is using a
temporary variable in place a a query. Ruby and its optional
parantheses, blurs the lines between variable, attribute and method.
It&amp;rsquo;s easy to forget what you are doing and assume everything is an
attribute. Why shouldn&amp;rsquo;t a Driver have a truck_id? The same reason a
Truck doesn&amp;rsquo;t have a CDL. But, we can query the truck_id for the
kTruck associated with a Driver with a method.&lt;/p>
&lt;p>After all that, I should have just written a query method in Driver as
such:&lt;/p>
&lt;pre>&lt;code>def truck_id
self.truck.id if self.truck
end
&lt;/code>&lt;/pre>
&lt;p>Too easy&amp;hellip;&lt;/p>
&lt;p>&lt;strong>UPDATE 3/16/2013&lt;/strong>&lt;/p>
&lt;blockquote>
&lt;p>As I convert this blog to Octopress and reread
these posts, I&amp;rsquo;m see some imporvements. Instead of the code above, the
&lt;code>try&lt;/code> method is really what we want to use here:&lt;/p>
&lt;/blockquote>
&lt;blockquote>
&lt;pre>&lt;code> def truck_id
self.truck.try(:id)
end
&lt;/code>&lt;/pre>
&lt;/blockquote>
&lt;blockquote>
&lt;p>On &lt;code>Object&lt;/code>, &lt;code>try&lt;/code> will attempt to send the parameter as a message to
the invoking object. So, it works just like calling the method. However,
on &lt;code>nil&lt;/code>, &lt;code>try&lt;/code> simply returns &lt;code>nil&lt;/code>. It effectively exactly replaces
the first implementation nicely.&lt;/p>
&lt;/blockquote>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Ruby Auto-Responder for Postfix/Vmail</title><link>https://codegoalie.com/posts/2013-03-16-ruby-auto-responder-for-postfix-slash-vmail/</link><pubDate>Tue, 15 Feb 2011 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-ruby-auto-responder-for-postfix-slash-vmail/</guid><description>&lt;p>Not knowing perl, I set out to write my own script in Ruby to send auto-responses from e-mail addresses setup in a vmail folder structure. You don&amp;rsquo;t need to use postfix, just have the &amp;lsquo;new&amp;rsquo; folder where new messages are stored.&lt;/p>
&lt;p>I recently moved our company&amp;rsquo;s e-mail server to &lt;!-- raw HTML omitted -->a new VPS on slicehost&lt;!-- raw HTML omitted --> and started using postfix. I followed &lt;!-- raw HTML omitted -->this great tutorial on How-ToForge&lt;!-- raw HTML omitted --> (except for the squirrelMail part) to setup a mysql database with the vmail folders to store the mail. I couldn&amp;rsquo;t get the Autoresponder in the tutorial to function correctly. Actually, it was &amp;lsquo;eating&amp;rsquo; random mail, which was a weeks worth of headache in itself. So, we rolled out without any auto-response capabilities.&lt;/p>
&lt;p>I&amp;rsquo;ve been half-heartedly looking for another solution every few weeks, but haven&amp;rsquo;t found anything other than a few Perl scripts (I&amp;rsquo;m not really famaliar with perl). So, yesterday I decided to write a ruby script to send auto-responses. I wanted to use text files to hold each autoresponse. Then, I&amp;rsquo;d just move them int and out of a folder to activate and deactivate them. I also took advantage of the &amp;lsquo;new&amp;rsquo; folder within the vmail structure to reply to mail newer than the autoresponder config file.&lt;/p>
&lt;p>The format of the config files is:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;p>The message can be multiple lines until the end of the file.&lt;/p>
&lt;p>For each config file in the directory, the script parses the file for the above information. Then it will check that user&amp;rsquo;s new mail folder for files. Any new mail file which was modified (sent) after the modification date of the config file is parsed to get the sender&amp;rsquo;s address(es)*. A new e-mail is composed using &lt;!-- raw HTML omitted -->benprew&amp;rsquo;s pony gem&lt;!-- raw HTML omitted --> and sent to each of the senders. Finally, the script &amp;lsquo;touches&amp;rsquo; the config file to move the modification date newer than the messages for which it just responded.&lt;/p>
&lt;p>The nifty parts of the script are iterating over a directory listing of files:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>and using the &lt;!-- raw HTML omitted -->stat method&lt;!-- raw HTML omitted --> of a file object to get the modified dateTime:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>and lastly, using the FileUtils module to &amp;lsquo;touch&amp;rsquo; a file:&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Here&amp;rsquo;s the full source:&lt;/p>
&lt;script type="text/javascript" src="https://gist.github.com/827900.js">&lt;/script>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Trick out your Vim</title><link>https://codegoalie.com/posts/2013-03-16-trick-out-your-vim/</link><pubDate>Fri, 25 Jun 2010 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-trick-out-your-vim/</guid><description>&lt;p>Today, I&amp;rsquo;m going to add some plugins and scripts to make better use of Vim. I have not started this project and I will be updating this post throughout the day with my finds and experiences.&lt;/p>
&lt;p>I generally use Vim to code web applications. My site at work run on PHP and at home I&amp;rsquo;m working with Ruby on Rails. So, I&amp;rsquo;ll be looking for something to specifically help with that, but who knows what I&amp;rsquo;ll find.&lt;/p>
&lt;h1 id="vimrc">.vimrc&lt;/h1>
&lt;p>.vimrc is a file in your home directory. It contains a script which runs each time you start Vim. You can setup your configurations, preferences and plugins in here. The .vimrc is the starting point for fine tuning your Vim to exactly how you want it. If you are a beginner, I would recommend finding some more advanced users' .vimrc&amp;rsquo;s and, at least, check them out, if not start using them for yourself. I started with &lt;!-- raw HTML omitted -->Todd Werth&amp;rsquo;s .vimrc file&lt;!-- raw HTML omitted -->. He keeps his in a separate folder and uses a symlink to put them in his home folder. I strongly recommend this as well. You can automatically sync your .vimrc (or any other files) across computers with Dropbox. See how in my post on how to &lt;!-- raw HTML omitted -->Use Dropbox to keep your preferences across Computers&lt;!-- raw HTML omitted -->.&lt;/p>
&lt;p>Here are some useful lines to start you out:&lt;/p>
&lt;pre>&lt;code>&amp;quot; Set tabs to 2 sapces
set softtabstop=2
set shiftwidth=2
set tabstop=2
set expandtab
&amp;quot; Move your backup and .swp files out of the directory of the file (Helpful to keep from adding them to a repo)
set backup
set backupdir=~/backup
set dir=~/swap
&amp;quot; Highlight the current line
set cursorline
&amp;quot; Keyboard shortcuts (Mappings)
c&amp;gt; &amp;quot; Use mat Insert Mode (instead of Escape)
imap =&amp;gt; =&amp;gt; &amp;quot; Hit =&amp;gt; to insert a &amp;quot;rocket&amp;quot; in insert mode
&amp;quot; Wildmenu - show a tab completion matches list
set wildmenu
set wildmode=list:longest,full
&lt;/code>&lt;/pre>
&lt;p>Again, search the google machine and checkout github for more samples and if you find anything cool, let me know in the comments.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>&lt;em>&lt;strong>Update 3/16/2013&lt;/strong>&lt;/em>&lt;/p>
&lt;blockquote>
&lt;p>Check out &lt;a href="https://github.com/chrismar035/vim_configs">my public vim configs repo&lt;/a> for more info!&lt;/p>
&lt;/blockquote>
&lt;p>See ya Soon!&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Use Dropbox to keep your preferences across Computers</title><link>https://codegoalie.com/posts/2013-03-16-use-dropbox-to-keep-your-preferences-across-computers/</link><pubDate>Fri, 25 Jun 2010 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-use-dropbox-to-keep-your-preferences-across-computers/</guid><description>&lt;p>Sometimes it can be kind of painful to discover a cool new setting or mode for on of your favorite programs. For instance, I use &lt;!-- raw HTML omitted -->TTYtter&lt;!-- raw HTML omitted -->, a terminal based Twitter client. A few weeks into using it, I discovered it had ReadLine support for tab auto-completion of @usernames, in-line editing of posts and command history (up key). Awesome right? I know. Except, now I need to change my .ttytterrc file on my laptop, home computer, work computer, everywhere. Also, how do I get it there? USB drive, e-mail to myself, browse the network, etc. Being geeks, we don&amp;rsquo;t want to go through all that.&lt;/p>
&lt;p>Then I discovered &lt;!-- raw HTML omitted -->Dropbox&lt;!-- raw HTML omitted --> (that link is a referral link, &lt;!-- raw HTML omitted -->here&amp;rsquo;s the regular homepage&lt;!-- raw HTML omitted -->). Not only is Dropbox a free 2GB of cloud storage for backing up your much needed files, but the really cool thing about Dropbox is that it &lt;!-- raw HTML omitted -->automatically detects when files change and syncs them across all of your computers&lt;!-- raw HTML omitted -->. Think about configuration files and read that again. Discover a new mode in any program with a config file and BAM! every computer you use has that mode enabled. The sync works in all directions so it doesn&amp;rsquo;t matter which computer you make the change on, every computer gets it. Seems perfect, right?&lt;/p>
&lt;p>If you&amp;rsquo;re new to Dropbox, check out &lt;a href="https://www.cloudwards.net/how-to-share-files-on-dropbox/">this post on Cloudwards&lt;/a> on getting setup.&lt;/p>
&lt;p>Here&amp;rsquo;s how it all works. When you install the Dropox client software on your computer, it will create a Dropbox folder with all your stuff in it. Add, delete or edit any file in this folder and Dropbox will sync it up to their servers, plus download the changes to any other computer running the Dropbox client with your account. It&amp;rsquo;s kind of cool to have your desktop and laptop running next to each other and watch them download the changes instantly.&lt;/p>
&lt;p>Back to business, I know what you are thinking, &amp;ldquo;All these files are in one Dropbox folder (and subfolders). My config file needs to be in my home directory. I still have to copy from my Dropbox to my home.&amp;rdquo; Well, let&amp;rsquo;s let the computer do the copying. Actually, let&amp;rsquo;s not even waste time and space copying. Let&amp;rsquo;s create a symlink to make the config files appear to be in your home folder but actually be stored in the Dropbox folder.&lt;/p>
&lt;p>First, open a terminal, navigate to the Dropbox folder and create a new subfolder; I called mine &amp;lsquo;configs.&amp;rsquo;&lt;/p>
&lt;pre>&lt;code>$ cd ~/Dropbox
$ mkdir configs
$ cd configs
&lt;/code>&lt;/pre>
&lt;p>Now, let&amp;rsquo;s move the config file from the home folder into the Dropbox/configs folder and navigate to the home folder.&lt;/p>
&lt;pre>&lt;code>$ mv ~/.ttytterrc ~/Dropbox/configs/.ttytterrc
$ cd ~/
&lt;/code>&lt;/pre>
&lt;p>Here&amp;rsquo;s the magic. We&amp;rsquo;ll create a symlink (like a shortcut in Windows) which will make it appear that the file is in your home directory, but Dropbox will still keep track of it.&lt;/p>
&lt;pre>&lt;code>$ ln -s ~/Dropbox/configs/.ttytterrc ~/.ttytterrc
&lt;/code>&lt;/pre>
&lt;p>Rough Spot: If you get a file exists error, the link will not overwrite an existing file. Remove the file from where you are creating the link into (the home dir in our case).&lt;/p>
&lt;p>Do this on all your computers, then you can edit the file directly from my home directory on any computer and the changes will be automatically propagated to all my other computers instantaneously.&lt;/p>
&lt;p>Here are some other ideas for this technique which I haven&amp;rsquo;t tried, but might be cool.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Keep ssh sessions from timing out</title><link>https://codegoalie.com/posts/2013-03-16-keep-ssh-sessions-from-timing-out/</link><pubDate>Thu, 20 May 2010 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-keep-ssh-sessions-from-timing-out/</guid><description>&lt;p>The &lt;a href="'http://embraceubuntu.com'">Ubuntu Blog&lt;/a> has a nice lil' article
about &lt;a href="'http://embraceubuntu.com/2006/02/03/keeping-ssh-sessions-alive/'">keeping SSH sessions alive&lt;/a>
It basically boils down to editing your &lt;code>/etc/ssh/ssh_config&lt;/code> file and
adding the following:&lt;/p>
&lt;pre>&lt;code># /etc/ssh/ssh_config
ServerAliveInterval 5
&lt;/code>&lt;/pre>
&lt;p>The number is the number of seconds to send the small keep alive which
keeps the connection open. Ubuntu Blog suggests changing it from 5 to
240 or 300 (4 or 5 minutes).&lt;/p>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Breaking Bad Season 3 Firefox Persona</title><link>https://codegoalie.com/posts/2013-03-16-breaking-bad-season-3-firefox-persona/</link><pubDate>Fri, 19 Mar 2010 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-breaking-bad-season-3-firefox-persona/</guid><description>&lt;p>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->Update: HURRAY!!! It was approved!! Get it now at &lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;a href="http://www.getpersonas.com/en-US/persona/140288">http://www.getpersonas.com/en-US/persona/140288&lt;/a>&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;!-- raw HTML omitted -->&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>That&amp;rsquo;s it! Enjoy the Breaking Bad awesomeness!!&lt;/p>
&lt;p>&lt;!-- raw HTML omitted -->UPDATE: I found out that it usually takes about a week for a Persona to get approved which should be around Friday March 26, 2010. I will update this post when I hear word. If you see if before me, let me know in the comments!&lt;!-- raw HTML omitted -->&lt;/p></description></item><item><title>Installing PianoBar - Console client for Pandora Radio</title><link>https://codegoalie.com/posts/2013-03-16-installing-pianobar-console-client-for-pandora-radio/</link><pubDate>Tue, 26 Jan 2010 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-installing-pianobar-console-client-for-pandora-radio/</guid><description>&lt;p>PianoBar is a console client for Pandora Internet Radio. For me, this
is a huge discovery. If you run Ubuntu, the flash player for Pandora
can be a pain in the ass to install. Plus, on my netbook, the flash
plugin for Chrome usually eats about 40-55% CPU constantly. A console
client for Pandora will resolve all these issues.&lt;/p>
&lt;p>However, the install instructions in the readme at the
&lt;a href="'http://github.com/PromyLOPh/pianobar'">PianoBar Github Repo&lt;/a> are very
sparse and for someone pretty new to linux (like me) may be a little
daunting. In the next few paragraphs, I will try to flesh out the
installation instructions for PianoBar on Ubuntu linux.&lt;/p>
&lt;h2 id="1-get-the-pianobar-source">1. Get the PianoBar source.&lt;/h2>
&lt;p>I downloaded the .tar.gz from &lt;a href="http://6xq.net/html/00/17.html">http://6xq.net/html/00/17.html&lt;/a> and
extracted it with&lt;/p>
&lt;pre>&lt;code>tar -xzf PromyLOPh-pianobar-e079b45.tar.gz
&lt;/code>&lt;/pre>
&lt;h2 id="2--try-to-make-the-pianobar-source">2. Try to Make the PianoBar source.&lt;/h2>
&lt;p>I say try because for me it didn&amp;rsquo;t work. I was missing some of the
required dependencies. But, you might not be missing the same ones as
me. So, try to make it and then follow the instructions below for the
dependencies you are missing.&lt;/p>
&lt;pre>&lt;code>cd PromyLOPh-pianobar-e079b45/
cmake .
&lt;/code>&lt;/pre>
&lt;h2 id="3-get-and-install-libao">3. Get and install libao&lt;/h2>
&lt;p>Libao is a cross-platform audio library for playing audio. I followed
&lt;a href="%22http://www.linuxfromscratch.org/blfs/view/cvs/multimedia/libao.html%22">these instructions from Linux from Scratch&lt;/a>
to install it. Download the source from that page. Extract the .tar.gz:&lt;/p>
&lt;pre>&lt;code>tar -xzf libao-0.8.8
&lt;/code>&lt;/pre>
&lt;p>Then, from withing the libao-0.8.8 directory, configure the library
with:&lt;/p>
&lt;pre>&lt;code>./configure --prefix=/usr &amp;amp;&amp;amp; make
&lt;/code>&lt;/pre>
&lt;p>Finally, install it as root:&lt;/p>
&lt;pre>&lt;code>sudo make install &amp;amp;&amp;amp; sudo install -v -m644 README /usr/share/doc/libao-0.8.8
&lt;/code>&lt;/pre>
&lt;p>Then, I retried step 2 to see that I didn&amp;rsquo;t need the LIBAO anymore.&lt;/p>
&lt;h2 id="4-install-faad2">4. Install FAAD2&lt;/h2>
&lt;p>Download the bootstrapped .tar.gz from
&lt;a href="%22http://www.audiocoding.com/downloads.html%22">AudioCoding.com&lt;/a>.
Extract the .tar.gz with:&lt;/p>
&lt;pre>&lt;code>tar -xzf f@d2-2.7
&lt;/code>&lt;/pre>
&lt;p>There are installation instructions in the INSTALL file in the
extracted folder. I&amp;rsquo;ll summarize what worked for me.
Configure it:&lt;/p>
&lt;pre>&lt;code>./configure
&lt;/code>&lt;/pre>
&lt;p>Make it:&lt;/p>
&lt;pre>&lt;code>make
&lt;/code>&lt;/pre>
&lt;p>Install it:&lt;/p>
&lt;pre>&lt;code>sudo make install
&lt;/code>&lt;/pre>
&lt;p>Then, I tried to make pianobar again. It still said it couldn&amp;rsquo;t find
libmad, but it turned out I didn&amp;rsquo;t need it.&lt;/p>
&lt;h2 id="5-install-pianobar">5. Install PianoBar.&lt;/h2>
&lt;p>After running the cmake from the extracted PianoBar folder, you should
see that the object files were made. Then, run make:&lt;/p>
&lt;pre>&lt;code>make
&lt;/code>&lt;/pre>
&lt;p>And install:&lt;/p>
&lt;pre>&lt;code>sudo make install
&lt;/code>&lt;/pre>
&lt;p>If all goes well, you will be able to run it:&lt;/p>
&lt;pre>&lt;code>./src/pianobar
&lt;/code>&lt;/pre>
&lt;p>Enter your pandora username/email address and password.
Choose your station.
Hear music!&lt;/p>
&lt;hr>
&lt;p>&lt;em>&lt;strong>UPDATE:&lt;/strong>&lt;/em>&lt;/p>
&lt;p>I recently used this post to install pianobar on another computer and was getting
&lt;!-- raw HTML omitted -->pianobar: error while loading shared libraries: &lt;a href="mailto:libf@d.so.2">libf@d.so.2&lt;/a>: cannot open shared object file: No such file or directory&lt;!-- raw HTML omitted -->
I needed to update the Shared Libraries (You can read more about Linux Shared Libraries from &lt;!-- raw HTML omitted -->this page&lt;!-- raw HTML omitted -->, specifically 3.5). I tried
&lt;!-- raw HTML omitted -->ldd /usr/local.bin/pianobar&lt;!-- raw HTML omitted -->
to see which shared libraries where being used by PianoBar and did see that libf@d/so/2 was not found.
&lt;!-- raw HTML omitted -->linux-gate.so.1 =&amp;gt; (0x0044c000)
&lt;a href="mailto:libf@d.so.2">libf@d.so.2&lt;/a> =&amp;gt; not found
libao.seeo.2 =&amp;gt; /usr/lib/libao.so.2 (0x00edb000)
libpthread.so.0 =&amp;gt; /lib/tls/i686/cmov/libpthread.so.0 (0x00507000)
libm.so.6 =&amp;gt; /lib/tls/i686/cmov/libibm.so.6 (0x00794000)
libc.so.6 =&amp;gt; /lib/tls/i686/cmov/libc.so.6 (0x00982000)
libdl.so.2 =&amp;gt; /lib/tls/i686/cmov/libdl.so.2 (0x00f20000)
/lib/0x00f20000ld-linux.so.2 (0x00f4e000)&lt;!-- raw HTML omitted -->
But I could find the &lt;a href="mailto:libf@d.so.2">libf@d.so.2&lt;/a> file in the &lt;!-- raw HTML omitted -->/usr/local/lib/&lt;!-- raw HTML omitted -->directory. Therefore, I needed to run ldconfig:
&lt;!-- raw HTML omitted -->sudo ldconfig&lt;!-- raw HTML omitted -->
Then I ran the ldd again and saw that &lt;a href="mailto:libf@d.so.2">libf@d.so.2&lt;/a> was now found in /usr/local/lib/ and PianoBar was now running again.
Also, I learned how to automatically sign in and change the keyboard short cuts.&lt;/p>
&lt;h2 id="6-pianobar-config">6. PianoBar config&lt;/h2>
&lt;p>You can change the configuration of PianoBar to switch up the keyboard short cuts and automatically login on run. To do this, you need to create and edit a file named &amp;lsquo;config&amp;rsquo; in the .config/pianobar/ within your home directory.&lt;/p>
&lt;pre>&lt;code>vim ~/.config/pianobar/config
&lt;/code>&lt;/pre>
&lt;p>To automatically login, add the following two lines&lt;/p>
&lt;pre>&lt;code>user = pandoraUserName
password = pandoraPassword
&lt;/code>&lt;/pre>
&lt;p>I also found that changing the &amp;ldquo;Loving Song&amp;rdquo; keyboard short cut from + to = worked out better, since I didn&amp;rsquo;t have to press Shift+=.&lt;/p>
&lt;pre>&lt;code>act_songlove = =
&lt;/code>&lt;/pre>
&lt;p>&amp;ndash; Chris&lt;/p></description></item><item><title>Notepad++ Color Configurator and styler.xml</title><link>https://codegoalie.com/posts/2013-03-16-notepad-color-configurator-and-styler-xml/</link><pubDate>Fri, 08 Jan 2010 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-16-notepad-color-configurator-and-styler-xml/</guid><description>&lt;p>Before I start talking about colors, let&amp;rsquo;s talk font.
&lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=22e69ae4-7e40-4807-8a86-b3d36fab68d3&amp;amp;displaylang=en">Consolas&lt;/a>.
That&amp;rsquo;s all you need to know. By far the best programming font. Get it. Use it. Love it.&lt;/p>
&lt;p>Recently I started learning Ruby on Rails and I found
&lt;a href="http://railscasts.com/">RailsCasts&lt;/a> with a ton of Rails focused screencasts.
I believe he use &lt;a href="http://macromates.com/">TextMate&lt;/a> for mac. I hadn&amp;rsquo;t really
thought much about color in my code before watching some of these screencasts.
But, it actually helps, a lot! I use Notepad++ in Windows and they have a great
styling system. You can use the in program Style Confirurator or you can
directly modify the XML style sheet.&lt;/p>
&lt;h1 id="style-configurator">Style Configurator&lt;/h1>
&lt;p>The Style Configurator is a dialog within Notepad++ accessible through the
Settings menu. The really great thing about the Configurator is that the styles
you choose are updated live in your code. So, open up a file with a lot of code.
Then open the Configurator and move it over to another screen. If you don&amp;rsquo;t have
more than one monitor, check the Transparency box in the lower right and you
will be able to see through the Configurator. The slider there sets the
Transparency level. Now you can see all of your code and pick styles for them.&lt;/p>
&lt;p>Start with the very first &amp;lsquo;language,&amp;rsquo; Global Styles. These not only include
default styles of text but many of the stuff around your code, such as line
number margin, inactive and active tab color, and the edge. The edge is great
to keep your lines of code to a certain length for printing or displaying in a
terminal. I also set the global font to Consolas. Also, be sure to set the
current line color and selected text background color.&lt;/p>
&lt;p>Now you are ready to style for you language. I usu PHP mostly at work so I&amp;rsquo;ll
go though that one. Hopefully, I&amp;rsquo;ll be familiar with Ruby soon enough to write
a post about Ruby styles.&lt;/p>
&lt;ul>
&lt;li>QUESTION MARK - This is the style of the opening and closing php tags
('&lt;!-- raw HTML omitted -->')&lt;/li>
&lt;li>DEFAULT - Text that doesn&amp;rsquo;t match any of the other styles will be this.&lt;/li>
&lt;li>STRING - Any string enclosed with double quotes&lt;/li>
&lt;li>STRING VARIABLE - variables enclosed withing literal strings: &amp;ldquo;The Count is
$count&amp;rdquo;&lt;/li>
&lt;li>SIMPLESTRING - These are string enclosed with single quotes. (I used a very
similar green to STRING)&lt;/li>
&lt;li>WORD - These are the keywords of PHP. There are a bunch defined. You can also
define some of your own in the blank box.&lt;/li>
&lt;li>NUMBER - Number literals, including array indices&lt;/li>
&lt;li>VARIABLE - Any word started with a $&lt;/li>
&lt;li>COMMENT - Text between matching multi-line comments ('/&lt;em>' and &amp;lsquo;&lt;/em>/')&lt;/li>
&lt;li>COMMENTLINE - Text on a line after and including two forward slashes (//)&lt;/li>
&lt;li>OPERATOR - Operators (+,=,-,etc.), matched parenthesis, brackets, curly
brackets and logical operators&lt;/li>
&lt;/ul>
&lt;h1 id="stylersxml">Stylers.xml&lt;/h1>
&lt;p>The stylers.xml file contains all the settings from the Configurator used by
Notepad++. In addition to using the Configurator, you can manually edit this
file. Or, download one from the web. The &lt;a href="http://notepad-plus.sourceforge.net/uk/download.php">Notepad++
site&lt;/a> has some under Theme
Files. &lt;a href="http://joyboner.com/60-free-textmate-notepad-styler-themes/">Joy Boner&lt;/a>
(read the &lt;a href="http://joyboner.com/about/">about page&lt;/a>) has 60 themes. I didn&amp;rsquo;t
check any of these out, but it might be worth a shot if you really don&amp;rsquo;t want
to set your own styles.&lt;/p>
&lt;p>I also put &lt;a href="http://gist.github.com/272115">my personal stylers.xml&lt;/a> as a gist
on github. Feel free to fork it.&lt;/p>
&lt;p>If you have any other Notepad++ styling tips, comment below!&lt;/p>
&lt;p>&amp;ndash;Chris&lt;/p></description></item><item><title>Getting and Parsing E-mail with PHP</title><link>https://codegoalie.com/posts/2013-03-15-getting-and-parsing-e-mail-with-php/</link><pubDate>Fri, 18 Dec 2009 00:00:00 +0000</pubDate><guid>https://codegoalie.com/posts/2013-03-15-getting-and-parsing-e-mail-with-php/</guid><description>&lt;p>Here&amp;rsquo;s my Problem:
My website sends text files to a partner&amp;rsquo;s site via FTP. Our partner site sends us the results of their processing the file in an e-mail. This e-mail is a the direct output from their processing script. Or, the relevant details are buried in a bunch of garbled text.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>My Solution:
I first looked at message piping, but my hosting provider doesn&amp;rsquo;t provide an easy way to do this.
Then I found &lt;!-- raw HTML omitted -->this PHP class&lt;!-- raw HTML omitted --> from PHP classes, which handles the interactions with the server. You do have to create an account with PHP classes to download the files. If you e-mail me directly, I could send them to you.
It&amp;rsquo;s easy enough to get working quickly.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;p>Edit the test_pop3.php file. All you need to do is change the sever name, user name and password to get rolling. After you see the full output and it&amp;rsquo;s getting the mail correctly, I recommend setting the debug and html_debug values to 0. This will cut out the unnecessary text of the interaction with the server and just show you the messages and what&amp;rsquo;s going on.&lt;/p>
&lt;p>One hangup of this class, the body of the message is an array and the message was repeated twice in the array.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;p>Luckily, the part boundaries are included in the array which makes it fairly easy to split the array and just get the message once.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;p>I needed to run some regular expressions on the body and imploded it into a single string.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;p>Now I have the body of my e-mail message as a string variable ready for processing. Alternatively, you can change the first parameter in implode( to a line break if you need to display the message not as one long string.&lt;/p>
&lt;p>Lastly, once you process your messages, you don&amp;rsquo;t need them anymore.&lt;/p>
&lt;!-- raw HTML omitted -->
&lt;!-- raw HTML omitted -->
&lt;p>The DeleteMessage( method will mark messages for deletion when you close the connection to your mail server. Please note that this method does not immediately delete the messages and messages can still be &amp;lsquo;un-deleted&amp;rsquo; until the connection is closed. The ResetDeletedMessages( method is used to un-mark all messages for deletion.&lt;/p>
&lt;p>Happy Parsing!!&lt;/p>
&lt;p>&amp;ndash;Chris&lt;/p></description></item></channel></rss>